-
Notifications
You must be signed in to change notification settings - Fork 273
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
Add a Customer Account API Abstraction #1430
Conversation
{ | ||
headers: { | ||
'Set-Cookie': await context.session.commit(), | ||
}, | ||
}, |
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 is the biggest thing that sucks about the abstraction at the moment. Any loader that calls the customer account api client must return the committed session. The only alternative I can think of is to always commit the session inside server.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.
Would it be a problem to always commit the session in server.ts
? Would it make sense to do that automatically in the remix-oxygen
adapter if you pass session
?
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.
Someone brought up a big downside of doing so. I'm trying to remember what the concern was. 🤔
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.
Could we change HydrogenSession
to actually track changes somehow so we know if it's "dirty"?
Something like this:
class HydrogenSession {
// ...
#isDirty = false;
get isDirty() {
return this.#isDirty;
}
set(...args) {
this.#session.set(...args);
this.#isDirty = true;
}
async commit() {
const result = await this.#sessionStorage.commitSession(this.#session);
this.#isDirty = false;
return result;
}
}
Then check session.isDirty
before committing in server.ts
/ remix-oxygen? 🤔
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 implemented this out, and after a discussion with @juanpprieto, I don't think I feel good about it for now. I'd rather just require the user to manually commit the session for now. Though, if I can convince the API folks to differentiate between these two scenarios, I think I might be able to warn the user they didn't persist/commit their session:
- Try to refresh the auth token, but the refresh token is expired
- Try to refresh the auth token, but the refresh token has already been used
'No refresh_token in the session. Make sure your session is configured correctly and passed to `createCustomerClient`.', | ||
); |
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.
It's super easy to get something small wrong in the oauth flow. In dev mode, I figured we can add these helper messages, potentially with links to a troubleshooting guide.
origin: string, | ||
) { | ||
const clientId = customerAccountId; | ||
const customerApiClientId = '30243aa5-17c1-465a-8493-944bcc4e88aa'; |
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.
Maybe I'll pull this out and make it more obvious that this is a magic id.
export interface HydrogenSession { | ||
get: (key: string) => string | undefined; | ||
set: (key: string, value: string) => void; | ||
unset: (key: string) => void; | ||
commit: () => Promise<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.
Now that we actually depend on this internally... should we also abstract away the HydrogenSession
class that lives in userland's server.ts
? Or at least provide some sort of abstract class that they can extend?
Otherwise it might be confusing to have this interface with the same name we have in the templates 🤔
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 wasn't sure what to do about that. I imagine most people take our default cookie session implementation, but I'm willing to bet other people use an actual DB of some sort to store sessions 🤔
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.
They could still extend our class and overwrite the constructor
/ etc. behavior? 🤔
Ah, maybe we wouldn't tree-shake the cookie related stuff in that case? So perhaps better to have an abstract HydrogenSession
class and another HydrogenCookieSession
? Well, just random ideas.
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'd like for people to be able to use any of the existing remix session utils easily. But it's looking like Remix 3 will be more opinionated about sessions. Maybe we should also be more opinionated about sessions? It would actually be pretty cool if we offered a default non-cookie based solution. For down the road though.
async mutate(query: string, variables?: any) { | ||
return this.query(query, variables); | ||
}, | ||
query: async (query: string, variables?: any) => { |
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.
Just to be consistent, should we wrap variables in an object like in the SFAPI? client.query('...', {variables: {}})
.
Another thing we do in the SFAPI client is to check with a regex if you are actually passing a mutation to mutate
or throw error. Not sure if we want to do the same here?
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.
Should we be following this error standard everywhere? throw new Error('[h2:error:storefront.query] Cannot execute mutations');
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 updated it to follow the same pattern, just [h2:error:customer.query]
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.
Oh yes, that's good, the CLI will pick it up 👍
{ | ||
headers: { | ||
'Set-Cookie': await context.session.commit(), | ||
}, | ||
}, |
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.
Would it be a problem to always commit the session in server.ts
? Would it make sense to do that automatically in the remix-oxygen
adapter if you pass session
?
vi.stubGlobal( | ||
'Response', | ||
class Response { | ||
message; | ||
constructor(body: any, options: any) { | ||
this.message = body; | ||
} | ||
}, | ||
); |
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.
Interesting, I hadn't considered this way of testing 🤔
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, it's a bit obnoxious because Remix allows you to throw new Response
but vitest uses uses check-error
that expects everything to be an error with a .message
property: https://github.com/chaijs/check-error/blob/main/index.js#L62
509c310
to
88ec943
Compare
88ec943
to
1fd49d6
Compare
1fd49d6
to
41b322a
Compare
@blittle I've fixed a couple of issues I found while reviewing, hope it doesn't break anything 😅 |
Also update the example to reference the new abstraction
Co-authored-by: Shawn D Lee-kwong <splitnova@gmail.com>
5f0fcb6
to
40d41ba
Compare
WHY are these changes introduced?
Implements the RFC here: #1189
WHAT is this pull request doing?
Implement the RFC and update the example to reference the new exposed functionality.
HOW to test your changes?
Follow the instructions in the Customer API example README.md
Post-merge steps
Checklist