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
[Modern] Query only the local client extension types will cause compiling error #2471
Comments
I can confirm the error and I'm also looking for the same functionality. In my case is even a little bit more complex because my GraphQL API requires an accessToken and I have a |
In order to overcome this limitation I just add |
@hisapy Can you elaborate on that by giving an example? (I’m not using this right now, so I’m only asking for the next reader that stumbles on this ticket.) |
In the following example, using const newUserFormQuery = graphql`
query routes_NewUserQuery {
__typename
state: userForm {
...UserForm_state
}
}
`; |
@hisapy Thanks for the workaround. It works for me. Hopefully in the future we don't need the hack though. |
Relay v4 https://github.com/facebook/relay/releases/tag/v4.0.0 it has full support to client schema extensions: full GraphQL types as well Added full support for client schema extensions: now full GraphQL types can be defined in the client schema (as opposed to just extending existing server types), and they will be properly retained during garbage collection when rendered can you test this again? or add a repro so we can investigate further? |
@sibelius I ran into this bug with v5.0.0 |
can you provide a sample repro? |
Types in local schema file: type LocalState {
id: ID!
whatever: String
}
extend type Query {
localState: LocalState
} Use local-schema-only fields in a query in js: import { graphql } from 'relay-runtime';
const query = graphql`
query state_Query {
localState {
whatever
}
}
`; when running relay-compiler you get: |
does your file is called where are you using this query? |
yes, it's called state.js I'm using it in the same file: import { fetchQuery } from 'react-relay';
import { graphql } from 'relay-runtime';
const query = graphql`
query state_Query {
localState {
whatever
}
}
`;
const getState = async environment => {
return await fetchQuery(environment, query, {});
}; I also tried moving the query outside of the state.js, but that didn't help. I don't think it matters, where the query is. hisapy's workaround works though: query state_Query {
__typename
localState {
whatever
}
} |
I don't know what the recommended way is for querying local-only fields, as the documentation is lacking in that part, but for now I have settled on this: const getState = environment => {
return environment.getStore().getSource().get('state');
}; It's synchronous and avoids the "GraphQLCompilerContext: Unknown document" bug without having to use any workarounds. |
you can try this one https://github.com/facebook/relay/blob/master/packages/react-relay/ReactRelayLocalQueryRenderer.js LocalQueryRenderer |
Ah cool, thanks! I'll give it a try |
I see ReactRelayLocalQueryRenderer only exports React component, but I need to access the local store before actually rendering anything. |
This issue is still present.
# client.graphql
extend type Query {
isDrawerOpen: Boolean
} // Drawer.tsx
import { graphql, LocalQueryRenderer } from 'react-relay';
const Drawer = () => {
return (
<LocalQueryRenderer
environment={environment}
query={graphql`
query DrawerQuery {
isDrawerOpen
}
`}
variables={{}}
render={({ props }) => {
return <SomeDrawerImpl isOpen={props.isDrawerOpen} />;
}}
/>
);
}; # relay-compiler
ERROR:
Cannot find root 'DrawerQuery'. Moreover, @hisapy's workaround still works (appending ...
query={graphql`
query DrawerQuery {
__typename
isDrawerOpen
}
`}
... |
Reviewed By: josephsavona Differential Revision: D19953903 fbshipit-source-id: 8863cc4d5215af0016438dd09ddf34e4710eb47b
v9.1.0 has added this change which kills this workaround. Because of the aforementioned change, you must downgrade the compiler back to v9.0.0 for the |
try this as workaround ... on Query { __typename } instead of just |
If you're only reading client fields there's no reason to define a Query at all - you can just use a fragment. |
@josephsavona Can you please elaborate? I thought that |
@josephsavona how do you use a "fragment" for the local lookup? I like the query approach because the compiler would kick in and I get types auto-magically. |
@josephsavona what's the "fragment-only" method that you're referring to? |
try https://gist.github.com/sibelius/43bd345873f84684c66942d9f06eeb2d const useLocalQuery = <TQuery extends {response: any; variables: any}>(
environment: Environment,
query: any,
inVariables: TQuery['variables'] = {}
): TQuery['response'] | null => {
const variables = useDeepEqual(inVariables)
const [dataRef, setData] = useRefState<SelectorData | null>(null)
const disposablesRef = useRef<Disposable[]>([])
useEffect(() => {
const {getRequest, createOperationDescriptor} = environment.unstable_internal
const request = getRequest(query)
const operation = createOperationDescriptor(request, variables)
const res = environment.lookup(operation.fragment, operation)
setData(res.data || null)
disposablesRef.current.push(environment.retain(operation.root))
disposablesRef.current.push(
environment.subscribe(res, (newSnapshot) => {
setData(newSnapshot.data || null)
})
)
const disposables = disposablesRef.current
return () => {
disposables.forEach((disposable) => disposable.dispose())
}
}, [environment, setData, query, variables])
return dataRef.current
} based on #1656 (comment) |
@sibelius, is that what @josephsavona meant? You're still defining a query with I'm not able to use your suggestion because it contains references to code that doesn't exist (e.g., what is I'm using the undocumented |
I haven't looked at Relay in 6 months, but I recall seeing EDIT: I just took a quick peek at the code - Look at the There's no test for |
@babangsund thanks for the tip! I am adding this to the list of changes that I want to submit PR's for. |
would like to know as well |
The "New in Relay Modern" post indicates this support is experimental. This changes the title of the guide to match the announcement. https://relay.dev/docs/en/new-in-relay-modern#client-schema-extensions-experimental As of this writing this feature still seems to be experimental. facebook#2471 (open) facebook#1656 (closed, related)
As a workaround to this limitation I have added query resolver in the backend called ping that simply returns the string "pong". I now simply include this ping field in every query that only has local fields to trick the compiler. I have also added some middleware to the front end network layer to prevent queries going out to the server. I'm using react-relay-network-modern to build the front end middleware stack. Here's the implementation for that middleware (in TypeScript) if you would like to do something similar. /*
* There is an open issue in the Relay Compiler that makes it so that only requesting fields from the local storage will
* result in an error. You can find out more about the issue here: https://github.com/facebook/relay/issues/2471
*
* As a work around we have added a dummy field that queries the ping/pong endpoint. This middleware makes it so that
* a round trip to the server isn't necessary when that happens.
*
* The middleware itself is implemented using a simple regex instead of a proper parser to keep it performant. After all
* every request passes through it.
* */
const onlyPingQueryRE = /query\s[a-zA-Z]+\s{\s+ping\s+}\s+/;
const dummyResponse = RelayNetworkLayerResponse.createFromGraphQL({
data: {ping: 'pong'},
});
const bustRelayLocalCacheMiddleware = (next: MiddlewareNextFn) => async (
req: RelayRequestAny,
) => {
const queryString = req.getQueryString();
if (queryString.match(onlyPingQueryRE)) {
return dummyResponse;
}
return next(req);
}; This solution makes it so we don't have to use the |
your suggestion works but we are getting a warning, can you give us any hints? |
I remember an issue with local queries in Relay, specifically that a query made on (i.e. a single field) of a local type, would always result in an extra round-trip to the backend. Is this still the case in V11? |
I was able to get rid of this warning message by adding |
@alunyov We should find a way to make local-only queries work somehow |
@josephsavona yeah - there is a recent report of this too: #3760 We'll add this. |
Never mind. The page the diff was against was removed. |
Let's say I declare the client schema extensions
client.graphql
And then in the QueryRenderer I made the query like this
The
relay-compiler
will fire the errorMy temporary workaround is adding extra fields that can be fetched from remote.
In this way, compiler can successfully compile the static query.
My assumption is
relay-compiler
will remove whatever client extensions from the query string, if I only query the local type, the query string will be stripped out entirely.My question is "Is it possible for relay to query ONLY the local type?" People like me are excited about the client extensions is because it gives a way to get rid of the redux store. It will be really helpful if we can directly query the local type and use commitLocalUpdate for the state management.
The text was updated successfully, but these errors were encountered: