What is GraphQL, its concepts with examples & limitations.
- A query language for your API.
- GraphQL gives the power to ask for exactly what we need and nothing more.
- Get as many as resources in a single request.
- Evolve your API's without versions.
- GraphQL makes it easy to build powerful tools like GraphiQL by leveraging your API’s type system.
- Queries & Mutations - GraphQL queries are so much easier to request data than a REST API.
- Schema & Types, Variables, Arguments - GraphQL has its own schema & type system which we are already familiar with (
String
,Int
,[]
etc.). - Resolver - is responsible for mapping the query to a function.
- Validation - By using the type system, it is easy to determine whether a GraphQL query is valid or not.
- Execution - After being validated, a GraphQL query is executed by a GraphQL server which returns a result that mirrors the shape of the requested query, typically as JSON.
- Introspection - It's often useful to ask a GraphQL schema for information about what queries it supports.
yarn or npm install
yarn or npm start
-
For local server open localhost:3000 in your browser.
- GraphQL.
- Express server.
- GraphQL HTTP Server Middleware.
- apollo-fetch for making fetch requests for demo.
Like any other programming language, GraphQL has variables
, arguments
. Lets see some examples.
The most basic components of a GraphQL schema are object types, which just represent a kind of object you can fetch from your service, and what fields it has. If you are a web developer, you can relate this with flow or typescript.
Example:
type Person {
name: String!
}
String!
-name
property is a non-nullable string. Meaning you will always give a value for this property.- More types.
We can pass arguments to any query.
Example:
query user {
getUser(id: 1) {
name
age
gender
picture
}
}
So far, we have been writing all of our arguments inside the query string. But in most applications, the arguments to fields will be dynamic.
Example:
variables:
{
"userId": 1
}
query:
query user($id: Int!) {
getUser(id: $id) {
name
age
gender
picture,
about
}
}
query helloworld {
hello
}
Result:
{
"data": {
"hello": "Hello World"
}
}
query getAllUsers {
getUsers {
name
age
gender
picture
}
}
Resolver getUsers:
const getUsers = args => {
const { gender } = args;
if (gender) return users.filter(user => user.gender === gender);
else return users;
};
Result:
{
"data":{
"users":[
{
"name":"Price Weber",
"age":37,
"gender":"male",
"picture":"http://placehold.it/32x32"
},
{
"name":"Pennington Parsons",
"age":22,
"gender":"male",
"picture":"http://placehold.it/32x32"
},
{
"name":"Yesenia Galloway",
"age":36,
"gender":"female",
"picture":"http://placehold.it/32x32"
}
]
}
}
query user {
getUser(id: 1) {
name
age
gender
picture
}
}
Resolver getUser:
export const getUser = args => {
const { id } = args;
const user = users.filter(user => user.id === id);
if (user.length === 1) return user[0];
else return `User not found for the id ${id}`;
};
Result:
{
"data":{
"user":{
"name":"Price Weber",
"age":37,
"gender":"male",
"picture":"http://placehold.it/32x32"
}
}
}
Most discussions of GraphQL focus on data fetching, but any complete data platform needs a way to modify server-side data as well. It is analogous to performing HTTP verbs such as POST
, PATCH
, and DELETE
. Just like queries, mutation should have mutation
instead of query
with some id or something.
Examples: open localhost:3000/graphql to try the below.
variables:
{
"name": "JEDI",
"age": 25,
"gender": "male"
}
mutation:
mutation user($name: String!, $age: Int!, $gender: String) {
createUser(name: $name, age: $age, gender: $gender) {
name
age
gender
}
}
Resolver for createUser:
const createUser = args => {
const { name, age, gender } = args;
const user = users.filter(user => user.name === name); // users from DB
if (user.length === 0) {
return user; // Save in DB and return
}
else return `A user with that name already exists.`;
};
Result:
{
"data":{
"createUser":{
"name":"JEDI",
"age":25,
"gender":"male"
}
}
}
variables:
{
"id": 1,
"name": "JEDI 🙃",
"age": 26
}
mutation:
mutation user($name: Int!, $name: String!) {
updateUser(name: $name, age: $age, gender: $gender) {
name
age
}
}
Resolver for updateUser:
const updateUser = args => {
const { id, name, age, gender } = args;
const user = users.filter(user => user.id === id);
if (user.length === 1) {
return user; // Save the updates in DB and return
}
else return `User doesn't exist for id ${id}.`;
};
Result:
{
"data":{
"updateUser":{
"name":"JEDI 🙃",
"age":25
}
}
}
variables:
{
"id": 1
}
mutation:
mutation user($id: Int!) {
deleteUser(id: $id) {
id
name
age
gender
}
}
Resolver deleteUser:
const deleteUser = args => {
const { id } = args;
const user = users.filter(user => user.id === id);
if (user.length === 1) {
return user; // Delete from DB and return user or return ok
}
else return `User doesn't exist for id ${id}.`;
};
Result:
{
"data":{
"deleteUser":{
"id":1,
"name":"Price Weber",
"age":37,
"gender":"male"
}
}
}
If are wondering how to write test cases for GraphQL. Here is an example for you starWarsValidation-test.js.
-
Specific Response Structure may required - In GraphQL the response matches the shape of the query, so if you need to respond in a very specific structure, you'll have to add a transformation layer to reshape the response.
-
Handling File Upload - There is nothing about file upload in the GraphQL specification and mutations doesn’t accept files in the arguments.
-
Cache at Network Level - Because of the commonly way GraphQL is used over HTTP (A POST in a single endpoint), cache at network level becomes hard. A way to solve it is to use Persisted Queries.
-
Rate Limiting - Limiting the API call's to particular query is problem in GraphQL. Github recently introducted GraphQL with different approach to solve this issue. Take a look here.
- Best practices for GraphQL - Serving over HTTP, Pagination, Caching etc.
- Running an Express GraphQL Server
- GraphQL vs REST.
- Apollo-Fetch - Handle all POST fetch calls as normal fetch API (See demo folder for more).
Thanks for reading so far 😙. Please do give a star for this repo if you liked it.