You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
What I mean by "authenticated queries" is graphql queries that have an authentication cookie or http header.
For a regular client-side SPA, it's easy to authenticate queries by modifying your queryFetcher. You can get the auth token from the browser environment & include it in the fetch call:
(or use fetch option credentials: 'include' to have http cookies included automatically)
For a server-side rendering, the queryFetcher needs to know about the page request (req), so that it can forward the auth token that the browser sent in the page request:
The objective becomes getting the req object in scope of queryFetcher. It's currently possible, by creating one client per page request (which makes sense anyway), but currently that's not ergonomic and comes with limitations.
I have pushed a demo project for reference: repo / deployment
In this demo, the components, instead of using a global singleton client, use the client we "provide" via React context. This way the component definitions are not tied to a single client. This is a common approach, used by apollo & urql & more.
The problem is that since there is no native GqlessContext in the @gqless/react, which the hooks & HOC would use to read client from context, we need to wrap the whole react client to make the hooks read client from context.
To avoid changing my components I created an adapted useQuery hook to (1) use the useContext hook to get the gqless clients (main client & react client) from context, & (2) call the hook and returns the result.
The alternative would be to have a single hook that returns the entire gqless react client, which could be used like const { posts } = useGqless().useQuery(). This is not really pretty, or a simple/straightforward change to the codebase, just to add that http header.
Also, using the graphql HOC becomes awkward since it's only accessible from within another component.
Recommendation
The ReactClient should include a GqlessContext: React.Context<GqlessClient<GeneratedSchema>> member which is consumed by the hooks & hoc. This would allow us to provide the client using <GqlessContext.Provider value={client}>, or not do that (the client param passed to createReactClient should be used as the default value), and use the same hooks & HOC either way.
The text was updated successfully, but these errors were encountered:
@PabloSzx Let me know if you are interested in a PR implementing my recommendation. I think it may solve the web of SSR issues I opened: this one & #165 for sure, & probably #168, which would in turn unblock the getInitialProps solution to #167
This specific feature is a tough one, as I mentioned in #168 (comment), using getInitialProps is completely possible to implement this feature, and if you want to propose a implementation around the existing code (after #169 is merged), I would be very grateful, and maybe add it in the docs as a copy-paste in your project solution, or add it in the gqless-react packages as scoped module "@gqless/react/nextjs" or something like that, but I don't think it should be added in the main module, since it would be a framework-specific solution
What I mean by "authenticated queries" is graphql queries that have an authentication cookie or http header.
For a regular client-side SPA, it's easy to authenticate queries by modifying your
queryFetcher
. You can get the auth token from the browser environment & include it in thefetch
call:const queryFetcher: QueryFetcher = async function (query, variables) { const response = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json", + Authorization: `Bearer ${window.localStorage["auth-token"]}`, }, body: JSON.stringify({ query, variables }), mode: "cors", }); const json = await response.json(); return json; };
(or use fetch option
credentials: 'include'
to have http cookies included automatically)For a server-side rendering, the
queryFetcher
needs to know about the page request (req
), so that it can forward the auth token that the browser sent in the page request:The objective becomes getting the
req
object in scope ofqueryFetcher
. It's currently possible, by creating one client per page request (which makes sense anyway), but currently that's not ergonomic and comes with limitations.I have pushed a demo project for reference: repo / deployment
In this demo, the components, instead of using a global singleton client, use the client we "provide" via React context. This way the component definitions are not tied to a single client. This is a common approach, used by apollo & urql & more.
The problem is that since there is no native
GqlessContext
in the@gqless/react
, which the hooks & HOC would use to read client from context, we need to wrap the whole react client to make the hooks read client from context.To avoid changing my components I created an adapted
useQuery
hook to (1) use theuseContext
hook to get the gqless clients (main client & react client) from context, & (2) call the hook and returns the result.The alternative would be to have a single hook that returns the entire gqless react client, which could be used like
const { posts } = useGqless().useQuery()
. This is not really pretty, or a simple/straightforward change to the codebase, just to add that http header.Also, using the
graphql
HOC becomes awkward since it's only accessible from within another component.Recommendation
The
ReactClient
should include aGqlessContext: React.Context<GqlessClient<GeneratedSchema>>
member which is consumed by the hooks & hoc. This would allow us to provide the client using<GqlessContext.Provider value={client}>
, or not do that (theclient
param passed tocreateReactClient
should be used as the default value), and use the same hooks & HOC either way.The text was updated successfully, but these errors were encountered: