Fullstack Apollo+React GraphQL setup

  • We were going to have a mobile and web applications which consume the same API in slightly different ways
  • We needed some built-in frontend caching
  • The data that we were going to work with was pretty complex and hard for the client to consume
  • Automatic TypeScript types generation for the frontend was a requirement

Initial setup

React

import { ApolloProvider } from '@apollo/client/react';
import { ApolloClient, ApolloLink, createHttpLink, InMemoryCache } from '@apollo/client';
const cache = new InMemoryCache();

const httpLink = createHttpLink({
uri: http://localhost:4000,
});
const client = new ApolloClient({
link: ApolloLink.from([httpLink]),
cache,
});
const App = () => {
return (
<ApolloProvider client={client}>
<Routes />
</ApolloProvider>
)
}
  • Authentication
  • Error handling
  • Cache configuration
  • Local variables

GraphQL server

  • Datasources (REST)
  • Schema
  • Resolvers
import { ApolloServer } from "apollo-server";
import {
ApolloServerPluginLandingPageDisabled,
ApolloServerPluginLandingPageGraphQLPlayground,
} from "apollo-server-core";
import depthLimit from "graphql-depth-limit";
import typeDefs from "./schemas";
import resolvers from "./resolvers";
import dataSources from "./datasources";
console.log(`🔥 process.env.NODE_ENV: ${process.env.NODE_ENV}`);
if (process.env.NODE_ENV === "development") {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
}
const isProduction = () => {
return process.env.NODE_ENV === "production";
};
const server = new ApolloServer({
debug: true,
typeDefs,
resolvers,
dataSources,
context: async ({ req }) => {
return { req };
},
validationRules: [depthLimit(5)],
introspection: isProduction() ? false : true,
formatError: (err) => {
err.message = err?.extensions?.response?.body?.title || err.message;
return err;
},
plugins: [
isProduction()
? ApolloServerPluginLandingPageDisabled()
: ApolloServerPluginLandingPageGraphQLPlayground(),
],
});
server.listen({ port: process.env.PORT || 4000 }).then((listenResponse) => {
console.log(`🚀 Server is running at ${listenResponse.url}`);
});

Datasources

import { DataSources } from "apollo-server-core/dist/graphqlOptions";
import TodoApi from "./TodoApi";
export interface IDataSources {
todoApi: ITodoAPI;
}
const dataSources = (): DataSources<IDataSources> => {
return {
todoApi new TodoApi(),
};
};
export default dataSources;
import { ITodoApi } from "../types/todoTypes";
import BaseRestDataSource from "./BaseRestDataSource";
class SearchApi extends BaseRestDataSource implements ITodoApi {
constructor() {
super();
this.baseURL = // Your REST service url here
}
todos() {
return this.get("Todo");
}
}
export default TodoApi;
export interface ITodoApi {
todos(): Promise<Todo>;
}

interface Todo {
id: number;
name: string;
}

Schema (type definitions)

import { gql } from "apollo-server";
import todoDefs from "./todoDefs";
const baseTypeDefs = gql`
type Query
type Mutation
`;
const schemas = [
todoDefs,
];
export default schemas;
import { gql } from "apollo-server";const todoTypeDefs = gql`
extend type Query {
todos: Todo
}
type Todo {
id: Int!
name: String!
}
`;
export default todoTypeDefs;

Resolvers

import GraphQLJSON from "graphql-type-json";
import merge from "lodash/merge";
import todoResolvers from "./todoResolvers";
export default merge(
{},
todoResolvers,
);
import { IDataSources } from "../types";interface IAppContext {
dataSources: IDataSources;
}
const queryResolvers = {
todos: (
// unused in this case
parent: unknown,
// no parameter provided to this query
parameters: unknown,
// the REST datasources we can use to make API calls
{ dataSources }: IAppContext
) => {
return dataSources.todoApi.todos();
},
};
export default {
Query: queryResolvers,
};
  1. Parent 👨 is available if you are trying to access child 👶 of a parent (nested data). e.g:
todos {
properties {
propertyName
propertyValue
}
}
Photo by Kelly Sikkema on Unsplash

--

--

--

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

The most popular Open-source GraphQL Servers and Clients

Amazon CloneTutorial-Part 1

Thinking in React: the thought process behind creating a new React app

The Fibonacci Sequence to the nᵗʰ number (Python & JavaScript)

Vue + Typescript = 🔥

React Hooks Tutorial on Developing a Custom Hook for Data Fetching

Automated CI/CD of a Monorepo with Lerna

Visualizing Neo4j Database Contents Like a Pro!

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
Mindaugas Nakrosis

Mindaugas Nakrosis

More from Medium

Dockerize MERN Full Stack App Part 1(Node.js and MongoDB)

How to solve argon2 install error when using NPM?

Create massive random data using faker.js

Week of Java: Part 1 - Setting Up the Project