I created a NestJS sample, I add a Mutation to sync user info to my backend.
And added the following codes, the #GqlUser is to extract user info from my jwt token.
#Mutation((returns) => UpdateUserResult)
#UseGuards(JwtAuthGuard)
updateUser(#GqlUser() user: UserPrincipal): Observable<UpdateUserResult> {
console.log('gql user:', user);
const { userId, email, name } = user;
return this.usersService.update({ id: userId, email, name }).pipe(
map((b) => ({
success: b,
})),
);
}
The related GraphQL definition is generated by NestJS as the following:
type Mutation {
//... other defs.
updateUser: UpdateUserResult!
}
type UpdateUserResult {
message: String!
success: Boolean!
}
// other defs.
But when executing this mutation by the following forms.
// failed due to *the expectedName is not a ")"*, it is a syntax error
mutation SyncUser{
updateUser(){//error
success
}
}
// or
mutation SyncUser(){ // error
updateUser(){
success
}
}
or
// failed due to *this.subQuery is not a function*
mutation {
updateUser {
success
}
}
In GraphQLspec, the input arguments should be optional in a mutation definition.
Your mutation name is updateUser, so you should use something similar this:
mutation {
updateUser ()
{
success
}
}
Consider that inside the parentheses, you need to pass data needed for the operation.
Anyway, I suggest using GraphQL PlayGround to find the correct query format.
Related
I have a Graphql schema that looks like this:
type Mutation {
createUploadUrl(
input: CreateUploadUrl!
): MyResponse!
}
input CreateUploadUrl {
deploymentId: ID!
}
I'm new to Graphql and am getting lost when trying to work out what my query should look like when I submit it via fetch:
fetch('https://example.com', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
query: `
mutation($input: ) {
createUploadUrl($input) {
__typename,
// my values I want to retrieve
// ...
}
}`,
variables: {
input: {deploymentId: "XXX"}
}
}),
})
.then((res) => res.json())
.then((result) => console.log(result));
The above gives me an error: `message: "Syntax Error: Expected Name, found "$"."
How am I supposed to specify a query or mutation that requires an object as a variable?
`
You just need to define your parametrized function and wrap the effective mutation.
In the example below the mutation MyMutation takes as param a $arg wich is a CreateUploadUrl!.
Then pass the $arg to the input of the mutation, the invocation becomes:
mutation MyMutation($arg: CreateUploadUrl!) {
createUploadUrl(input: $arg) {
__typename,
...
}
I have a login mutation tha looks similiar to this:
mutation login($password: String!, $email: String) {
login(password: $password, email: $email) {
jwt
user {
account {
id
email
}
}
}
}
On the other hand, I have a query for getting the account details. The backend verifies which user it is by means of the JWT token that is send with the request, so no need for sending the account id as an argument.
query GetUser {
user {
account {
id
email
}
}
}
The issue I am facing is now: Apollo is making a network request every time as GetUser has no argument. I would prever to query from cache first. So I thought, I could redirect as described here.
First, I was facing the issue that user field does not return an id directly so I have defined a type policy as such:
const typePolicies: TypePolicies = {
User: {
keyFields: ["account", ["id"]],
},
}
So regarding the redirect I have add the following to the type policy:
const typePolicies: TypePolicies = {
User: {
keyFields: ["account", ["id"]],
},
Query: {
fields: {
user(_, { toReference }) {
return toReference({
__typename: "User",
account: {
id: "1234",
},
})
},
},
},
}
This works, however there is a fixed id of course. Is there any way to solve this issue by always redirecting to the user object that was queried during login?
Or is it better to add the id as argument to the GetUser query?
I have solve this by means of the readField function:
Query: {
fields: {
user(_, { toReference, readField }) {
return readField({
fieldName: "user",
from: toReference({
__typename: "LoginMutationResponse",
errors: null,
}),
})
},
},
},
What happens if the reference cannot be found? It seems like apollo is not making a request then. Is that right? How can this be solved?
I have noticed this in my tests as the login query is not executed.
I'm getting the following error despite the mutation being wrapped in the gql tag:
Invariant Violation: Expecting a parsed GraphQL document. Perhaps you need to wrap the query string in a "gql" tag? http://docs.apollostack.com/apollo-client/core.html#gql
This issue is only caused by the mutation code below, I have a query that works.
Code:
<script>
import gql from 'graphql-tag'
export default {
apollo: {
createTask: {
mutation: gql`
mutation Task(
$taskName: String!
$taskDesc: String!
) {
setSession(
taskName: $taskName
taskDesc: $taskDesc
) {
id
taskName
}
}
`,
variables() {
return {
taskName: this.res.data.task_name,
taskDesc: this.res.data.task_description,
}
},
},
},
data() {
return {
createTask: '',
}
},
}
<script>
Smart queries are declared using the apollo object and are ran when the component mounts. If you have queries that you'd like to run this way, then your code would look something like this:
export default {
apollo: {
someQuery: gql`...`,
}
}
However, when working with mutations, you generally don't want to run them on mount. Instead, you want to execute the mutation in response to some user action, like a button click. So the above syntax won't work for mutations. Instead, you need to call this.$apollo.mutate directly inside one of your methods:
export default {
methods: {
createTask() {
this.$apollo.mutate({
mutation: gql`...`,
variables: {...},
// other options
}).then(result => {
// do something with the result
})
}
}
}
I had this problem recently and it was because of an issue with an async import
I am using vue-apollo
async account () {
return {
query: (await import('src/modules/accounts/graphql/accounts.list.query.gql')),
......
I just had to replace that import with a require and it was happy again.
async account () {
return {
query: require('src/modules/accounts/graphql/accounts.list.query.gql'),
......
I'm using the request-promise library to make http request to a graphql server. To achieve a query, I'm doing this:
const query = `
{
user(id:"123173361311") {
_id
name
email
}
}
`
const options = {
uri: "http://localhost:5000/graphql",
qs: { query },
json: true
}
return await request(options)
The above code is working fine. However I'm confused about how to go about a mutation since I need to specify both the actual mutation and the inputData like this:
// Input
{
name: "lomse"
email: "lomse#lomse.com"
}
const mutation = `
mutation addUser($input: AddUserInput!){
addUser(input: $input) {
_id
name
email
}
}
`
const option = {
uri: "http://localhost:5000/graphql",
formData: {mutation},
json: true,
// how to pass the actual data input
}
request.post(option)
Or is it that the request-promise library isn't designed for this use case?
Use body, not formData. Your body should consist of three properties:
query: The GraphQL document you're sending. Even if the operation is a mutation, the property is still named query.
variables: A map of your variable values serialized as a JSON object. Only required if your operation utilized variables.
operationName: Specifies which operation to execute. Only required if your document included multiple operations.
request.post({
uri : '...',
json: true,
body: {
query: 'mutation { ... }',
variables: {
input: {
name: '...',
email: '...',
},
},
},
})
The graphql-request library seems to do what I needed the request-promise library to do.
import { request } from 'graphql-request'
const variables = {
name: "lomse",
email: "lomse#lomse.com"
}
const mutation = `
mutation addUser($input: AddUserInput!){
addUser(input: $input) {
_id
name
email
}
}
`
response = await request(uri, mutation, {input: variables})
I wrote simple GraphQL schemas and resolvers in studying purpose, and I could not get reason why my codes work as expected. I used Prisma for ORM, and express-graphql and graphql-import to compose the API.
type User {
id: ID!
name: String!
}
type Link {
id: ID!
url: String!
user: User!
}
type Query {
links(id: ID!): [Link!]!
}
// resolvers
const links = async (root, args, ctx) => {
const links = await ctx.prisma.links({
where: {
user {
id: args.id
}
}
}
}
// resolver for `Link` type
const user = async (root, args, ctx) => {
const user = await ctx.prisma.link({ id: parent.id }).user()
return user
}
// omitted field resolver for `url` and `id`
module.exports = {
user
}
With these codes, I expected to get id, url, user fields when I query links, but when I send the query, it returns null with user field. Which means, if I check in the server-side, the resolver for user field does not invoked at all. What is wrong with this?