Parameterized queries qraphQL - graphql

I want to make parameterized requests from the Apollo client to the Apollo server.
On client:
const GET_VALUES = gql`
query Values($desc: String!) {
Values
}
`;
function ValueSelector({ pickValue, dirDesc }) {
const { loading, data, error } = useQuery(GET_VALUES, {
variables: { dirDesc },
});
}
On server (schema):
type Query {
Values(desc: String!): [String]
#cypher(
statement: "MATCH (:Dir{description:$desc})-[:value]->(v) RETURN collect(v.TXTLG)"
)
}
Result:
[GraphQL error]: Message: Field "Values" argument "desc" of type "String!" is required, but it was not provided., Location: [object Object], Path: undefined
[Network error]: ServerError: Response not successful: Received status code 400

You should use desc instead of dirDesc in variables param of useQuery. Try this:
const { loading, data, error } = useQuery(GET_VALUES, {
variables: { desc: dirDesc },
});

const GET_VALUES = gql`
query Values($desc: String!) {
Values(desc: $desc)
}
`;
function ValueSelector({ pickValue, dirDesc }) {
const { loading, data, error } = useQuery(GET_VALUES, {
variables: { desc:dirDesc},
});

Your query declaration on the client is missing the actual variable. It should be something like this
const GET_VALUES = gql`
query Values($desc: String!) {
Values(dirDesc: $desc)
}
`;
Then you can use useQuery passing dirDesc.

Related

Apollo GQL useMutation does not return data field

I have the following mutation that works just fine in the Sandbox (it creates and returns the bookmark):
mutation CreateBookmark ($options: BookmarkInput!) {
createBookmark(options: $options) {
bookmark {
id
title
url
}
}
}
When I try to create a bookmark from my react app, the bookmark is being created but data is undefined.
This is my code:
const CREATE_BOOKMARK = gql`
mutation CreateBookmark($options: BookmarkInput!) {
createBookmark(options: $options) {
bookmark {
id
title
url
}
}
}
`;
const [mutateFunction, {data, error, loading}] = useMutation(CREATE_BOOKMARK);
mutateFunction({
variables: {
options: {
title: bookmark.title,
url: bookmark.url,
},
},
});
When I try to console.log(data) it returns undefined.
I have also tried to not destructure the object that is being returned like this:
const [mutateFunction, obj] = useMutation(CREATE_BOOKMARK);
When I console.log(obj), it returns this:
{
error: ...,
loading: ...,
client: ...,
reset: ...
}
As you can see, there is no data field. Why is this happening?

Using GraphQL useQuery Variables

I'm currently on client side trying to make a query but can't go through. However it works when testing at the back-end.
back-end docs & getting response
front-end code (getting 400 code)
const QUERY_SPECIFIC_CATEGORY_PRODUCTS = gql` query QUERY_SPECIFIC_CATEGORY_PRODUCTS($category: String!) { category(input: { title: $category }) { name } } `; const { data, loading, error } = useQuery(QUERY_SPECIFIC_CATEGORY_PRODUCTS, { // prettier-ignore variables: {input: { title: "clothes" }} });
When you call useQuery just pass the "clothes" value as the category variable:
const { data, loading, error } = useQuery(QUERY_SPECIFIC_CATEGORY_PRODUCTS, {
variables: { category: "clothes" },
});

Apollo nodejs server; How to get mutation/query schema path in the request context when writing a plugin?

I'm writing an Apollo server plugin for node.js, and my goal is to improve my teams debugging experience. My plugin currently looks something like this:
export function eddyApolloPlugin(): ApolloServerPlugin {
return {
requestDidStart(requestContext) {
// Set requestId on the header
const requestId = (requestContext?.context as EddyContext)?.requestId;
if (requestId) {
requestContext.response?.http?.headers.set('requestId', requestId);
}
return {
willSendResponse(context) { // <== Where do I find the "path" in the schema here?
// Inspired by this: https://blog.sentry.io/2020/07/22/handling-graphql-errors-using-sentry
// and the official documentation here: https://docs.sentry.io/platforms/node/
// handle all errors
for (const error of requestContext?.errors || []) {
handleError(error, context);
}
},
};
},
};
}
I would like to know if I can access the path in the schema here? It's pretty easy to find the name of mutaiton/query with operation.operationName, but where can I get the name of the query/mutation as defined in the schema?
Solution
export function eddyApolloPlugin(): ApolloServerPlugin {
return {
requestDidStart(requestContext) {
// Set requestId on the header
const requestId = (requestContext?.context as EddyContext)?.requestId;
if (requestId) {
requestContext.response?.http?.headers.set('requestId', requestId);
}
return {
didResolveOperation(context) {
const operationDefinition = context.document
.definitions[0] as OperationDefinitionNode;
const fieldNode = operationDefinition?.selectionSet
.selections[0] as FieldNode;
const queryName = fieldNode?.name?.value;
// queryName is what I was looking for!
},
};
},
};
}
Your requirement is not very clear. If you want to get the name of the query/mutation to distinguish which query or mutation the client sends.
You could get the name from context.response.data in willSendResponse event handler.
E.g.
server.ts:
import { ApolloServer, gql } from 'apollo-server';
import { ApolloServerPlugin } from 'apollo-server-plugin-base';
import { parse, OperationDefinitionNode, FieldNode } from 'graphql';
function eddyApolloPlugin(): ApolloServerPlugin {
return {
requestDidStart(requestContext) {
return {
didResolveOperation(context) {
console.log('didResolveOperation');
const obj = parse(context.request.query!);
const operationDefinition = obj.definitions[0] as OperationDefinitionNode;
const selection = operationDefinition.selectionSet.selections[0] as FieldNode;
console.log('operationName: ', context.request.operationName);
console.log(`${context.operation!.operation} name:`, selection.name.value);
},
willSendResponse(context) {
console.log('willSendResponse');
console.log('operationName: ', context.request.operationName);
console.log(`${context.operation!.operation} name:`, Object.keys(context.response.data!)[0]);
},
};
},
};
}
const typeDefs = gql`
type Query {
hello: String
}
type Mutation {
update: String
}
`;
const resolvers = {
Query: {
hello() {
return 'Hello, World!';
},
},
Mutation: {
update() {
return 'success';
},
},
};
const server = new ApolloServer({ typeDefs, resolvers, plugins: [eddyApolloPlugin()] });
const port = 3000;
server.listen(port).then(({ url }) => console.log(`Server is ready at ${url}`));
GraphQL Query:
query test {
hello
}
the logs of the server:
didResolveOperation
operationName: test
query name: hello
willSendResponse
operationName: test
query name: hello
GraphQL Mutation:
mutation test {
update
}
the logs of the server:
didResolveOperation
operationName: test
mutation name: update
willSendResponse
operationName: test
mutation name: update

Apollo Client Introspective Queries

Works on the Playground...
I am trying to query the following enum values:
query {
__type(name:"ActivityType") {
enumValues {
name
}
}
}
When I test the query with the playground, it works. I receive a list of the enumeration values for the ActivityType:
Doesn't work with Apollo-Client...
When I run the following code with the client, I receive the expected results for the first query, but not for the second:
import ApolloClient, { gql } from 'apollo-boost'
const FIRST_QUERY = gql`
query successfulQuery {
totalActivities
}
`
const SECOND_QUERY = gql`
query unsuccessfulQuery {
__type(name:"ActivityType") {
enumValues {
name
}
}
}
`
const client = new ApolloClient({ uri: 'http://localhost:4000' })
//
// First Query returns data
//
client.query({ query: FIRST_QUERY })
.then(console.log)
.catch(console.error)
//
// Second Query does not return data
//
client.query({ query: SECOND_QUERY })
.then(console.log)
.catch(console.error)
The results
{ data: {...}, loading: false, networkStatus: 7, stale: false }
{ data: null, loading: false, networkStatus: 7, stale: false }
Is there something special that you have to implement with the client to allow introspective queries?

GraphQL how to mutate data

I have a basic schema for mutating some data which looks like
const schema = new graphql.GraphQLSchema({
mutation: new graphql.GraphQLObjectType({
name: 'Remove',
fields: {
removeUser: {
type: userType,
args: {
id: { type: graphql.GraphQLString }
},
resolve(_, args) {
const removedData = data[args.id];
delete data[args.id];
return removedData;
},
},
},
})
});
Looking around google I cant find a clear example of the example query which needs to be sent to mutate.
I have tried
POST -
localhost:3000/graphql?query={removeUser(id:"1"){id, name}}
This fails with error:
{
"errors": [
{
"message": "Cannot query field \"removeUser\" on type \"Query\".",
"locations": [
{
"line": 1,
"column": 2
}
]
}
]
}
In order to post requests from the front-end application it is recommended to use apollo-client package. Say i wanted to validate a user login information:
import gql from 'graphql-tag';
import ApolloClient, {createNetworkInterface} from 'apollo-client';
client = new ApolloClient({
networkInterface: createNetworkInterface('http://localhost:3000/graphql')
});
remove(){
client.mutate({
mutation: gql`
mutation remove(
$id: String!
) {
removeUser(
id: $id
){
id,
name
}
}
`,
variables: {
id: "1"
}
}).then((graphQLResult)=> {
const { errors, data } = graphQLResult;
if(!errors && data){
console.log('removed successfully ' + data.id + ' ' + data.name);
}else{
console.log('failed to remove');
}
})
}
More information about apollo-client can be found here
Have you tried using graphiql to query and mutate your schema?
If you'd like to create a POST request manually you might wanna try to struct it in the right form:
?query=mutation{removeUser(id:"1"){id, name}}
(Haven't tried POSTing myself, let me know if you succeeded, i structured this out of the url when using graphiql)
You have to explicitly label your mutation as such, i.e.
mutation {
removeUser(id: "1"){
id,
name
}
}
In GraphQL, if you leave out the mutation keyword, it's just a shorthand for sending a query, i.e. the execution engine will interpret it as
query {
removeUser(id: "1"){
id,
name
}
}
cf. Section 2.3 of the GraphQL Specification
const client = require("../common/gqlClient")();
const {
createContestParticipants,
} = require("../common/queriesAndMutations");
const gql = require("graphql-tag");
const createPartpantGql = async (predictObj) => {
try {
let resp = await client.mutate({
mutation: gql(createContestParticipants),
variables: {
input: {
...predictObj,
},
},
});
let contestParticipantResp = resp.data.createContestParticipants;
return {
success: true,
data: contestParticipantResp,
};
} catch (err) {
console.log(err.message)
console.error(`Error creating the contest`);
return {
success: false,
message: JSON.stringify(err.message),
};
}
};

Resources