GraphQL Syntax Error while passing parameters - javascript

When I try to pass this query, I get a syntax error on the first line even though I am using a mutation with the same syntax that works:
GraphQLError: Syntax Error: Expected Name, found }
interface WhereInput {
email_contains: String;
}
export const LoadUsersQuery = gql`
query usersList($where: WhereInput) {
users(where: $where}) {
nodes {
email
firstName
}
totalCount
}
}
The word usersListis self-defined.
This is the original query looks like on the playground:
query {
users(where: {email_contains: "B"}) {
nodes {
email
firstName
}
totalCount
}
}
And this is how I am calling it:
const [searchItem, setSearchItem] = useState('');
const [loadUsers, { loading, data }] = useLazyQuery(LoadUsersQuery);
return (
<div>
<StyledSearchBar
value={searchItem}
onChange={value => {
setSearchItem(value);
}}
onRequestSearch={() => loadUsers({
variables: {
where: {email_contains: searchItem}
}
})}
/>
</div>
);

The syntax error is correct (and should point you to the exact location of the problem) - there's a stray } in there:
users(where: $where}) {
# ^

Related

Keystone 6 custom schema - mutation not working - Maximum call stack size exceeded

I'm trying to extend a mutation in Keystone 6, but having a lot of trouble just getting the standard DB update to work in a custom mutation resolver; Using the standard Keystone boilerplate and added a new collection/list.
Following the examples here, I've matched custom-schema.ts with the generated schema.graphql
schema.graphql (simplified):
type Dog {
id: ID!
name: String
}
input DogWhereUniqueInput {
id: ID
}
input DogUpdateInput {
name: String
}
type Mutation {
updateDog(
where: DogWhereUniqueInput!
data: DogUpdateInput!
): Dog
}
custom-schema.ts:
import { graphQLSchemaExtension } from '#keystone-6/core';
import { Context } from '.keystone/types';
export const extendGraphqlSchema = graphQLSchemaExtension<Context>({
typeDefs: `
type Mutation {
""" update a dog """
updateDog(
where: DogWhereUniqueInput!
data: DogUpdateInput!
): Dog
}
`,
resolvers: {
Mutation: {
updateDog: async (root, { where, id }, context) => {
try {
const response = await context.db.Dog.updateOne({
where: { id },
data: { name: 'updated name'}
});
return response;
} catch (updateError: any) {
throw updateError;
}
}}
}
},
);
keystone.ts:
import { extendGraphqlSchema } from './custom-schema';
// ...
export default withAuth(
config({
db: {
provider: 'sqlite',
url: 'file:./keystone.db',
},
ui: {
isAccessAllowed: (context) => !!context.session?.data,
},
lists,
session,
extendGraphqlSchema,
})
);
When I trigger an update from the (boilerplate) UI, I get this error repeatedly from the catch error handler. Same happens in graphQL playground. Really struggling to understand what's happening and why the resolver is getting spammed and generating this error.
RangeError: Maximum call stack size exceeded
at isLeafType (.../poc/node_modules/graphql/type/definition.js:247:20)
at coerceInputValueImpl (.../poc/node_modules/graphql/utilities/coerceInputValue.js:122:34)
Why is this happening, how to fix? Am I missing something obvious?
That's because both context.db and context.query internally still use the GraphQL API for CRUD. And since your custom mutation updateDog also has the same name as the generated mutation from schema updateDog, both the mutations are repeatedly invoking each other and hence the error RangeError: Maximum call stack size exceeded.
You can solve your problem in one of the two ways —
Change the name of your custom mutation to something else. Eg. updateDogCustom
or
(Practice caution) Instead of context.db.Dog.updateOne, use the prisma client to skip keystone's data layer and CRUD the database directly. Be warned, this means if you have hooks, access control or validation logic in place they won't be invoked.
export const extendGraphqlSchema = graphQLSchemaExtension<Context>({
typeDefs: `
type Mutation {
""" update a dog """
updateDog(
where: DogWhereUniqueInput!
data: DogUpdateInput!
): Dog
""" update a dog custom """
updateDogCustom(
where: DogWhereUniqueInput!
data: DogUpdateInput!
): Dog
}
`,
resolvers: {
Mutation: {
updateDog: async (root, { where: { id }, data: { name } }, context) => {
try {
const response = await context.prisma.dog.update({
where: { id },
data: { name },
});
return response;
} catch (updateError: any) {
throw updateError;
}
},
updateDogCustom: async (
root,
{ where: { id }, data: { name } },
context
) => {
try {
const response = await context.db.Dog.updateOne({
where: { id },
data: { name },
});
return response;
} catch (updateError: any) {
throw updateError;
}
},
},
},
});
Codesandbox here — https://codesandbox.io/s/winter-shadow-fz689e?file=/src/custom-schema.ts
You can run the graphql playground right from codesandbox from /api/graphql path. Eg. https://fz689e.sse.codesandbox.io/api/graphql

typescript custom component function param throwing warning

I have this piece of code
<GoogleLogin
onSuccess={responseGoogle => {
const { email, name } = responseGoogle.profileObj; // error: Property 'profileObj' does not exist on type 'GoogleLoginResponse | GoogleLoginResponseOffline'.
}}
/>
The library is here https://www.npmjs.com/package/react-google-login
What should I do? I tried (responseGoogle:any) it doesn't work.
You have to specify the login response type. It can either be GoogleLoginResponseOffline or GoogleLoginResponse. The property profileObj exists only in GoogleLoginResponse. If you are requesting offline access, the response will only have a code in the response and you should use GoogleLoginResponseOffline type.
<GoogleLogin
onSuccess={(responseGoogle: GoogleLoginResponse) => {
const { email, name } = responseGoogle.profileObj;
}}
/>
Try this
<GoogleLogin
onSuccess={(responseGoogle: GoogleLoginResponse ) => {
const { email, name } = responseGoogle.profileObj
}}
/>
Or you can also use the as keyword to let the typescript know that it is of type GoogleLoginResponse and not misinterpret it as GoogleLoginResponseOffline.
Try this
<GoogleLogin
onSuccess={({ profileObj: { email, name } = {} }: any) => {
// use email and name
}
/>

How change query value (where : { }) with Apollo GraphQL

with graphQL we can fetch data with "where"
query{
activities(where: {date: "2020-08-01"}){
date
collect
}
}
How change the date value to params ?
I try this :
let date = "2020-01-08"
const { loading, error, data } = useQuery(GET_ACTIVITY, {
variables: {
input: {
where: { date: date }
}
}
});
First the schema definition from your back-end must be something like this:
type Activity {
date: String
collect: String
...
}
type Query {
activities(date: String): [Activity]
...
}
then in the front-end create the query using the gql function from #apollo/client:
import { gql, useQuery } from '#apollo/client';
...
const GET_ACTIVITY = gql`
query Activities($date: String!) {
activities(date: $date){
date
collect
}
}
`;
And finally call it like this:
let date = "2020-01-08";
const { loading, error, data } = useQuery(GET_ACTIVITY, {
variables: {
date
}
});
More about queries: https://www.apollographql.com/docs/react/data/queries

`updater` not working correctly when using subscriptions in Relay Modern

I'm using Relay Modern in my app and have successfully integrated subscriptions using the requestSubscription function. All works well and the updater function that I use to update the cache gets called correctly with the proper subscription payload.
The subscription is used to add a new item to a list of Link elements. Here's what the subscription looks like:
NewLinkSubscription.js
const newLinkSubscription = graphql`
subscription NewLinkSubscription {
Link {
mutation
node {
id
description
url
createdAt
postedBy {
id
name
}
}
}
}
`
export default (updater, onError) => {
const subscriptionConfig = {
subscription: newLinkSubscription,
variables: {},
updater,
onError
}
requestSubscription(
environment,
subscriptionConfig
)
}
I then have a LinkList component that's rendering all the Link elements. In componentDidMount of that component, I initiate the NewLinkSubscription:
LinkList.js
class LinkList extends Component {
componentDidMount() {
NewLinkSubscription(
proxyStore => {
const createLinkField = proxyStore.getRootField('Link')
const newLink = createLinkField.getLinkedRecord('node')
const viewerProxy = proxyStore.get(this.props.viewer.id)
const connection = ConnectionHandler.getConnection(viewerProxy, 'LinkList_allLinks')
if (connection) {
ConnectionHandler.insertEdgeAfter(connection, newLink)
}
},
error => console.log(`An error occured:`, error),
)
}
render() {
console.log(`LinkList - render `, this.props.viewer.allLinks.edges)
return (
<div>
{this.props.viewer.allLinks.edges.map(({node}) =>
{
console.log(`render node: `, node)
return <Link key={node.id} link={node} viewer={this.props.viewer} />
}
)}
</div>
)
}
}
export default createFragmentContainer(LinkList, graphql`
fragment LinkList_viewer on Viewer {
id
...Link_viewer
allLinks(last: 100, orderBy: createdAt_DESC) #connection(key: "LinkList_allLinks", filters: []) {
edges {
node {
...Link_link
}
}
}
}
`)
Now, here's what's happening when a subscription with a new Link comes in. The updater is called correctly and it seems like the new node gets inserted into the connection correctly (at least ConnectionHandler.insertEdgeAfter(connection, newLink) is called).
This triggers a rerender of the component. When I debug render to inspect the data (props.viewer.allLinks.edges), I can see that a new node indeed was added to the connection - so the list actually does contain one more item now! However, the problem is that this new node is actually undefined which causes the app to crash!
Does anyone spot what I'm missing here?
I was able to make it work, this is how I implemented the updater now:
NewLinkSubscription(
proxyStore => {
const linkField = proxyStore.getRootField('Link')
const newLink = linkField.getLinkedRecord('node')
const viewerProxy = proxyStore.get(this.props.viewer.id)
const connection = ConnectionHandler.getConnection(viewerProxy, 'LinkList_allLinks', {
last: 100,
orderBy: 'createdAt_DESC'
})
if (connection) {
const edge = ConnectionHandler.createEdge(proxyStore, connection, newLink, 'allLinks')
ConnectionHandler.insertEdgeBefore(connection, edge)
}
},
error => console.log(`An error occurred:`, error),
)

Uncaught Error: react-apollo only supports a query, subscription, or a mutation per HOC

I'm trying to wrap my Chat component with two queries and one mutation using compose.
However, I'm still getting the following error in the console:
Uncaught Error: react-apollo only supports a query, subscription, or a mutation per HOC. [object Object] had 2 queries, 0 subscriptions and 0 mutations. You can use 'compose' to join multiple operation types to a component
Here are my queries and the export statement:
// this query seems to cause the issue
const findConversations = gql`
query allConversations($customerId: ID!) {
allConversations(filter: {
customerId: $customerId
})
} {
id
}
`
const createMessage = gql`
mutation createMessage($text: String!, $conversationId: ID!) {
createMessage(text: $text, conversationId: $conversationId) {
id
text
}
}
`
const allMessages = gql`
query allMessages($conversationId: ID!) {
allMessages(filter: {
conversation: {
id: $conversationId
}
})
{
text
createdAt
}
}
`
export default compose(
graphql(findConversations, {name: 'findConversationsQuery'}),
graphql(allMessages, {name: 'allMessagesQuery'}),
graphql(createMessage, {name : 'createMessageMutation'})
)(Chat)
Apparently, the issue is with the findConversations query. If I comment it out, I don't get the error and the component loads properly:
// this works
export default compose(
// graphql(findConversations, {name: 'findConversationsQuery'}),
graphql(allMessages, {name: 'allMessagesQuery'}),
graphql(createMessage, {name : 'createMessageMutation'})
)(Chat)
Can anyone tell me what I'm missing?
By the way, I also have a subscription set up on the allMessagesQuery, in case that's relevant:
componentDidMount() {
this.newMessageSubscription = this.props.allMessagesQuery.subscribeToMore({
document: gql`
subscription {
createMessage(filter: {
conversation: {
id: "${this.props.conversationId}"
}
}) {
text
createdAt
}
}
`,
updateQuery: (previousState, {subscriptionData}) => {
...
},
onError: (err) => console.error(err),
})
}
Your findConversationsQuery is actually two queries. This one:
query allConversations($customerId: ID!) {
allConversations(filter: {
customerId: $customerId
})
}
And this one:
{
id
}
The entire query needs to be enclosed between a single pair of opening and closing brackets.
I think what you meant to write is:
query allConversations($customerId: ID!) {
allConversations(filter: { customerId: $customerId }){
id
}
}

Categories

Resources