Building a Full-Stack GraphQL Application with Remix
Remix is a powerful React framework that focuses on server-side rendering, allowing applications to have fast load times and seamless client-side functionality. By leveraging technologies like Apollo GraphQL, developers can build robust, full-stack GraphQL applications with Remix. In this article, we’ll explore how to set up a Remix application with GraphQL functionality and implement simple CRUD operations using GraphQL server routes with Apollo.
What is Remix?
Remix is a full-stack web framework that prioritizes the user interface and delivers a fast, sleek, and resilient user experience. Built on top of React, Remix includes features like server-side rendering, TypeScript support, production server, and backend optimization.
Understanding Remix API Routes
In Remix, routes are their own APIs, allowing components to fetch data on the server side when a user requests a route. This approach differs from other frameworks like Next.js, where the client makes requests to API/server routes to perform CRUD operations.
Introduction to Apollo GraphQL
Apollo is a suite of tools for creating GraphQL servers and consuming GraphQL APIs. We’ll use Apollo’s Schema Link to perform GraphQL operations on a provided schema instead of making network calls to a GraphQL API.
Setting up a Remix Project
To create a new Remix project, run the following command in your terminal:
npx remix-create my-remix-app
Follow the prompts to set up your project.
Apollo GraphQL in Remix
Install the required packages:
npm install @apollo/client graphql-tag
Create a new file app/lib/apollo/index.ts
to configure your Apollo client:
“`typescript
import { ApolloClient } from ‘@apollo/client’;
import { makeExecutableSchema } from ‘graphql-tools’;
import { typeDefs } from ‘./schema’;
const graphQLClient = new ApolloClient({
schema: makeExecutableSchema({ typeDefs }),
});
“`
Setting up Utility Functions
Create a JSON file at app/data/books.json
to store your data. Create a new file app/utils/readWrite.ts
to set up utility functions for reading and writing to the JSON file:
“`typescript
import fs from ‘fs’;
import path from ‘path’;
const filePath = path.join(__dirname, ‘..’, ‘data’, ‘books.json’);
export const read = () => {
return JSON.parse(fs.readFileSync(filePath, ‘utf8’));
};
export const write = (data) => {
fs.writeFileSync(filePath, JSON.stringify(data));
};
“`
Running Queries
Create a new file app/routes/books.tsx
to define your query and execute it using the Apollo client:
“`typescript
import { useLoaderData } from ‘remix’;
import { graphQLClient } from ‘~/lib/apollo’;
const Books = () => {
const data = useLoaderData();
return (
Books
-
{data.books.map((book) => (
-
))}
);
};
export const loader = async () => {
const query =
;
query GetBooks {
books {
id
title
}
}
const result = await graphQLClient.query({ query });
return result.data;
};
“`
Setting up Mutations
Define your mutation and resolver in app/lib/apollo/schema.ts
:
“`typescript
import { gql } from ‘graphql-tag’;
const typeDefs = gql`
type Mutation {
addBook(book: BookInput!): [Book]
}
input BookInput {
title: String!
author: String!
}
`;
const resolvers = {
Mutation: {
addBook: async (parent, args) => {
const book = args.book;
const data = await read();
data.push(book);
await write(data);
return data;
},
},
};
typescript
Create a new file `app/routes/books/addbook.tsx` to define your mutation and execute it using the Apollo client:
import { useActionData } from ‘remix’;
import { graphQLClient } from ‘~/lib/apollo’;
const AddBook = () => {
const data = useActionData();
return (
Add Book
{data &&
Book added successfully!
}
);
};
export const action = async ({ request }) => {
const formData = await request.formData();
const title = formData.get(‘title’);
const author = formData.get(‘author’);
const query =
;
mutation AddBook($book: BookInput!) {
addBook(book: $book) {
id
title
}
}
const variables = { book: { title, author } };
const result = await graphQLClient.mutate({ query, variables });
return result.data;
};
“`
This is just the beginning of what you can achieve with Remix and GraphQL. You can also create a resource route in Remix to provide a GraphQL endpoint using Apollo Server.