Unlock GraphQL's full Potential for Frontend
@vilvaathibanpb
What does GraphQL solve
- Better Client Experience
- One API for all
- Fix over/under fetching
- No version hell
- Work with exisiting systems
Auto Docs and Playground
Code generation
# schema.graphql
type Query {
getUser(id: ID!): User
}
type User {
id: ID!
name: String!
}
# queries.graphql
query GetUser($id: ID!) {
getUser(id: $id) {
id
name
}
}
Code generation
overwrite: true
schema: schema.graphql
documents: "src/**/*.graphql"
src/generated/react-hooks.tsx:
plugins:
- "typescript"
- "typescript-react-apollo"
Code generation
overwrite: true
schema: schema.graphql
documents: "src/**/*.graphql"
generates:
src/generated/types.ts:
plugins:
- "typescript"
src/generated/react-hooks.tsx:
plugins:
- "typescript"
- "typescript-react-apollo"
Code generation
import React from 'react';
import { useGetUserQuery } from '../generated/react-hooks';
const UserProfile = ({ userId }) => {
const { data, loading, error } = useGetUserQuery({
variables: { id: userId },
});
if (loading) {
return <div>Loading...</div>;
}
if (error) {
return <div>Error: {error.message}</div>;
}
const user = data?.getUser;
return (
<div>
<h2>User Profile</h2>
<p>Name: {user?.name}</p>
</div>
);
};
export default UserProfile;
Automatic update of data on write
// schema.graphql
type Todo {
id: ID!
text: String!
completed: Boolean!
}
type Query {
todos: [Todo]!
}
type Mutation {
createTodo(text: String!): Todo!
}
Automatic update of data on write
const [createTodo] = useMutation(CREATE_TODO, {
// Refetch the GET_TODOS query after the mutation
refetchQueries: [{ query: GET_TODOS }],
});
Cache Policy
- Cache-first
- Cache-only
- Network-only
- Cache-and-Network
- No-cache
Cache-first
import { useQuery } from "@apollo/client";
const { loading, error, data } = useQuery(GET_TODOS, {
fetchPolicy: "cache-first",
});
Cache-only
import { useQuery } from "@apollo/client";
const { loading, error, data } = useQuery(GET_TODOS, {
fetchPolicy: "cache-only",
});
Network-only
import { useQuery } from "@apollo/client";
const { loading, error, data } = useQuery(GET_TODOS, {
fetchPolicy: "network-only",
});
Cache-and-network
import { useQuery } from "@apollo/client";
const { loading, error, data } = useQuery(GET_TODOS, {
fetchPolicy: "cache-and-network",
});
No Cache
import { useQuery } from "@apollo/client";
const { loading, error, data } = useQuery(GET_TODOS, {
fetchPolicy: "no-cache",
});
Out of the box - Pagination
const { loading, error, data, fetchMore } = useQuery(GET_ITEMS, {
variables: { limit: 10, offset: 0 }, // Initial values for pagination
});
export const GET_ITEMS = gql`
query GetItems($limit: Int!, $offset: Int!) {
items(limit: $limit, offset: $offset) {
id
name
description
}
}
`;
Optimistic UI
const optimisticTodo = {
id: 'temp-id-' + Date.now(), // Use a temporary ID
text,
completed: false, // Assuming new todos are initially incomplete
};
type Mutation {
createTodo(input: TodoInput!): Todo!
}
input TodoInput {
text: String!
completed: Boolean
}
type Todo {
id: ID!
text: String!
completed: Boolean!
}
Optimistic UI
createTodo({
variables: { input: optimisticTodo },
optimisticResponse: {
__typename: 'Mutation',
createTodo: optimisticTodo,
},
update: (cache, { data: { createTodo } }) => {
// Update the cache with the real data when the response is received
cache.modify({
fields: {
todos(existingTodos = []) {
const newTodoRef = cache.writeFragment({
data: createTodo,
fragment: gql`
fragment NewTodo on Todo {
id
text
completed
}
`,
});
return [...existingTodos, newTodoRef];
},
},
});
},
});
Magic of CacheĀ
Other benefits
- Out of the box Cache persist and sharing
- Local state management
Designing better Queries
Better purpose
type Query {
getUser(id: ID, email: String): User
}
type User {
id: ID!
username: String!
email: String!
// Other user fields
}
type Query {
getUserByID(id: ID!): User
getUserByEmail(email: String!): User
}
type User {
id: ID!
username: String!
email: String!
// Other user fields
}
Better Types - Custom Scalars
input EventInput {
name: String!
date: String!
}
input EventInput {
name: String!
date: Date!
}
Better Types - Enums
type User {
id: ID!
username: String!
email: String!
role: String!
}
enum UserRole {
USER
ADMIN
MODERATOR
GUEST
}
type User {
id: ID!
username: String!
email: String!
role: UserRole!
}
Over Exposing
type User {
id: ID!
username: String!
email: String!
role: String!
bank_acc_no: String
personal_email_id: String
}
Other Backend Tips
- Federation
- Schema linting
- Schema Design
- Security
Thank You
@vilvaathibanpb
Unlock full Potential of GraphQL for Front
By Vilva Athiban
Unlock full Potential of GraphQL for Front
- 130