Enabling CORS by Implementing Proxy Server for Apollo GraphQL API Integration in React Application
Last Updated on
Sep 27, 2023
Frequently Apollo GraphQL API which is also known as GraphQL over REST API needs to be integrated with frontend application which is built using React or React Native technology. In the usual scenario, both GraphQL API and the React application are hosted on the same domain. But in a specific scenario, we required to develop the react application with the Apollo GraphQL API which is already hosted on some domain other than the domain of the hosted React application. Such scenario leads to challenge, as Apollo GraphQL API does not allow cross-origin request/response while application development due to security reasons.
In such scenario when we try to make request from our React application to API hosted on another domain, and API endpoint does not support cross origin request/response we get the error message as below screenshot of browser inspector window.
In order to resolve the error, if we add the headers for cross domain from client side, we will get “Method not allowed for OPTIONS” error message when we call the graphql API endpoint from react application. This happens because of our application and graphql API are running on different ports/domains.
To address this challenge, we can implement one of two solutions given below:
Solution 1: Enabling CORS module in the Apollo GraphQL API source code so that it allows cross origin request. Below is the code snippet how this can be achieved.
Code :
Installation
npm install --dev cors |
npm install –dev cors
Simple Usage (Enable All CORS Requests)
var express = require('express'); var cors = require('cors') // Added this var app = express(); app.use(cors()); // Added this |
var express = require(‘express’); var cors = require(‘cors’) // Added this var app = express(); app.use(cors()); // Added this
There are some drawback with this implementation.
- We must have access to the GraphQL API source code. If API owner is not allowing access of the code we can’t implement this solution.
- Even if API owner provide access to code and we implement this solution, it becomes security threat because now API becomes Global/Public and can be accessed by any unauthorized cross domain also.
- Implement the Apollo client for React application
import { ApolloLink } from 'apollo-link'; import { ApolloClient } from 'apollo-client'; import { InMemoryCache } from 'apollo-cache-inmemory'; import { HttpLink } from 'apollo-link-http'; const graphUrl = 'http://[appdomain]:3000/graphql'; const client = new ApolloClient({ link: new HttpLink({ uri: graphUrl }), cache: new InMemoryCache() });
import { ApolloLink } from ‘apollo-link’; import { ApolloClient } from ‘apollo-client’; import { InMemoryCache } from ‘apollo-cache-inmemory’; import { HttpLink } from ‘apollo-link-http’; const graphUrl = ‘http://[appdomain]:3000/graphql’; const client = new ApolloClient({ link: new HttpLink({ uri: graphUrl }), cache: new InMemoryCache() });
- Create a ./.env file on React application root for the API endpoint configuration dynamically API_URL=http://apidomain.com/graphql PORT=3000
- Create a config file for the API endpoint (./src/server/config/config.js) on React server
let config = { apiUrl: process.env.API_URL, apiKeyName: process.env.API_KEY_NAME, apiKeyValue: process.env.API_KEY_VALUE, port: process.env.PORT || 3000, assignKey: assignKey }
let config = { apiUrl: process.env.API_URL, apiKeyName: process.env.API_KEY_NAME, apiKeyValue: process.env.API_KEY_VALUE, port: process.env.PORT || 3000, assignKey: assignKey }
function assignKey(query){ let obj = {}; obj[config.apiKeyName] = config.apiKeyValue; return Object.assign(query, obj); }
function assignKey(query){ let obj = {}; obj[config.apiKeyName] = config.apiKeyValue; return Object.assign(query, obj); }
module.exports = config;
module.exports = config;
- Create a server file which supposed to run on node server
require('dotenv').config(); const config = require('./config/config'); const express = require('express'); const request = require('request'); const cors = require('cors'); const app = express(); const port = config.port; app.use(cors());
require(‘dotenv’).config(); const config = require(‘./config/config’); const express = require(‘express’); const request = require(‘request’); const cors = require(‘cors’); const app = express(); const port = config.port; app.use(cors());
app.use('/', function(req, res) {
app.use(‘/’, function(req, res) {
//Take the baseurl from your api and also supply whatever //route you use with that url let url = config.apiUrl + req.url; let query = config.assignKey(req.query);
//Take the baseurl from your api and also supply whatever //route you use with that url let url = config.apiUrl + req.url; let query = config.assignKey(req.query);
//Pipe is through request, this will just redirect //everything from the api to your own server at localhost. //It will also pipe your queries in the url req.pipe(request({ qs: query , uri: url })).pipe(res); });
//Pipe is through request, this will just redirect //everything from the api to your own server at localhost. //It will also pipe your queries in the url req.pipe(request({ qs: query , uri: url })).pipe(res); });
//Start the server by listening on a port app.listen(port, () => { console.log("+---------------------------------------+"); console.log(`| Listening on port:${port} |`); console.log("+---------------------------------------+"); });
//Start the server by listening on a port app.listen(port, () => { console.log(“+—————————————+”); console.log(`| Listening on port:${port} |`); console.log(“+—————————————+”); });
- Update the package.json to run the proxy server
"scripts": { ... "server-start": "node ./src/server/server.js", }
“scripts”: { … “server-start”: “node ./src/server/server.js”, }
- To start the server run below command
npm run server-start
npm run server-start
Comments