Setting up Relay Modern on frontend
Hello, for such long break I’m back to the Django, React & Relay tutorial! Today I will show you how to setup Relay on the frontend to work with Django. Let’s get started!
Preparing Django
Schema
First thing is to somehow tell Relay what is the structure of data in the backend. It is done via schema.
The schema describes all the queries, mutations and data structures of GraphQL application. To generate one
I add following line to Makefile
:
.PHONY: generate-schema
generate-schema:
docker-compose run film_api python manage.py graphql_schema --indent 2
mv film_api/schema.json film_ui/schema.json
I’m using here command (graphql_schema
) provided by django graphene. Indent option in for a
sake of better readability of generated schema which looks like:
{
"data": {
"__schema": {
"queryType": {
"name": "Query"
},
"mutationType": {
"name": "Mutation"
},
"subscriptionType": null,
"types": [
{
"kind": "OBJECT",
"name": "Query",
"description": null,
"fields": [
{
"name": "actor",
"description": "The ID of the object",
"args": [
{
"name": "id",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
},
"defaultValue": null
}
],
# rest of the schema
CORS
As I got schema, next thing is to allow Relay to connect to Django GraphQL backend. For this, I need
to setup CORS. It allows request coming
from 127.0.0.1:3000
(which I will be serving my ui app in dev mode) to be received by Django.
Adding CORS to django is simple. First I have to install a package called django-cors-headers.
Then I setup it as instructions from their tutorial goes.
One custom thing I add was CORS_ORIGIN_WHITELIST
setting which I set as:
CORS_ORIGIN_WHITELIST = ('localhost:3000', '127.0.0.1:3000')
This is all for Django part - next comes JavaScript part
Preparing UI App
Relay dev dependencies
As I’m using create-react-app I have the whole
configuration done for me but to use Relay I need to eject.
It’s simple as running: npm run eject
. As I got my whole configuration done I need to install a couple
of relay packages:
npm install --save react-relay
npm install --save -dev babel-plugin-relay relay-compiler
Let’s look first how to setup dev dependencies. To allow relay generate and execute schema I needed
to add babel plugin & present to babel config in package.json
(order is important here):
"babel": {
"plugins": ["relay"],
"presets": ["react-app"]
},
Then I added following script to the package.json
:
"relay": "relay-compiler --src ./src/components/ --schema ./schema.json --extensions jsx"
It tells the compiler to generate files that will be used then by Relay to make queries. Important here
are schema
flag which points to schema location and extensions
as by default relay compiler
recognizes only .js
files.
Setting up Relay
I have my dev dependencies done - right now I can setup Relay! First I need Environment.js
:
import { Environment, Network, RecordSource, Store } from "relay-runtime";
const store = new Store(new RecordSource());
const network = Network.create((operation, variables) => {
return fetch("http://127.0.0.1:8000/graphql/", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({
query: operation.text,
variables,
}),
}).then((response) => {
return response.json();
});
});
const environment = new Environment({
network,
store,
});
export default environment;
Going from the top - I create a store for my Relay data, then I create a network
where I submit
the address of graphql
instance - In my case where Django Graphene listens to. The rest of the code in
network
function is JSON handling. At the end of the file I export environment
so I can use
it in my App.jsx
:
import { QueryRenderer, graphql } from "react-relay";
import environment from "../Environment";
const FilmListQuery = graphql`
query AppQuery {
films {
id
title
}
}
`;
class App extends Component {
render() {
return (
<QueryRenderer
environment={environment}
query={FilmListQuery}
render={({ error, props }) => {
if (error) {
return <div>{error.message}</div>;
} else if (props) {
return <FilmList films={props.films} />;
}
return <div>Loading</div>;
}}
/>
);
}
}
export default App;
What is happening here? FilmListQuery
is the simplest query of all - I fetch the id and title
of the film - I can take this string and execute in on 127.0.0.1:8000/graphql
and the result will
be a list of films with title and ids. In QueryRenderer
component I specify the previously created
environment
, query
and handling of errors. If there is no error and I got a data I render FilmList
.
I’ve got a basic version of my application! I can right now get data from Django using Relay! That’s all for today and stay tuned for next part!
Repo with code can be found on github.