In this project, we'll create a graphql back-end for an ecommerce site. Our goal will be to have a functioning cart that we can add items to, retrieve items from, edit quantities, and remove items from. In addition, we should be able to access products and specific products. If you need a reminder on structuring your mutations, queries, or other items, checkout the graphql-yoga documentation and the howtographql documentation.
Step 1
Summary
We'll start by setting up the skeleton for our GraphQL server. We'll start by creating the type definition for our Products and the Query type definition for retrieving all of our products.
Instructions
Add a new directory call schema to our server/ directory.
Next, add two files to our schema/ directory
A typeDefs.graphql file (Where we'll set our type definitions using GraphQL's Schema Definition Language)
A resolvers.js file (Where we'll write the code that will retrieve the data being requested)
Take a look at the server/models/products.js file
Notice the data we have available and what type that data is (Int, Boolean, String, Float, ID)
Navigate to our typeDefs.graphql file. Create a Product type that matches the structure of our product object. Each property should be marked as required
Next, create a Query Type
We'll use the Query Type to describe what we'll be querying for and what the return data should look like.
Add a property on our Query Type called products who's return value is an array of Products.
The array should always have at least one Product and should always be an array (denoted by the !)
Solution
typeDefs.graphql
type Product {
id: ID!
title: String!
color: String!
category: String!
price: Int!
}
type Query {
products: [Product!]!
}
Step 2
Summary
We now need to write a resolver, which is simply a function that aggregates data in some way, that satisfies the Product Query we defined previously. It should return an array of Products.
Instructions
Navigate to the resolver.js file
At the top of the file, require our products model from models/products.js and store it to a variable called products
Export an object with a single property of Query.
Query should be an object that defines each of the methods we'll use to query for data.
These methods will match the properties of the query types we defined in our typeDefs.graphql file.
We defined a single Query called products.
Add a matching resolver function on our Query object called products that returns our array of products.
In this step we'll setup our first GraphQL server along with the built in graphiql testing tool. We'll also make our first request to Query data from our graphql server.
Instructions
Navigate to the index.js file
Start by installing graphql-yoga from npm
Then, require and destructure GraphQLServer from graphql-yoga
Next, bring your typeDefs and resolver files into the index.
The resolver file can simply be required
Node does not know how to read .graphql files
We'll need to use the built in fs (file system) module's readFileSync property to read the file as utf8.
Set the output equal to a variable called typeDefs
Create an options object with port, endpoint, and playground properties
The port should be 3001
The endpoint should be /graphql This is used to send Queries and Mutations from the client to the server
The playground should be /graphiql This is our testing endpoint that enables and makes the graphiql interface viewable in the browser
Create your server
Declare a variable called server
Set server equal to a new GraphQLServer
Pass it a configuration object with your typeDefs and resolver as properties.
In addition, you can pass a context object that has access to the req object from express, but we won't be using it for this project. More on that here.
Start your server by invoking server.start
Pass it the options from above
Pass it a callback to log the port from the options object
Test!
Make sure your server is running, if not, debug!
Navigate to http://localhost:3001/graphiql
Explore your schema with the interactive docs on the right
Query for your products using the pane on the left
After you run your Query, you should see an array of products on the right pane
From here on out, any time your Schema changes, you'll need to refresh your browser so it has the latest version of your Schema
Solution
index.js
const { readFileSync } = require('fs');
const { GraphQLServer } = require('graphql-yoga');
const typeDefs = readFileSync(`${__dirname}/schema/typeDefs.graphql`, 'utf8');
const resolvers = require('./schema/resolvers');
const options = {
port: 3001,
endpoint: '/graphql',
playground: '/graphiql'
};
const server = new GraphQLServer({
typeDefs,
resolvers,
// optional context function that accessesg the req object from express
context: req => ({
...req.request
})
});
server.start(options, () =>
console.log(`Server is running on localhost:${options.port}`)
);
Graphiql Interface
{
products {
id
title
category
price
color
}
}
Step 4
Summary
Now that our server is running, let's create a Query that will allow us to retrieve data on a single Product instead of all of our Products.
Instructions
Navigate to the typeDefs.graphql file
Add a property to our Query type called product
It should expect an id as an argument and optionally return a Product
Next, navigate to resolvers.js
Add a resolver on our Query called product
resolver functions receive 3 arguments
parent (usually denoted by an _ because we won't be using it)
args (an object with any arguments, such as id, that are received by the Query or Mutation)
context (if we're using it)
product should return a product if one matches the passed in id on the arguments objects, or throw an error if there is no matching product
Test in graphiql
Solution
resolvers.js
let products = require('../models/products');
const resolvers = {
Query: {
products() {
return products;
},
// The second argument is our `arguments` object. It references the passed in arguements for your Query. Here we're destructuring the id, but you could reference it as `args.id`
product(_, { id }) {
const item = products.find(val => val.id === +id);
if (!item) {
throw new Error(`No Product With ID: ${id}`)
}
return products.find(val => val.id === +id);
}
}
}
type Product {
id: ID!
title: String!
color: String!
category: String!
price: Int!
quantity: Int
}
type Query {
products: [Product!]!
product(id: ID!): Product
cart: [Product]!
}
Step 6
Summary
Now that we have several ways to Query for data, we'll work on adding methods for updating, deleting, and posting data, otherwise called Muatations in GraphQL.
Instructions
Navigate to the typeDefs.graphql file
Here we'll add a type called Mutation
Mutation should have 3 properties
addProductToCart
Expects an id argument of type ID (this will reference an item in our products to be added to cart)
Should expect a return value of an array that may or may not be empty or have Product. (This will be our updated cart we're returning)
removeProductFromCart
Expects an id argument of type ID
Should expect a required return value of an ID (We send this back to tell the UI what item was removed)
updateQuantity
Expects an id argument of type ID and a change argument of type String (change will be either up or down to increase or decrease the quantity)
The following is optional. There are currently no instructions for client setup.
Integrate one or several of your features using the Apollo Client for React. create-react-app has already been run for you. You'll need to install the Apollo dependencies (graphql, apollo-boost, react-apollo), setup the Apollo Client, and setup the Apollo Provider to get started.
For a refresher, checkout the Apollo Graphql getting started section here. This will walk you through what you need to install and how to get all the pieces setup.
Be imaginative, or build a vanilla ecommerce frontend, it's up to you!
Contributions
If you see a problem or a typo, please fork, make the necessary changes, and create a pull request so we can review your changes and merge them into the master repo and branch.
请发表评论