Skip to content
This repository was archived by the owner on Jul 14, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"body-parser": "^1.18.2",
"connect-redis": "^3.3.0",
"express": "^4.16.2",
"express-http-proxy": "^1.2.0",
"express-session": "^1.15.3",
"knex": "^0.13.0",
"node-fetch": "^1.7.3",
Expand All @@ -49,7 +50,9 @@
"husky": "^0.14.3",
"jest": "^21.2.1",
"lint-staged": "^5.0.0",
"nock": "^9.4.4",
"prettier": "^1.8.2",
"prettier-check": "^2.0.0"
"prettier-check": "^2.0.0",
"supertest": "^3.1.0"
}
}
2 changes: 2 additions & 0 deletions routes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const bodyParser = require('body-parser');

const createShopifyAuthRoutes = require('./shopifyAuth');
const shopifyApiProxy = require('./shopifyApiProxy');
const shopifyGraphQLProxy = require('./shopifyGraphQLProxy');

module.exports = function createRouter(shopifyConfig) {
const router = express.Router();
Expand All @@ -17,6 +18,7 @@ module.exports = function createRouter(shopifyConfig) {
verifyApiCall,
shopifyApiProxy,
);
router.use(shopifyGraphQLProxy());

return router;
};
Expand Down
34 changes: 34 additions & 0 deletions routes/shopifyGraphQLProxy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const proxy = require('express-http-proxy');

const PROXY_BASE_PATH = '/graphql';
const GRAPHQL_PATH = '/admin/api/graphql.json';

module.exports = function shopifyGraphQLProxy() {
return function shopifyGraphQLProxyMiddleware(req, res, next) {
const { session: { shop, accessToken } } = req;

if (req.path !== PROXY_BASE_PATH || req.method !== 'POST') {
return next();
}

if (accessToken == null || shop == null) {
return res.status(403).send('Unauthorized');
}

proxy(shop, {
https: true,
parseReqBody: false,
proxyReqOptDecorator(proxyReqOpts, srcReq) {
proxyReqOpts.headers['content-type'] = 'application/json';
proxyReqOpts.headers['x-shopify-access-token'] = accessToken;
return proxyReqOpts;
},
proxyReqPathResolver(req) {
return GRAPHQL_PATH;
}
})(req, res, next);
}
};

module.exports.PROXY_BASE_PATH = PROXY_BASE_PATH;
module.exports.GRAPHQL_PATH = GRAPHQL_PATH;
78 changes: 78 additions & 0 deletions routes/tests/shopifyGraphQLProxy.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
const request = require('supertest');
const express = require('express');
const nock = require('nock');
const expressShopifyGraphqlProxy = require('../shopifyGraphQLProxy');

describe('shopifyGraphQLProxy', () => {
const app = express();
app.use(function(req, res, next) { req.session = {}; next(); });
app.use(expressShopifyGraphqlProxy());

it('bails and calls next middleware if request method is not POST', (done) => {
request(app)
.get('/graphql')
.expect(404)
.expect(/Cannot GET \/graphql/, done);
});

it('bails and calls next middleware if request path is not /graphql', (done) => {
request(app)
.post('/not/graphql')
.expect(404)
.expect(/Cannot POST \/not\/graphql/, done);
});

it('responds 403 unauthorized when no session is provided', (done) => {
request(app)
.post('/graphql')
.expect(403)
.expect('Unauthorized', done);
});

it('proxies request to the current logged in shop found in session', (done) => {
const app = express();

app.use(function(req, res, next) {
req.session = {
shop: 'testshop.myshopify.com',
accessToken: 'token'
};
next();
});

app.use(expressShopifyGraphqlProxy());

const graphqlAdminAPI = nock('https://testshop.myshopify.com')
.post('/admin/api/graphql.json')
.reply(200, {
data: {
shop: {
name: 'Test Shop'
}
},
extensions: {
cost: {
requestedQueryCost: 1,
actualQueryCost: 1,
throttleStatus: {
maximumAvailable: 1000.0,
currentlyAvailable:999,
restoreRate:50.0
}
}
}
}, {
'x-shopid': '12345678'
});

request(app)
.post('/graphql')
.send(JSON.stringify({ query: '{ shop { name } }' }))
.end(function(err, res) {
expect(res.statusCode).toEqual(200);
expect(res.header['x-shopid']).toEqual('12345678');
expect(res.body.data.shop.name).toEqual('Test Shop');
done();
});
});
});
Loading