-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
URO-206 getting started with orcidlink integration #206
Conversation
tweaks to jsonrpc to better support 2.0, detects whether linked, shows 3 fields from link if so, redux state not developed
placeholder icon
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! The only things blocking approval are overrideExisting
& hiding the icon from src/features/layout/LeftNavBar.tsx. (We're merging into main, so everything should be presentable if it's directly accessible, just in case we cut a release in the meantime. We have some nascent feature flag support, too, which could hide the page altogether if that's preferable.) I would also recommend stubbing out a test file with an "OrcidLink Renders" test before merging, but it'd just be a formality.
I figure if the parseError comment works out, it can be in the next PR.
Also, Re: queries in components, that's the way to do it with rtk-query. It handles caching for queries with the same query key. Sometimes this requires memoization to leverage but often not. Custom thunks are a good solution if there are dependant queries, however.
fetchArgs?: FetchArgs; | ||
} | ||
|
||
export interface JSONRPC11Body { | ||
version: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: You can hardcode the version string here, or use a template string type if we want to support minor versions
It will make discrimination (type guarding) between this type and the 2.0 type easier downstream
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In terms of versions, as far as I know there are only two relevant JSON-RPC versions for us: 1.1
and 2.0
. Also, 1.1
is not technically official (although it is used in many places in KBase). That being said, official documents describing their operation do exist, and I suggest that we hew as close to them as possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, agreed @dakotablair, although our JSON-RPC 1.1 is not the same as the working draft that inspired it. So our reference for that should be our implementation.
@dakotablair Yes, the version could be hardcoded for sure; I did have another set of changes that addressed this more fundamentally, but more loc.
.injectEndpoints({ | ||
// because many apis have "status", some have "info", and there may be | ||
// other random clashes. | ||
overrideExisting: true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't want to do this, as it will squash any same-named endpoints. Just use unique names for your endpoints.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eg "orcidLinkStatus"
injectEndpoints does not create a new API, but rather adds enpoints to the common baseAPI instance. We set it up like that so that we can expire query tags across services. So, moral of the story, setting this to true will probably cause runtime errors if a collision occurs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This also means you can export the endpoints themselves (like we do elsewhere) without worrying about duplicates
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dauglyon thanks, you answered the question I had, though I thought my original researched showed this was safe. Thanks, Google!
// It is mostly a JSONRPC 2.0 service, although the oauth flow is rest-ish. | ||
const orcidlinkService = jsonRpcService({ | ||
url: '/services/orcidlink/api/v1', | ||
version: '2.0', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice
src/features/layout/LeftNavBar.tsx
Outdated
@@ -37,6 +38,7 @@ const LeftNavBar: FC = () => { | |||
<NavItem path="/legacy/search" desc="Search" icon={faSearch} /> | |||
<NavItem path="/legacy/jobbrowser" desc="Jobs" icon={faSuitcase} /> | |||
<NavItem path="/legacy/account" desc="Account" icon={faIdCard} /> | |||
<NavItem path="/orcidlink" desc="ORCID Link" icon={faLink} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should put this behind a feature flag or hide it from the sidebar whilst orcidlink is in development.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<NavItem path="/orcidlink" desc="ORCID Link" icon={faLink} /> | |
{/*<NavItem path="/orcidlink" desc="ORCID Link" icon={faLink} />*/} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, and my thought exactly; are there feature flags used in the codebase?
@@ -172,19 +189,35 @@ export const kbaseBaseQuery: ( | |||
// Generate JsonRpc request id | |||
const reqId = Math.random().toString(); | |||
|
|||
const body = ((): JSONRPCBody => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
const message = (() => { | ||
if ('status' in error) { | ||
switch (error.status) { | ||
case 'JSONRPC_ERROR': | ||
return error.data.error.message; | ||
case 'FETCH_ERROR': | ||
return 'Fetch Error'; | ||
case 'CUSTOM_ERROR': | ||
return error.error; | ||
case 'PARSING_ERROR': | ||
return error.error; | ||
case 'TIMEOUT_ERROR': | ||
return error.error; | ||
} | ||
} else { | ||
return error.message || 'Unknown Error'; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check out the parseError utility for this functionality. It may need to be updated to support exactly what you want, but will be reusable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/common/api/utils/parseError.ts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We tend to avoid switch
statements. My personal preference is that if we are going to use them then we should make use of their special features, in particular, fall-through and default
cases. For example:
switch (error.status) {
case 'JSONRPC_ERROR':
return error.data.error.message;
case 'FETCH_ERROR':
return 'Fetch Error';
case 'CUSTOM_ERROR':
case 'PARSING_ERROR':
case 'TIMEOUT_ERROR':
default:
return error.error;
}
I think many other switch
users write code as you have to avoid confusion about these features, and it is this situation that has led us to avoid them on this project. There is another open PR with what I think is a good alternative.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can abide by the codebase conventions. Yeah, first pass was not to use fallthrough because I hadn't explored those error conditions to see if there was more specialized information before; e.t. timeout in theory should have information about the timeout like the timeout limit and actual elapsed time. But, like I said, I didn't have time on this batch to create a test to exercise the conditions.
src/features/orcidlink/Linked.tsx
Outdated
} else if (isSuccess) { | ||
return renderLink(data); | ||
} else { | ||
return <div>???</div>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume this is to appease typescript re: the function return type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it is something I still wanted to follow up on, as I don't yet understand the full set of states for the various query state flags.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have been putting all the API defs in src/common/api/
That said, I can see the argument for feature-specific APIs like this and collections being in the feature folder itself. Thoughts? It's probably something to quickly talk about on the UI call
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I meant to move the api over to the centralized api directory, but forgot that piece of housekeeping.
Yeah, I think there is a need for sequenced queries like this that I would usually do in an async thunk if working w/ redux. |
and a bit of cleanup
without feature switches or being able to restrict to devs, we don't want the navigation to leak out in a release
This set of changes introduces a primitive orcidlink feature. A link is displayed on the left nav area, a route is in place, the feature is invoked, and a message is displayed indicating whether the user has an orcid link or not. If so, some orcid link information is shown.
What is not included? Tests, actual (other than stub) redux store data definitions (state types), api calls in the the redux layer (they are in the components themselves), proper error handling.
Some bespoke layout (loading indicator, box around the content) was added just to keep have an implementation - I just couldn’t find anything satisfying to grab quickly.
Some light modifications were made to the jsonrpc api machinery. The orcidlink service is JSON-RPC 2.0, and the existing JSON-RPC support is not fully 2.0 compatible. I also made a more extensive revision of JSON-RPC, because error response support is also needs some improvement, but is not addressed in this ticket.