GraphQL advanced concepts 💥💥

Introduction 🙋

Hi, this is my second blog about GraphQL (2020 Blogging challenge )

First ! Graphql subscriptions 💥💥:

While discovering GraphQL’s core concepts, I found out that if the client wants to fetch or send data to the server, there are queries and mutations that should be used, as for real-time messages and interactions there is “GraphQL subscriptions”.

Example Graphql subscriptions App design
subscription Message {
Message {
mutation
node {
id
createdAt
text
author
}
}
}

Validations in GraphQL🚩:

While adding or modifying data, it is important to validate user input.

  • Solution 1 with Resolvers :
  1. Define our schema.graphql
type Query {
greeting:String
}

type Mutation {
signUp(input:SignUpInput):String
}

input SignUpInput {
email:String!,
password:String!,
firstName:String!
}
const Mutation ={
signUp:(root,args,context,info) => {

const {email,firstName,password} = args.input;

const emailExpression = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;

const isValidEmail = emailExpression.test(String(email).toLowerCase())
if(!isValidEmail)
throw new Error("email not in proper format")

if(firstName.length > 15)
throw new Error("firstName should be less than 15 characters")

if(password.length < 8 )
throw new Error("password should be minimum 8 characters")

return "success";
}
}
module.exports = {Query,Mutation}
{
"input":{
"email": "abc@abc",
"firstName": "kannan",
"password": "pass@1234"
}
}
{
"data": {
"signUp": null
},

"errors": [
{
"message": "email not in proper format",
"locations": [
{
"line": 2,
"column": 4
}
],
"path": [
"signUp"
]
}
]
}
type SignUpInput {
email: String! @constraint(format: "email", maxLength: 255)
password: String! @constraint(maxLength: 255)
firstName: String! @constraint(pattern: "^[0-9a-zA-Z]*$", maxLength: 255)
lastName: String! @constraint(pattern: "^[0-9a-zA-Z]*$", maxLength: 255)
}

type Mutation {
signUp(input: SignUpInput!)
}

Authentication with GraphQL 🔓 🔏:

import { GraphQLServer } from 'graphql-yoga'
import * as jwt from 'jsonwebtoken'

const typeDefs = `type Query { hello(name: String): String! }`

const resolvers = {
Query: {
hello: (_, { name }) => `Hello ${name || 'World'}`,
},
}

const server = new GraphQLServer({ typeDefs, resolvers })
server.express.use((req, res, next) => {
const { authorization } = req.headers
jwt.verify(authorization, 'secret', (err, decodedToken) => {
if (err || !decodedToken) {
res.status(401).send('not authorized')
return
}
next()
})
})
server.start(() => console.log('Server is running on localhost:4000'))
context: ({ req }) => {
// get the user token from the headers
const token = req.headers.authorization || '';

// try to retrieve a user with the token
const user = getUser(token);

// optionally block the user
// we could also check user roles/permissions here
if (!user) throw new AuthenticationError('you must be logged in');

// add the user to the context
return { user };
},

Paginating and sorting with GraphQL 📃 📑:

  1. Define in our schema.graphql (add params `skip start index ` and `first the first x elements after a provided start index` to our query feed )
type Query {
info: String!
feed(filter: String, skip: Int, first: Int): [Link!]!
}
async function feed(parent, args, context, info) {
const where = args.filter ? {
OR: [
{ description_contains: args.filter },
{ url_contains: args.filter },
],
} : {}

const links = await context.prisma.links({
where,
skip: args.skip,
first: args.first
})
return links
}
query {
feed(
first: 1
skip: 1
) {
id
description
url
}
}

sorting:

With Graphql API Design, it is possible to return lists of elements that are sorted (ordered) according to specific criteria

  1. Add the following enum definition to schema.graphql:
enum LinkOrderByInput {
description_ASC
description_DESC
url_ASC
url_DESC
createdAt_ASC
createdAt_DESC
}
type Query {
info: String!
feed(filter: String, skip: Int, first: Int, orderBy: LinkOrderByInput): [Link!]!
}
async function feed(parent, args, context, info) {
const where = args.filter ? {
OR: [
{ description_contains: args.filter },
{ url_contains: args.filter },
],
} : {}

const links = await context.prisma.links({
where,
skip: args.skip,
first: args.first,
orderBy: args.orderBy
})
return links
}
query {
feed(orderBy: createdAt_ASC) {
id
description
url
}
}

Fragments, Interfaces, and Unions in GraphQL 📀 📼:

“Reducing the schema complexity”

Error handling with GraphQL 🚫 ❌ :

  1. Server problems (5xx HTTP codes, 1xxx WebSocket codes)
  2. Client problems e.g. rate-limited, unauthorized, etc. (4xx HTTP codes)
  3. The query is missing/malformed
  4. The query fails GraphQL internal validation (syntax, schema logic, etc.)
  5. The user-supplied variables or context is bad and the resolve/subscribe function intentionally throws an error (e.g. not allowed to view requested user)
  6. An uncaught developer error occurred inside the resolve/subscribe function (e.g. poorly written database query)
const {
ApolloServer,
gql,
AuthenticationError,} = require('apollo-server');

const typeDefs = gql`
type Query {
authenticationError: String
}
`;

const resolvers = {
Query: {
authenticationError: (parent, args, context) => { throw new AuthenticationError('must authenticate'); }, },
};
const {
ApolloServer,
UserInputError,
gql,
} = require('apollo-server');

const typeDefs = gql`
type Mutation {
userInputError(input: String): String
}
`;

const resolvers = {
Mutation: {
userInputError: (parent, args, context, info) => { if (args.input !== 'expected') { throw new UserInputError('Form Arguments invalid', { invalidArgs: Object.keys(args), }); } }, },
};

Batching in GraphQL 📟:

Caching in GraphQL 💲:

  • Client Caching: is the process of caching data in the client-side browser that helps to limit the data cost incurred by the user by keeping commonly referenced data locally. The client often requests data that may not be large but is indeed continuously needed
  • Network Caching: they intercept requests that look the same (based on various configurable criteria), returning a response early straight out of memory, instead of hitting the application serve
  • Application Caching: It can be implemented in the application with tools like Memcache, Redis, etc… one of the advantages for example if the remote server is not available due to a crash or network partitioning, the client can obtain a cached copy at the proxy. Hence, the robustness of the Web service is enhanced.

Technical solution: “DataLoader” 📘 📙

GraphQL tools :

And before ending this Blog, This a lits of useful tools that can help you as a GraphQl developer to speed up your work or to tets it perfectly

  1. GraphiQL — making GraphQL easier
  2. GraphQL Voyager : visualize your GraphQL
  3. GraphQL Docs : — auto-create your docs
  4. GraphQL IDE — the GraphQL playground
  5. Graphql-network: Chrome Devtool that provides a “network”-style tab for GraphQL requests to allow developers to debug more easily.
  6. Graphql-code-generator: GraphQL code generator with flexible support for custom plugins and templates
  7. swagger-to-graphql Swagger to GraphQL API adapter
  8. Prisma Modern DB toolkit to query, migrate and model your database

Conclusion :

For conclusion, GraphQL was one of the priority skills and technologies that I fixed to learn in 2020, I just started with core concepts, and discover the all whole ecosystem, in parallel, I’m trying to practice and implement some “POCS” by creating this repo: https://github.com/Rebaiahmed/Graphql-Learning

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Rebai Ahmed

Rebai Ahmed

<script>alert('try your best')</script>