Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"express": "^4.13.3",
"express-force-ssl": "^0.3.0",
"express-graphql": "^0.6.1",
"express-interceptor": "^1.2.0",
"graphiql": "^0.11.11",
"graphql": "^0.13.2",
"graphql-depth-limit": "^1.1.0",
Expand Down Expand Up @@ -113,11 +114,13 @@
"eslint-config-airbnb": "^3.1.0",
"eslint-plugin-react": "^3.14.0",
"expect.js": "^0.3.1",
"graphql-crunch": "^1.1.2",
"husky": "^0.13.3",
"jest": "^22.4.2",
"lint-staged": "^3.4.0",
"prettier": "^1.7",
"sinon": "^1.17.2",
"supertest": "^3.1.0",
"typescript": "^2.7.2",
"typescript-babel-jest": "^1.0.5"
},
Expand Down
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import moment from "moment"
import morgan from "artsy-morgan"
import raven from "raven"
import xapp from "artsy-xapp"
import crunchInterceptor from "./lib/crunchInterceptor"
import {
fetchLoggerSetup,
fetchLoggerRequestDone,
Expand Down Expand Up @@ -79,6 +80,7 @@ async function startApp() {
next()
},
fetchPersistedQuery,
crunchInterceptor,
graphqlHTTP((req, res) => {
const accessToken = req.headers["x-access-token"]
const userID = req.headers["x-user-id"]
Expand Down
60 changes: 60 additions & 0 deletions src/lib/__tests__/crunchInterceptor.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import express from "express"
import graphqlHTTP from "express-graphql"
import request from "supertest"
import bodyParser from "body-parser"
import { makeExecutableSchema, addMockFunctionsToSchema } from "graphql-tools"
import { crunch } from "graphql-crunch"

import crunchInterceptor from "../crunchInterceptor"

describe("crunchInterceptor", () => {
let app

beforeEach(() => {
const schema = makeExecutableSchema({
typeDefs: `
type Query {
greeting: String
}
`,
})
addMockFunctionsToSchema({ schema })
app = express()
app.use(
"/",
bodyParser.json(),
crunchInterceptor,
graphqlHTTP({
schema,
graphiql: false,
})
)
})

it("should pass the result through unchanged when no param is present", () => {
return request(app)
.get("/?query={greeting}")
.set("Accept", "application/json")
.expect(res => {
expect(res.body.data).toMatchObject({ greeting: "Hello World" })
})
})

it("should crunch the result when param is present", () => {
return request(app)
.get("/?query={greeting}&crunch")
.set("Accept", "application/json")
.expect(res => {
expect(res.body.data).toMatchObject(crunch({ greeting: "Hello World" }))
})
})

it("should not crunch an introspection query", () => {
return request(app)
.get("/?query={__schema{types{name}}}&crunch")
.set("Accept", "application/json")
.expect(res => {
expect(Array.isArray(res.body.data)).toBeFalsy()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expectation is that a crunched result will be an array whereas a non-crunched result will be an object. This isn't a very sophisticated test, but it at least provides some level of validation. I'm not convinced this should even be a thing though... more on that below.

})
})
})
13 changes: 13 additions & 0 deletions src/lib/crunchInterceptor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { crunch } from "graphql-crunch"
import interceptor from "express-interceptor"

export default interceptor(req => ({
isInterceptable: () => req.query.hasOwnProperty("crunch"),
intercept: (body, send) => {
body = JSON.parse(body) // eslint-disable-line no-param-reassign
if (body && body.data && !body.data.__schema) {
body.data = crunch(body.data) // eslint-disable-line no-param-reassign
}
send(JSON.stringify(body))
},
}))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can anyone see why checking for __schema here would be necessary? That part comes more or less straight from the docs, but I'm assuming if the client was adding a crunch param then it already has immediate crunch handling before the results are actually processes by the client's gql library. Also, it doesn't seem like an exhaustive search for introspection queries... I mean, there's a lot of other queryable fields, right? At the very least it doesn't hurt anything so I left it there for discussion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also there are two other things that I'm a bit concerned with here.

  1. parsing the body at the beginning of the interceptor and stringifying it at the end seems like it could negatively impact perf
  2. I'm not sure if the interceptor will be triggered on an error response. I likely need to add a more robust check in the isInterceptable method.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure the __schema comes from the official recommendation on generating a full introspection query, basically to generate the data that fills GraphiQL.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yeah, good point, those clients wouldn't be adding the crunch param, so wouldn't see it at all

Copy link
Contributor Author

@just-be-dev just-be-dev May 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if a client did do an introspection query with the crunch flag, so long as the uncrunch step happened on the client before it was passed to the graphql layer I'd think that it wouldn't matter. I reached out to @jamesreggio, maybe I'm just missing something.

Copy link

@jamesreggio jamesreggio May 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there — just confirmed that including the __schema condition was an unnecessary mistake.

We built graphql-crunch as a drop-in replacement for graphql-deduplicator, which is a lossy compressor that depends upon Apollo-specific behavior. The graphql-deduplicator example code includes that condition, and we accidentally cargo-culted it into our README.

All that to say, it's safe to remove.

Also, hey @orta 👋

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sweet, thanks!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense 👋

86 changes: 83 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1649,6 +1649,12 @@ color-name@^1.1.1:
version "1.1.3"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"

combined-stream@1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818"
dependencies:
delayed-stream "~1.0.0"

combined-stream@^1.0.5, combined-stream@~1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009"
Expand All @@ -1675,7 +1681,7 @@ compare-versions@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.1.0.tgz#43310256a5c555aaed4193c04d8f154cf9c6efd5"

component-emitter@^1.2.1, component-emitter@~1.2.0:
component-emitter@^1.2.0, component-emitter@^1.2.1, component-emitter@~1.2.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"

Expand Down Expand Up @@ -1752,6 +1758,10 @@ cookiejar@2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.0.6.tgz#0abf356ad00d1c5a219d88d44518046dd026acfe"

cookiejar@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.1.tgz#41ad57b1b555951ec171412a81942b1e8200d34a"

copy-descriptor@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
Expand Down Expand Up @@ -2348,6 +2358,12 @@ express-graphql@^0.6.1:
http-errors "^1.3.0"
raw-body "^2.1.0"

express-interceptor@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/express-interceptor/-/express-interceptor-1.2.0.tgz#33460a8e11dce7e5a022caf555d377e45ddb822a"
dependencies:
debug "^2.2.0"

express@^4.13.3:
version "4.16.2"
resolved "https://registry.yarnpkg.com/express/-/express-4.16.2.tgz#e35c6dfe2d64b7dca0a5cd4f21781be3299e076c"
Expand Down Expand Up @@ -2400,7 +2416,7 @@ extend@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4"

extend@~3.0.0, extend@~3.0.1:
extend@^3.0.0, extend@~3.0.0, extend@~3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444"

Expand Down Expand Up @@ -2584,6 +2600,14 @@ form-data@1.0.0-rc3:
combined-stream "^1.0.5"
mime-types "^2.1.3"

form-data@^2.3.1:
version "2.3.2"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099"
dependencies:
asynckit "^0.4.0"
combined-stream "1.0.6"
mime-types "^2.1.12"

form-data@~2.1.1:
version "2.1.4"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1"
Expand All @@ -2606,6 +2630,10 @@ formatio@1.1.1:
dependencies:
samsam "~1.1"

formidable@^1.1.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.1.tgz#70fb7ca0290ee6ff961090415f4b3df3d2082659"

formidable@~1.0.14:
version "1.0.17"
resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.0.17.tgz#ef5491490f9433b705faa77249c99029ae348559"
Expand Down Expand Up @@ -2800,6 +2828,10 @@ graphiql@^0.11.11:
codemirror-graphql "^0.6.11"
markdown-it "^8.4.0"

graphql-crunch@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/graphql-crunch/-/graphql-crunch-1.1.2.tgz#8c8e686d1cb92b55f779fdf902c99ac644280c15"

graphql-depth-limit@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/graphql-depth-limit/-/graphql-depth-limit-1.1.0.tgz#59fe6b2acea0ab30ee7344f4c75df39cc18244e8"
Expand Down Expand Up @@ -4357,7 +4389,7 @@ mersenne-twister@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/mersenne-twister/-/mersenne-twister-1.1.0.tgz#f916618ee43d7179efcf641bec4531eb9670978a"

methods@~1.1.1, methods@~1.1.2:
methods@^1.1.1, methods@~1.1.1, methods@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"

Expand Down Expand Up @@ -4419,6 +4451,10 @@ mime@1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"

mime@^1.4.1:
version "1.6.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"

mimic-fn@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18"
Expand Down Expand Up @@ -5024,6 +5060,10 @@ qs@^5.2.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/qs/-/qs-5.2.1.tgz#801fee030e0b9450d6385adc48a4cc55b44aedfc"

qs@^6.5.1:
version "6.5.2"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"

qs@~6.4.0:
version "6.4.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
Expand Down Expand Up @@ -5143,6 +5183,18 @@ readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4, readable
string_decoder "~1.0.3"
util-deprecate "~1.0.1"

readable-stream@^2.0.5:
version "2.3.6"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.3"
isarray "~1.0.0"
process-nextick-args "~2.0.0"
safe-buffer "~5.1.1"
string_decoder "~1.1.1"
util-deprecate "~1.0.1"

readdirp@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"
Expand Down Expand Up @@ -5806,6 +5858,12 @@ string_decoder@~1.0.3:
dependencies:
safe-buffer "~5.1.0"

string_decoder@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
dependencies:
safe-buffer "~5.1.0"

stringstream@~0.0.4, stringstream@~0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
Expand Down Expand Up @@ -5844,6 +5902,21 @@ strip-json-comments@~2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"

superagent@3.8.2:
version "3.8.2"
resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.2.tgz#e4a11b9d047f7d3efeb3bbe536d9ec0021d16403"
dependencies:
component-emitter "^1.2.0"
cookiejar "^2.1.0"
debug "^3.1.0"
extend "^3.0.0"
form-data "^2.3.1"
formidable "^1.1.1"
methods "^1.1.1"
mime "^1.4.1"
qs "^6.5.1"
readable-stream "^2.0.5"

superagent@^1.2.0:
version "1.8.5"
resolved "https://registry.yarnpkg.com/superagent/-/superagent-1.8.5.tgz#1c0ddc3af30e80eb84ebc05cb2122da8fe940b55"
Expand All @@ -5860,6 +5933,13 @@ superagent@^1.2.0:
readable-stream "1.0.27-1"
reduce-component "1.0.1"

supertest@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/supertest/-/supertest-3.1.0.tgz#f9ebaf488e60f2176021ec580bdd23ad269e7bc6"
dependencies:
methods "~1.1.2"
superagent "3.8.2"

supports-color@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
Expand Down