I am trying to use graphql for one of the GET request based on an id. Here's the code:
const { graphql, buildSchema } = require('graphql');
EmployeeService.prototype.getEmployee = function() {
// Construct a schema
const schema = buildSchema(`
type Query {
employee(id="12345") {
id
items {
id
name
}
}
}
`);
// The root provides a resolver function
let root = {
employee: () => id
};
// Run the GraphQL query
graphql(schema, '{ employee }', root).then((response) => {
console.log(response);
});
};
Trying to follow the documentation on http://graphql.org/graphql-js/.
I get a GraphQL error: "Syntax Error GraphQL request (3:19) Expected :, found =↵↵2: type Query {↵3: employee (id="12345") {↵ ^↵4: id↵"
Please advise.
You are maybe mixing things a little bit up. The schema and resolvers are part of your API and are not needed to make a query on a client. Just for demonstration purposes here a valid schema definition (that would normally run on a API server):
let schema = buildSchema(`
type Item {
id: Int!
name: String!
}
type Employee {
id: Int!
items: [Item]
}
type Query {
employee(id: Int!): Employee
}
`);
You then define your types and resolvers (simplified examples):
class Employee {
constructor(id, items) {
this.id = id;
this.items = items;
}
}
let root = {
employee: ({id}) => {
return new Employee(id, [{id: 1, name: 'Item 1'}, {id: 2, name: 'Item2'}]);
}
};
You can then run a query:
const query = `
{
employee(id: 1) {
id,
items {
id,
name
}
}
}
`;
graphql(schema, query, root).then((response) => {
console.log(response.data);
});
To run actual queries against a remote API have a look at GraphQL clients like Apollo or lokka
Related
The result of the mutation should update the data without an unnecessary request to the server, I do not understand what needs to be corrected so that the data is not fetched twice, but taken from the cache.
const [createEvent, { loading }] = useMutation(CREATE_GOOD_MUTATION, {
variables: values,
update(proxy, result) {
// TODO: remove goods from cache
const data = proxy.readQuery({
query: FETCH_ITEMS_QUERY,
});
let newData = [...data.events];
newData = [result.data.events, ...newData];
proxy.writeQuery({
query: FETCH_ITEMS_QUERY,
data: {
...data,
events: {
newData,
},
},
});
},
// refetchQueries: [
// {
// query: FETCH_ITEMS_QUERY,
// },
// ],
onError(err) {
setErrors(err.message);
},
});
enter image description here
Mutation to create a new good:
CREATE_GOOD_MUTATION = gql`
mutation createEvent(
$title: String!
$description: String!
$price: String!
$autor: String!
$pageNumber: String!
$publishYear: String!
) {
createEvent(
eventInput: {
title: $title
description: $description
price: $price
autor: $autor
pageNumber: $pageNumber
publishYear: $publishYear
}
) {
title
description
price
}
}
`;
Query to display all products:
FETCH_ITEMS_QUERY = gql`
query events {
events {
id
title
description
price
}
}
`;
I need to fetch it once, when I try to create a new good by mutation and display all products from the cache, without an additional request.
You should use proxy.modify instead of proxy.readQuery/proxy.writeQuery.
Using cache.modify
Making cache updates with mutation.update function
Try to change your mutation update function to something like this:
update(proxy, result) {
proxy.modify({
fields: {
events(existingEvents = []) {
return [...existingEvents, result.data.createEvent];
}
}
})
},
I'd like to retrieve the _id of a document in my mongodb database using a graphql query.
Here is my query:
query {
getTeamRegistrationID(teamName:"Patriots") {
_id
}
}
And the result:
{
"data": {
"getTeamRegistrationID": []
}
}
This should return the ObjectID of the document from the mongodb database.
Here's my graphql schema:
const typeDefs = gql`
type TeamRegistration {
_id: ID,
teamName: String
},
type Query {
getTeamRegistrationID(teamName: String): [TeamRegistration]
}`
My resolver:
const resolvers = {
Query: {
getTeamRegistrationID: (parent, teamRegistration) => TeamRegistration.find({ teamName: teamRegistration.teamName })
}
}
I can't figure out what I'm doing wrong here. Is there something I'm missing? Thanks in advance!
Sorry for the long post, but I tried to be as detailed as possible.
How can I edit my current model, schema, and resolver to be able to save/connect a related type (Vendor) to my created type (Item) via a web form?
I want to create an inventory item and select a vendor to be associated with that item.
I have a Prisma data model like so (I've other fields for simplicity because I have no trouble saving the other fields; it's just with other types where there is a relation)...
Items may or may not have a vendor associated with them. Vendors may or may not have a list of items currently associated with them.
type Item {
id: ID! #id
name: String!
description: String!
vendor: Vendor
}
type Vendor {
id: ID! #id
items: [Item!]
}
I have a graphql schema like this (compare to modified schema at the end of this question)...
type Mutation {
createItem(
name: String!
description: String!
): Item!
}
My resolver:
async createItem(parent, args, ctx, info) {
const item = await ctx.db.mutation.createItem(
{
data: {
...args,
},
}, info);
return item;
}
My React component contains the following:
const CREATE_ITEM_MUTATION = gql`
mutation CREATE_ITEM_MUTATION(
$name: String!
$description: String!
) {
createItem(
name: $name
description: $description
) {
id
name
description
vendor {
id
}
}
}
`;
const ALL_VENDORS_QUERY = gql`
query ALL_VENDORS_QUERY {
vendors {
id
}
}
`;
Later on down the web page in my HTML form, I have:
<Query query={ALL_VENDORS_QUERY}>
{({ data, loading }) => (
<select
id="vendor"
name="vendor"
onChange={this.handleChange}
value={this.state.vendor}
>
<option>Vendor</option>
{data.vendors.map(vendor => (
<option key={vendor.id} value={vendor.id}>{vendor.name}</option>
))}
</select>
)}
</Query>
I just don't know how to connect the vendor to the item through a form submission. I can get it working if I hard code the vendor id in my resolver like so:
async createItem(parent, args, ctx, info) {
const item = await ctx.db.mutation.createItem(
{
data: {
vendor: {
connect: { id: "ck7zmwfoxg4b70934wx8kgwkx" } // <-- need to dynamically populate this based on user input from the form
},
...args,
},
}, info);
return item;
}
...but that obviously is not what I want.
To me, it makes the most sense to modify my schema like so:
createItem(
name: String!
description: String!
vendor: Vendor <--- added
): Item!
But when I do that I get this:
Error: The type of Mutation.createItem(vendor:) must be Input Type but got: Vendor.
How can I edit my current model, schema, and resolver to be able to save/connect a vendor ID that is selected on the form?
The answer to my problem was found here: How to fix 'Variable "$_v0_data" got invalid value' caused from data types relation - Mutation Resolver
I was spreading the args (...args) while also passing the vendor argument.
Here is my updated mutation:
createItem(
name: String!
description: String!
vendorId: ID
): Item!
and its resolver:
async createItem(parent, {name, description, vendorId}, ctx, info) {
const item = await ctx.db.mutation.createItem(
{
data: {
vendor: {
connect: { id: vendorId }
},
name,
description,
},
}, info);
return item;
}
Boom! 💥
RedwoodJS automatically maps GraphQL queries resolvers to api/src/services. How do I create a field resolver for a given GraphQL type?
Suppose I have this schema:
type Person {
name: string!
birthDate: DateTime!
age: Int!
}
But only name and birthDate are stored in the database.
Using graphql-tools I would write my resolvers like this:
const resolvers = {
Query: { ... },
Mutation: { ... },
Person: {
age(person) {
return new Date().getFullYear() - person.birthDate.getFullYear();
},
},
};
PS: I know the age formula is wrong.
PS2: I'm using age here for the sake of simplicity, imagine this is expensive to compute or get from database.
It's almost identical to the way you do it with graphql-tools.
You export an object with the same name as your type in your service:
// services/person.js
export const Person = {
age: (_args, { root }) {
return new Date().getFullYear() - root.birthDate.getFullYear();
},
}
As an aside, you could also export a resolvers in the person.sdl.js file (But services take precendence):
// graphql/person.sdl.js
export const schema = gql`/* ... */`
export const resolvers = {
Query: {},
Mutation: {},
Person: {},
}
Edit: I misunderstood the question, this answer just covers creating query + mutation resolvers, not a resolver for a computed field.
To create a field resolver, you'll need to decide whether you're creating a resolver for a query, or a handler for a mutation.
We can use the following schema as an example:
export const schema = gql`
type Person {
id: String!
name: String!
age: Int!
}
type PersonInput {
name: String
age: Int
}
type Mutation {
createPerson(input: PersonInput!): Person
}
type Query {
people: [Person]
person(id: String!): Person
}
`
If the above schema is stored in a file called persons.sdl.js, in the api/src/graphql directory, you can implement the queries and mutations in a file called persons.js in the api/src/services/persons directory.
// implements Mutation.createPerson(...)
export const createPerson({ input }) => {
return db.person.create({
data: input
})
}
// implements Query.people
export const people = () => {
return db.person.findMany()
}
// implements Query.person(...)
export const person = ({ id }) => {
return db.person.findOne({
where: { id }
})
}
I am building an application with React, Apollo and Prsima that allows users to filter cars by model, brand, price... I know (for example) how to filter cars by brand:
const GET_CARS = gql`
query FilterCars($brandId: ID){
cars(where: {
model : { brand: { id: $brandId } }
}) {
id
model {
name
brand {
name
}
horses
}
year
km
price
...
}
`;
And in the component:
const CarList = (props) => {
const { data, loading, error } = useQuery(GET_CARS, {
variables: {
brandId: "exampleBrandId"
}
})
...
}
The problem is, that some parameters are optional: maybe the user does not care about the brand, or the model, or the price... So then all cars should appear: If no brand is selected, cars of all brands should appear; If no price is selected, cars of all prices should appear...
How can I do that? Something like:
query FilterCars($brandId: ID){
cars(where: {
model : { brand: { id: $brandId || all_brand_ids } }
}) {
...
}
}
I have investigated a and found a possible solution, but the custom input that the post refers to is not generated in my prisma.
getCars(parent, args, {prisma}, info){
const queryArgs ={}
if(args.brandId){
queryArgs ={
where: {
model: {
id: args.brandId
}
}
}
}
if(args.price){
queryArgs={
...queryArgs,
where: {
...queryArgs.where
//What every you want to add
}
}
}
return prisma.query.cars(queryArgs, info)
}
You can check on the Backend your args. And create a flexible obj to query for...
The answer from #Toiz is feasible. However, what if the number of parameters increases so that multiple if-statements are needed?
I suggest using undefined.
As mentioned in prisma official docs here, you can use undefined to optioanally exclude a field from query.
For example,
where: {
model : {
brand: {
id: $brandId != null ? $brandId : undefined
}
}
}
const GET_CARS = gql`
query FilterCars($brandId: ID){
cars(where: {
model : { brand: { id: $brandId } }
}) {
id
model {
name
brand {
name
}
horses
}
year
km
price
}
`;
const CarList = (props) => {
const { data, loading, error } = useQuery(GET_CARS, {
variables: {
brandId: "exampleBrandId"
}
})
}
brandId: "exampleBrandId" - this should be dynamic, and one of the options could be something like "All Brands", which would then query all brands.