Create End to End Application using React, Relay, GraphQL, Rejoiner and gRPC

We are going to create a stack where:

  • Microservices are communicating using gRPC using protobuf for serializing-deserializing
  • Frontend is consuming APIs through graphQL
  • React is used to render UI

Step 1: gRPC Service

You need a gRPC server running for the tutorial. If you don’t have one of your own, you can use the one here. This will run a basic gRPC server at 8089 port.

We will cover how to make your own gRPC server in some other tutorial.

Step 2: GraphQL Server

Now, we need to consume the gRPC service to expose the methods through the graphQL. We have used rejoiner.io for the purpose. For the purpose of this tutorial, you can use the graphQL server provided here.

Step 3: React UI

  1. Install yarn. Yarn is a dependency management system. We are going to use yarn for our project
brew install yarn

2. Install react-relay

yarn add react react-dom react-relay

3. Install relay-config

yarn add --dev relay-config

4. Install babel-plugin-relay

yarn add --dev babel-plugin-relay graphql

5. Install relay-compiler

yarn add --dev relay-compiler

6. Install tailwind for css purpose

npm install tailwindcss

7. Create a react application using yarn

yarn create react-app relay-example

Here relay-example is the name of my project. You can have any name of your choice.

8. Now you can see a folder called relay-example. Change directory to relay-example

cd relay-example

9. Make a file with the name relay.config.js and paste following code in the file:

module.exports = {
// …
// Configuration options accepted by the `relay-compiler` command-line tool and `babel-plugin-relay`.
src: "./src",
schema: "./data/schema.graphql",
exclude: ["**/node_modules/**", "**/__mocks__/**", "**/__generated__/**"],
}
view raw relay.config.js hosted with ❤ by GitHub

10. Make a file called “.babelrc”. Add the following code in the file

{
  "plugins": [
    "relay"
  ]
}

11. Paste the following detail in package.json

{
"name": "relay-example",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-relay": "^10.0.1",
"react-scripts": "3.4.1",
"tailwindcss": "^1.6.2"
},
"scripts": {
"build:tailwind": "tailwindcss build src/tailwind.css -o src/tailwind.output.css",
"prestart": "npm run build:tailwind",
"prebuild": "npm run build:tailwind",
"relay": "relay-compiler –src ./src –schema ./schema.graphql –extensions js jsx",
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"babel-plugin-relay": "^10.0.1",
"graphql": "^15.3.0",
"relay-compiler": "^10.0.1",
"relay-config": "^10.0.1"
}
}
view raw package.json hosted with ❤ by GitHub

11. Relay Environment

Make a file called RelayEnvironment.js in src folder and paste the following detail

import {
Environment,
Network,
RecordSource,
Store,
} from 'relay-runtime';
function fetchQuery(
operation,
variables,
) {
return fetch('http://localhost:8080/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
query: operation.text,
variables,
}),
}).then(response => {
return response.json();
});
}
const environment = new Environment({
network: Network.create(fetchQuery),
store: new Store(new RecordSource()),
});
export default environment;
view raw RelayEnvironment.js hosted with ❤ by GitHub

12. Get your graphQL schema file. Do this in home folder(i.e. in relay-example)

npm install -g get-graphql-schema
get-graphql-schema http://localhost:8080/graphql > schema.graphql

13. App.js

import React from 'react';
import { QueryRenderer } from 'react-relay';
import environment from './RelayEnvironment'
import graphql from 'babel-plugin-relay/macro';
import './tailwind.output.css';
export default class App extends React.Component {
//this.state = {farmCropId:1}
constructor(props) {
super(props)
this.state = { farmCropId: 1 }
}
onFarmCropIdChange = (event) => {
console.log(event.target.value)
this.setState({ farmCropId: event.target.value })
}
render() {
const farmCropId = this.state.farmCropId
console.log('Props', this.props)
return (
<div>
<div className="max-w-md mx-auto flex p-6 bg-gray-100 mt-10 rounded-lg shadow-xl">
<label class="block text-gray-700 text-sm font-bold mb-2" for="farmCropId">
Farm Crop Id
</label>
<input class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" type="text" value={farmCropId} onChange={this.onFarmCropIdChange} />
</div>
<QueryRenderer
environment={environment}
query={graphql`
query AppQuery($farmCropId: Int) {
bookings(input: {farmCropId: $farmCropId}){
bookings {
bookingId
machines{
location
}
}
}
}
`}
variables={{ farmCropId }}
render={({ error, props }) => {
console.log('Error', error, 'Props', props)
if (error) {
return <div>Error!</div>;
}
if (!props) {
return <div>Loading…</div>;
}
return <div className="max-w-md mx-auto flex p-6 bg-gray-100 mt-10 rounded-lg shadow-xl">
<div className="ml-6 pt-1">
<h1 className="text-2xl text-blue-700 leading-tight">
Booking Information:
</h1>
{props.bookings.bookings.map((booking) => {
return (
<div className="max-w-md mx-auto flex p-6 bg-gray-100 mt-10 rounded-lg shadow-xl" key={`booking-${booking.bookingId}`}>
<label>Booking Id: {booking.bookingId}</label>
<br />
<label>Machine Location Id: {booking.machines.location}</label>
</div>
)
})}
</div>
</div>;
}}
/>
</div>
);
}
}
view raw App.js hosted with ❤ by GitHub

14. Let’s run relay

yarn relay

This will generate some code in _generated_ folder in src.

15. Run the project

yarn start

Step 4: Deployment With nginx

  • Install nginx using this link
  • yarn build in the home folder of the project
  • Find you nginx configuration file at /usr/local/etc/nginx/nginx.conf and change location inside server block as follow:
location / {
            root   {absolute path in your computer}/relay-example/build;
            index  index.html index.htm;
        }

For referece, my nginx.conf file looks like this:

#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr – $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 7000;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root /Users/harshvardhan/IdeaProjects/react-learning/relay-example/build;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
include servers/*;
}
view raw nginx.conf hosted with ❤ by GitHub

After you run successfully, you should have following screen:

Github Repo

Github

References:

https://relay.dev/docs/en/quick-start-guide

https://relay.dev/docs/en/experimental/step-by-step

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Blog at WordPress.com.

Up ↑

%d bloggers like this: