I'm using graphql all across my app. The problem is on the front end I also have to make a query to a 3rd party rest API and to remain consistent I used #rest directive of graphql to make a get request. Now the issue is, I want graphql to not send the query params that are undefined but the issue is with #rest directive it sends the undefined value too which is becoming an issue for me. Can somebody please tell me how can I fix this? Thanks
const getNftsQuery = gql`
query Nfts($limit: Int, $owner: String!) {
# eslint-disable-next-line #graphql-eslint/fields-on-correct-type
entities: nfts(limit: $limit, owner: $owner)
# eslint-disable-next-line #graphql-eslint/known-directives
#rest(method: GET, path: "/api/v1/assets?owner={args.owner}&limit={args.limit}&cursor={args.cursor}", type: "[Nft]") {
list: assets {
id
image_url
name
token_id
}
}
}
`;
function useGetNfts(owner: string, limit: number, cursor: string | undefined): QueryNftsResults {
const { loading, error, data, networkStatus, fetchMore } = useQuery<Pagination<NFT>>(getNftsQuery, {
variables: { owner, limit, cursor },
notifyOnNetworkStatusChange: true,
context: { clientName: ClientName.nftClient },
});
return { loading, error, data, networkStatus, fetchMore };
}
export default useGetNfts;
Related
I have started getting this warning, when I update an "Transaction" with a mutation.
The code is old and have newer showed this warning before. I do not know when this regression started.
Oddly enough, In my mind there should be no cache either, since fetchPolicy: "network-only" is set.
How can I get rid of the warning?
invariant.esm.js:42 Cache data may be lost when replacing the transactions field of a Query object.
To address this problem (which is not a bug in Apollo Client),
define a custom merge function for the Query.transactions field,
so InMemoryCache can safely merge these objects:
existing: [{"__ref":"Transaction:5feabda25e7967001267ffd2"},
{"__ref":"Transaction:5feabda55e7967001267ffd3"},
{"__ref":"Transaction:5feabda75e7967001267ffd4"},
{"__ref":"Transaction:5feabda95e7967001267ffd5"},
{"__ref":"Transaction:5feabdab5e7967001267ffd6"},
{"__ref":"Transaction:60127209c3731400116fe0c5"},
{"__ref":"Transaction:602543cde12cd00011881a8b"},
{"__ref":"Transaction:602544e7e12cd00011881a91"},
{"__ref":"Transaction:602f7d9be14be20011a5cbec"},
{"__ref":"Transaction:6033b4d5ad34870011e7ba08"},
{"__ref":"Transaction:603494fbad34870011e7bf07"},
{"__ref":"Transaction:6038a0519d844c00116e544f"},
{"__ref":"Transaction:6038a05f9d844c00116e545e"},
{"__ref":"Transaction:6038a06c9d844c00116e549e"},
{"__ref":"Transaction:6038a06f9d844c00116e54a1"},
{"__ref":"Transaction:6038a0549d844c00116e5452"},
{"__ref":"Transaction:6038a0629d844c00116e545f"},
{"__ref":"Transaction:6038a0699d844c00116e549a"},
{"__ref":"Transaction:603cd5c39d844c00116f232b"},
{"__ref":"Transaction:603ce07d9d844c00116f2342"},
{"__ref":"Transacti
incoming: [{"__ref":"Transaction:5feabda25e7967001267ffd2"},
{"__ref":"Transaction:5feabda55e7967001267ffd3"},
{"__ref":"Transaction:5feabda75e7967001267ffd4"},
{"__ref":"Transaction:5feabda95e7967001267ffd5"},
{"__ref":"Transaction:5feabdab5e7967001267ffd6"},
{"__ref":"Transaction:60127209c3731400116fe0c5"},
{"__ref":"Transaction:602543cde12cd00011881a8b"},
{"__ref":"Transaction:602544e7e12cd00011881a91"},
{"__ref":"Transaction:602f7d9be14be20011a5cbec"},
{"__ref":"Transaction:6033b4d5ad34870011e7ba08"},
{"__ref":"Transaction:603494fbad34870011e7bf07"},
{"__ref":"Transaction:6038a0519d844c00116e544f"},
{"__ref":"Transaction:6038a05f9d844c00116e545e"},
{"__ref":"Transaction:6038a06c9d844c00116e549e"},
{"__ref":"Transaction:6038a06f9d844c00116e54a1"},
{"__ref":"Transaction:6038a0549d844c00116e5452"},
{"__ref":"Transaction:6038a0629d844c00116e545f"},
{"__ref":"Transaction:6038a0699d844c00116e549a"},
{"__ref":"Transaction:603cd5c39d844c00116f232b"},
{"__ref":"Transaction:603ce07d9d844c00116f2342"},
{"__ref":"Transacti
For more information about these options, please refer to the documentation:
* Ensuring entity objects have IDs: https://go.apollo.dev/c/generating-unique-identifiers
* Defining custom merge functions: https://go.apollo.dev/c/merging-non-normalized-objects
From code that looks like this:
const UPDATE_TRANSACTION = gql`
mutation updateTransaction($input: UpdateTransactionInput!) {
updateTransaction(input: $input) {
_id
status
}
}
`;
export const DealBlotterGrid = ({ startDate }: DealBlotterGridPropsType): ReactElement => {
const swedenIsoString = moment.tz(startDate, "Europe/Stockholm").format();
const { loading, error, data } = useQuery(GET_TRANSACTIONS, {
variables: { tradeTimestampStart: swedenIsoString },
fetchPolicy: "network-only",
pollInterval: 10000
});
const [updateTransactionStatus] = useMutation(UPDATE_TRANSACTION, {
refetchQueries: [
{
query: GET_TRANSACTIONS,
variables: { tradeTimestampStart: swedenIsoString }
}
]
});
...
I'm a bit stuck. I am using graphql-request with react-query, following the example code quite closely. I replaced it with my own backend, and it works when I don't use variables, but hardcode the values. It also all works in my GraphiQL test environment.
So doing this works:
export default function usePost(postId) {
return useQuery(
["post", postId],
async () => {
const { post } = await request(
endpoint,
gql`
query {
post(id: "123123123123") { // <--- with the id hard-coded, it works
id
heading
content
}
}
`
)
return post
},
{
enabled: !!postId,
}
)
}
What follows is exactly the same code, but now the previously hard-coded post-id ("123123123123") is replaced by a variable (${postId}). Exactly as described in the example code
export default function usePost(postId) {
return useQuery(
["post", postId],
async () => {
const { post } = await request(
endpoint,
gql`
query {
post(id: ${postId}) { // <--- with the ${postId} variable, things break, but it's exactly the same syntax as in the react-query example & it works in my graphiql backend. Also console-logged the postId, and it is correct
id
heading
content
}
}
`
)
return post
},
{
enabled: !!postId,
}
)
}
The error response is:
commons.js:46154 Error: Syntax Error: Expected :, found ):
{"response":{"errors":[{"message":"Syntax Error: Expected :, found
)","locations":[{"line":3,"column":46}]}],"status":400},"request":{"query":"\n
query {\n post(id: 5fda109506038d9d18fa27e2) {\n
id\n heading\n content\n }\n
}\n "}}
at GraphQLClient. (commons.js:13039)
at step (commons.js:12930)
at Object.next (commons.js:12911)
at fulfilled (commons.js:12902)
I guess it's some syntax that I am getting wrong? Or could it have to do with the fact that now the quotation marks are missing? Though the example code also doesn't do anything differently... Really not sure anymore, but it's literally that one line that breaks it all and that I cannot figure out.
Your id 5fda109506038d9d18fa27e2 looks to be a string but you're not passing it as a string to your back end, which is why you're getting a syntax error.
It looks like this
query {
post(id: 5fda109506038d9d18fa27e2) {
id
title
body
}
}
Notice how there aren't any quotation marks around the id? e.g. "5fda109506038d9d18fa27e2". You can also use integers as ids, I just want to make a point that you're not actually passing an integer. Read more on scalar types here.
I recommend you pass variables how they're intended by graphql rather than using string interpolation. This will help avoid this problem. Read more on variables in graphql here.
Here's an example of passing variables in graphql:
query Post($id: ID!) {
post(id: $id) {
id
title
body
}
}
Here's how it would look using your code:
function usePost(postId) {
return useQuery(
["post", postId],
async () => {
const { post } = await request(
endpoint,
gql`
query Post($id: ID!) {
post(id: $id) {
id
title
body
}
}
`,
{ id: postId }
);
return post;
},
{
enabled: !!postId
}
);
}
Having a weird issue passing variables into the useQuery hook.
The query:
const GET_USER_BY_ID= gql`
query($id: ID!) {
getUser(id: $id) {
id
fullName
role
}
}
`;
Calling the query:
const DisplayUser: React.FC<{ id: string }> = ({ id }) => {
const { data, error } = useQuery(GET_USER_BY_ID, {
variables: { id },
});
return <div>{JSON.stringify({ data, error })}</div>;
};
Rendering the component:
<DisplayUser id="5e404fa72b819d1410a3164c" />
This yields the error:
"Argument \"id\" of required type \"ID!\" was provided the variable \"$id\" which was not provided a runtime value."
Calling the query from GraphQL Playground returns the expected result:
{
"data": {
"getUser": {
"id": "5e404fa72b819d1410a3164c",
"fullName": "Test 1",
"role": "USER"
}
}
}
And calling the query without a variable but instead hard-coding the id:
const GET_USER_BY_ID = gql`
query {
getUser(id: "5e404fa72b819d1410a3164c") {
id
fullName
role
}
}
`;
const DisplayUser: React.FC = () => {
const { data, error } = useQuery(GET_USER_BY_ID);
return <div>{JSON.stringify({ data, error })}</div>;
};
Also returns the expected result.
I have also attempted to test a similar query that takes firstName: String! as a parameter which also yields an error saying that the variable was not provided a runtime value. This query also works as expected when hard-coding a value in the query string.
This project was started today and uses "apollo-boost": "^0.4.7", "graphql": "^14.6.0", and "react-apollo": "^3.1.3".
[Solved]
In reading through the stack trace I noticed the issue was referencing graphql-query-complexity which I was using for validationRules. I removed the validation rules and now everything works! Granted I don't have validation at the moment but at least I can work from here. Thanks to everyone who took the time to respond!
I had also ran into a similar issue and was not really sure what was happening.
There seems to be similar problem reported here - https://github.com/apollographql/graphql-tools/issues/824
We have 2 options to fix the issue.
- First one is a simple fix, where in you don't make the ID mandatory when it takes only a single parameter ( which is not an object )
const GET_USER_BY_ID= gql`
query($id: ID) {
Second option is to use an object as a parameter instead of a primitive. I went ahead with this and it seemed to work fine for me even though I made the object and the property inside to be required.
// On the client
const GET_USER_BY_ID= gql`
query($input: GetUserInput!) {
getUser(input: $input) {
id
fullName
role
}
}`;
const { data, error } = useQuery(GET_USER_BY_ID, {
variables: { input: { id }},
});
// In the server, define the input type
input GetUserInput {
id: ID!
}
Try
const { data, error } = useQuery(GET_USER_BY_ID, { id });
I am following this Apollo Pagination tutorial:
Apollo Pagination Examples
Summary of my issue:
I have a known working GraphQL query that works in the playground. When I try to fetch data and use it in a React component, as outlined in that Apollo link above, I get the following error:
"TypeError: Cannot read property 'errorlogsConnection' of undefined"
However, when I check the response from the graphQL api in the web console, the query does in fact return data. Picture attached below.
I believe I'm probably trying to reference the object incorrectly but I can't spot what my mistake is.
Note: I have been able to query and use this same API endpoint in other React components for this very same project without issue.
Here is the code involved:
I am using this query, which works in my GraphiQL playground:
query errorlogsConnection($cursor: String) {
errorlogsConnection(orderBy: errorid_DESC, first: 4, after: $cursor) {
edges {
node {
errorid
errorlog
entrydate
}
}
pageInfo {
hasPreviousPage
hasNextPage
endCursor
startCursor
}
}
}
Here is the ReactJS code that I've adapted from their tutorial:
function ErrorLogsPagination() {
const {data: {errorlogsConnection: errorLogs}, loading, fetchMore, error} = useQuery(
ERROR_LOG_PAGINATION
);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :(</p>;
return (
<ErrorLogs
entries={errorLogs || []}
onLoadMore={() =>
fetchMore({
variables: {
cursor: errorLogs.pageInfo.endCursor
},
updateQuery: (previousResult, { fetchMoreResult }) => {
const newEdges = fetchMoreResult.errorLogs.edges;
const pageInfo = fetchMoreResult.errorLogs.pageInfo;
return newEdges.length
? {
// Put the new comments at the end of the list and update `pageInfo`
// so we have the new `endCursor` and `hasNextPage` values
comments: {
__typename: previousResult.errorLogs.__typename,
edges: [...previousResult.errorLogs.edges, ...newEdges],
pageInfo
}
}
: previousResult;
}
})
}
/>
);
}
The data property will be undefined until the data is fetched from the server or the cache. To prevent the error, either avoid destructuring data until after loading is complete, or else provide default values where appropriate:
const {
data: {
errorlogsConnection: errorLogs
} = {},
loading,
fetchMore,
error,
} = useQuery(ERROR_LOG_PAGINATION)
I've got the following setup for my app. I have a LinkList component that renders a list of Link components. Then I also have a CreateLink component to create new links. Both are rendered under different routes with react-router:
<Switch>
<Route exact path='/create' component={CreateLink}/>
<Route exact path='/:page' component={LinkList}/>
</Switch>
The Link type in my GraphQL schema looks as follows:
type Link implements Node {
url: String!
postedBy: User! #relation(name: "UsersLinks")
votes: [Vote!]! #relation(name: "VotesOnLink")
comments: [Comment!]! #relation(name: "CommentsOnLink")
}
I'm using Apollo Client and want to use the imperative store API to update the list after new Link was created in the CreateLink component.
await this.props.createLinkMutation({
variables: {
description,
url,
postedById
},
update: (store, { data: { createLink } }) => {
const data = store.readQuery({ query: ALL_LINKS_QUERY }) // ERROR
console.log(`data: `, data)
}
})
The problem is that store.readQuery(...) throws an error:
proxyConsole.js:56 Error: Can't find field allLinks({}) on object (ROOT_QUERY) {
"allLinks({\"first\":2,\"skip\":10})": [
{
"type": "id",
"id": "Link:cj3ucdguyvzdq0131pzvn37as",
"generated": false
}
],
"_allLinksMeta": {
"type": "id",
"id": "$ROOT_QUERY._allLinksMeta",
"generated": true
}
}.
Here is how I am fetching the list of links in my LinkList component:
export const ALL_LINKS_QUERY = gql`
query AllLinksQuery($first: Int, $skip: Int) {
allLinks(first: $first, skip: $skip) {
id
url
description
createdAt
postedBy {
id
name
}
votes {
id
}
}
_allLinksMeta {
count
}
}
`
export default graphql(ALL_LINKS_QUERY, {
name: 'allLinksQuery',
options: (ownProps) => {
const { pathname } = ownProps.location
const page = parseInt(pathname.substring(1, pathname.length))
return {
variables: {
skip: (page - 1) * LINKS_PER_PAGE,
first: LINKS_PER_PAGE
},
fetchPolicy: 'network-only'
}
}
}) (LinkList)
I am guessing that the issue somehow has to do with my pagination approach, but I still don't know how to fix it. Can someone point me into the right direction here?
How to read a paginated list from the store depends on how you do the pagination. If you're using fetchMore, then all the data will be stored under the original keys of the query, which in this case I guess was fetched with { first: 2, skip: 0 }. That means in order to read the updated list from the store, you would have to use the same parameters, using { first: 2, skip: 0 } as variables.
PS: The reason Apollo does it this way is because it still allows you to relatively easily update a list via a mutation or update store. If each page was stored separately, it would be very complicated to insert an item in the middle or the beginning of the list, because all of the pages would potentially have to be shifted.
That said, we might introduce a new client-side directive called #connection(name: "ABC") which would let you explicitly specify under which key the connection is to be stored, instead of automatically storing it under the original variables. Happy to talk more about it if you want to open an issue on Apollo Client.