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.

  1. 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.
  2. 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.
Solution 2: This solution doesn’t require to change Apollo GraphQL API code hence has it overcomes the drawbacks of the solution 1. In this solution we are creating a proxy server for GraphQL API. All GraphQL API requests from our React application make call on proxy server and it redirect the request on actual GraphQL API endpoint and provide the response. So ultimately proxy server become a server side middleware for the GraphQL API endpoint. Below are the code snippets how this can be achieved.
  1. 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() });

  2. Create a ./.env file on React application root for the API endpoint configuration dynamically API_URL=http://apidomain.com/graphql PORT=3000
  3. 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;

  4. 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(“+—————————————+”); });

  5. 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”, }

  6. To start the server run below command
     npm run server-start

    npm run server-start

Comments


Your comment is awaiting moderation.