{"id":14976202,"url":"https://github.com/nicolasdao/graphql-serverless","last_synced_at":"2025-10-27T18:30:46.059Z","repository":{"id":24615746,"uuid":"100709125","full_name":"nicolasdao/graphql-serverless","owner":"nicolasdao","description":"GraphQL (incl. a GraphiQL interface) middleware for the webfunc serverless web framework. ","archived":false,"fork":false,"pushed_at":"2022-12-30T20:54:42.000Z","size":1482,"stargazers_count":129,"open_issues_count":15,"forks_count":9,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-01T07:31:50.899Z","etag":null,"topics":["express","faas","functions","graphql","graphql-server","middleware","neap","serverless"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nicolasdao.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-08-18T12:19:11.000Z","updated_at":"2024-04-18T12:50:27.000Z","dependencies_parsed_at":"2023-01-14T01:18:08.356Z","dependency_job_id":null,"html_url":"https://github.com/nicolasdao/graphql-serverless","commit_stats":null,"previous_names":[],"tags_count":55,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicolasdao%2Fgraphql-serverless","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicolasdao%2Fgraphql-serverless/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicolasdao%2Fgraphql-serverless/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicolasdao%2Fgraphql-serverless/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nicolasdao","download_url":"https://codeload.github.com/nicolasdao/graphql-serverless/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238536116,"owners_count":19488660,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["express","faas","functions","graphql","graphql-server","middleware","neap","serverless"],"created_at":"2024-09-24T13:53:29.780Z","updated_at":"2025-10-27T18:30:40.557Z","avatar_url":"https://github.com/nicolasdao.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GraphQL For Serverless \u0026middot;  [![NPM](https://img.shields.io/npm/v/graphql-serverless.svg?style=flat)](https://www.npmjs.com/package/graphql-serverless) [![Tests](https://travis-ci.org/nicolasdao/graphql-serverless.svg?branch=master)](https://travis-ci.org/nicolasdao/graphql-serverless) [![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) [![Neap](https://neap.co/img/made_by_neap.svg)](#this-is-what-we-re-up-to)  [![npm downloads](https://img.shields.io/npm/dt/graphql-serverless.svg?style=flat)](https://www.npmjs.com/package/graphql-serverless)\n\u003ca href=\"https://tracking.gitads.io/?repo=graphql-serverless\" target=\"_blank\"\u003e\u003cimg src=\"https://images.gitads.io/graphql-serverless\" alt=\"GitAds\"/\u003e\u003c/a\u003e\n\n__*graphql-serverless*__ is a middleware for [_**webfunc**_](https://github.com/nicolasdao/webfunc), that allows to deploy [GraphQL](http://graphql.org/learn/) apis (including an optional [GraphiQL interface](https://github.com/graphql/graphiql)) to the most popular serverless platforms. _**GraphQl Subscriptions**_ over websocket are also supported out-of-the-box (also supported in GraphiQL). Without changing a single line of code, seamlessly deploy to:\n- [Zeit Now](https://zeit.co/now) (using express under the hood)\n- [Google Cloud Functions](https://cloud.google.com/functions/) (incl. Firebase Function)\n- [AWS Lambdas](https://aws.amazon.com/lambda)\n- [Azure Functions](https://azure.microsoft.com/en-us/services/functions/) (COMING SOON...)\n\nCopy/paste the following in your terminal if you want to run your first GraphQL api ([http://localhost:4000](http://localhost:4000)) including a GraphiQL interface ([http://localhost:4000/graphiql](http://localhost:4000/graphiql)) on your local machine in less than 30 seconds:\n\n```\ngit clone https://github.com/nicolasdao/graphql-universal-server.git\ncd graphql-universal-server\nnpm install\nnpm start \n```\n\nThis will serve 2 endpoints:\n\n- [http://localhost:4000](http://localhost:4000): This is the GraphQL endpoint that your client can start querying.\n- [http://localhost:4000/graphiql](http://localhost:4000/graphiql): This is the GraphiQL Web UI that you can use to test and query your GraphQL server. \n\nDeploying that api to [Zeit Now](https://zeit.co/now) will take between 15 seconds to 1.5 minute (depending on whether you need to login/creating a free Zeit account or not).\n\n_If you haven't installed Zeit now-CLI yet or you need to login/create an account, then copy/paste this in your terminal:_\n```\nnpm install now -g\nnow login\nnpm run deploy:prod\n```\n\nThe above will work the exact same way whether you have an account or not. This is free, so don't worry about it.\n\n_If you're already logged in, then simply run this:_\n```\nnpm run deploy:prod\n```\n\n# Table Of Contents\n\u003e * [Install](#install)\n\u003e * [How To Use It](#how-to-use-it)\n\u003e   - [Basics](#basics)\n\u003e   - [GraphQl Subscriptions](#graphql-subscriptions)\n\u003e   - [Customizing GraphiQL](#customizing-graphiql)\n\u003e   - [Managing GraphQl Errors](#managing-graphql-errors)\n\u003e   - [Controling GraphQl Server Behavior With Custom Middleware](#controling-graphql-server-behavior-with-custom-middleware)\n\u003e * [About Us](#this-is-what-we-re-up-to)\n\n# Install\n```\nnpm install webfunc graphql-serverless --save\n```\n\n# How To Use It\n## Basics\nUsing the template above (i.e. [graphql-universal-server](https://github.com/nicolasdao/graphql-universal-server.git)) is the easiest way to start a new GraphQL project from scratch. \n\nHowever, if you really want to start on a blank page:\n\n1. Create a new npm project: `npm init`\n2. Install the following: `npm install graphql-serverless webfunc --save`\n3. Create an index.js as follow:\n\n  ```js\n  const { graphqlHandler, graphqlError } = require('graphql-serverless')\n  const { makeExecutableSchema } = require('graphql-tools') // this dependency is automatically included in 'graphql-serverless'\n  const { app } = require('webfunc')\n\n  // STEP 1. Mock some data for this demo.\n  const productMocks = [\n    { id: 1, name: 'Product A', shortDescription: 'First product.' }, \n    { id: 2, name: 'Product B', shortDescription: 'Second product.' }]\n\n  // STEP 2. Creating a basic GraphQl Schema.\n  const schema = `\n    type Product {\n      id: ID!\n      name: String!\n      shortDescription: String\n    }\n\n    type Query {\n      products(id: Int): [Product]\n    }\n\n    schema {\n      query: Query\n    }`\n\n  const productResolver = {\n    Query: {\n      products(root, { id }, context) {\n        const results = id ? productMocks.filter(p =\u003e p.id == id) : productMocks\n        if (results.length \u003e 0)\n          return results\n        else\n          throw graphqlError(404, `Product with id ${id} does not exist.`)\n      }\n    }\n  }\n\n  const executableSchema = makeExecutableSchema({\n    typeDefs: schema,\n    resolvers: productResolver\n  })\n\n  // STEP 3. Creating a GraphQL and a GraphiQl endpoint\n  const graphqlOptions = {\n    schema: executableSchema,\n    graphiql: { // If you do not want to host any GraphiQl web interface, leave this property undefined.\n      endpoint: '/graphiql' \n    },\n    context: {\n    \tsomeVar: 'This variable is passed in the \"context\" object in each resolver.'\n    }\n  }\n\n  // Host a GraphQl API on 2 endpoints: '/' and '/graphiql'. '/graphiql' is used to host the GraphiQL web interface.\n  // If you're not interested in the GraphiQl web interface, leave the above 'graphqlOptions.graphiql' undefined and \n  // replace the path following ['/', '/graphiql'] with '/'.\n  app.all(['/', '/graphiql'], graphqlHandler(graphqlOptions))\n\n  // STEP 4. Starting the server \n  eval(app.listen('app', 4000))\n  ```\n\n4. Then simply run:\n  ```\n  node index.js\n  ```\n\nThis will serve 2 endpoints:\n\n- [http://localhost:4000](http://localhost:4000): This is the GraphQL endpoint that your client can start querying.\n- [http://localhost:4000/graphiql](http://localhost:4000/graphiql): This is the GraphiQL Web UI that you can use to test and query your GraphQL server. \n\n\u003eIf you need best practices on how to structure your GraphQL project, clone the [graphql-universal-server](https://github.com/nicolasdao/graphql-universal-server.git) project and see by yourself. \n\n## GraphQl Subscriptions\n\n\u003e __WARNING: This feature is only available on [Zeit Now serverless](https://zeit.co/now) or on localhost.__ \n\u003e Even though _graphql-serverless_ relies on [_webfunc_](https://github.com/nicolasdao/webfunc) to deploy on FaaS solutions like AWS Lambdas or Google Functions, because those hosting platforms do not natively support websocket, GraphQl Subscriptions can't be deployed there.\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/nicolasdao/graphql-serverless/master/img/graphql_subscription.gif\"/\u003e\u003c/p\u003e\n\n_graphql-serverless_ exposes a helper method `setupSubscriptions` that can host a websocket endpoint for GraphQl Subscriptions. In the following example, we will slightly modify the code above to:\n- (MODIFICATION A) Configure a new websocket endpoint for all subscriptions.\n- (MODIFICATION B) Add a PubSub queue so that publisher can publish messages onto topics and subscribers can listen to certain topics so that clients using websocket can receive updates.\n- (MODIFICATION C) Add a new GraphQl Mutation to insert a new product. This insert will act as a publisher. It will add a message to the PubSub topic once the product has been successfully inserted.\n- (MODIFICATION D) Add a new GraphQl Subscription that listen to a specific topic on the PubSub queue and uses websocket to inform the client that a new product has been inserted.\n\nInstall _graphql-subscriptions_: \n\n`npm install graphql-subscriptions --save`\n\nUpdate the previous `index.js` as follow:\n  ```js\n  // MODIFICATION A - Import the 'setupSubscriptions' helper\n  const { graphqlHandler, graphqlError, setupSubscriptions } = require('graphql-serverless')\n\n  ...\n\n  // MODIFICATION B - Create a simple local pub/sub (not scalable option, but good enough for a demo) \n  const { PubSub } = require('graphql-subscriptions')\n  const pubsub = new PubSub()\n\n  ...\n\n  // MODIFICATION C/D - Add an 'insert product' MUTATION and a 'product inserted' SUBSCRIPTION in the GraphQl schema\n  const schema = `\n  input NewProductInput {\n    name: String!\n    shortDescription: String\n  }\n\n  type Mutation {\n    productInsert(product: NewProductInput!): Product\n  }\n\n  type Subscription {\n    productInserted: Product\n  }\n\n  schema {\n    query: Query\n    mutation: Mutation\n    subscription: Subscription\n  }`\n\n  ...\n\n  // MODIFICATION C/D - Add an 'insert product' MUTATION and a 'product inserted' SUBSCRIPTION in the GraphQl product resolver\n  const productResolver = {\n    Query: {...},\n\n    Mutation: {\n      productInsert(root, { product }, context) {\n        if (!product || !product.name)\n          throw context.graphqlError('Missing required argument \\'product.name\\'.')\n\n        const newId = productMocks.sort((a,b) =\u003e a.id \u003c b.id)[0].id + 1\n        const newProduct = Object.assign({ id: newId }, product)\n        productMocks.push(newProduct)\n        pubsub.publish('productInserted', { productInserted: newProduct })\n        return newProduct\n      }\n    },\n\n    Subscription: {\n      productInserted: {\n        subscribe: () =\u003e pubsub.asyncIterator('productInserted')\n      }\n    }\n  }\n\n  ...\n\n  // MODIFICATION A - Define the location of the subscriptions endpoint\n  const graphqlOptions = {\n    schema: executableSchema,\n    graphiql: {\n      endpoint: '/graphiql'\n    },\n    subscriptionsEndpoint: '/subscriptions' // this means that the subscription endpoint is 'ws://localhost:4000/subscriptions' if you're deploying locally\n  }\n\n  ...\n\n  // MODIFICATION A - Start the websocket endpoint after the server as started. \n  // WARNING: This only works for localhost, serverless Zeit Now, but not \n  // for FaaS like AWS Lambdas, Google Functions, ...\n  eval(app.listen('app', 4000, () =\u003e setupSubscriptions(app.server, graphqlOptions)))\n  ```\n\nExecute `node index.js` and then browse to [http://localhost:4000/graphiql](http://localhost:4000/graphiql). Start a subscription as follow:\n```js\nsubscription {\n  productInserted {\n    id\n    name\n  }\n}\n```\n\nAt that point, the client is simply listening to any new messages on the 'productInserted' topic. Time to publish a new messages on that topic. Open a new tab and browse again to [http://localhost:4000/graphiql](http://localhost:4000/graphiql). There insert a new product as follow:\n```js\nmutation {\n  productInsert(product: {\n    name: \"Product C\"\n  }) {\n    id\n    name\n  }\n}\n```\n\nOnce the product has been inserted, you should be able to observe that your subscription client has noticed it. \n\n\u003cp align=\"center\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/nicolasdao/graphql-serverless/master/img/graphql_subscription.gif\"/\u003e\u003c/p\u003e\n\n## Customizing GraphiQL\n\nThe code sample in the [__*Basics*__](#basics) section uses the default GraphiQl settings:\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/nicolasdao/graphql-serverless/master/img/graphiql_light_theme.png\" width=\"600\"/\u003e\u003c/p\u003e\n\nBy updating the `graphqlOptions` in the [__*Basics*__](#basics) section example as follow:\n\n```js\nconst graphqlOptions = {\n\tschema: executableSchema,\n\tgraphiql: { \n\t\tendpoint: '/graphiql',\n\t\thead: {\n\t\t\ttitle: 'Neap GraphQl API',\n\t\t\t// Adding a custom Favicon\n\t\t\tcustom: '\u003clink rel=\"shortcut icon\" href=\"https://neap.co/favicon.ico\"\u003e',\n\t\t\t// Change the default 'light' theme to a dark one.\n\t\t\ttheme: 'dark',\n\t\t\t// Replace the default 'GraphiQl' logo to your own\n\t\t\tlogo: '\u003cdiv class=\"title\"\u003e\u003cimg src=\"https://neap.co/img/neap_white_small_logo.png\" style=\"width: 88px;z-index: 7;padding-left: 24px;\"\u003e\u003c/div\u003e'\n\t\t},    \n\t\t// Adding a custom JS script\n\t\tscript: () =\u003e {\n\t\t\tfunction getCookie(cname) {\n\t\t\t\tvar name = cname + '='\n\t\t\t\tvar decodedCookie = decodeURIComponent(document.cookie)\n\t\t\t\tvar ca = decodedCookie.split(';')\n\t\t\t\tfor(var i = 0; i \u003cca.length; i++) {\n\t\t\t\t\tvar c = ca[i]\n\t\t\t\t\twhile (c.charAt(0) == ' ')\n\t\t\t\t\t\tc = c.substring(1)\n\t\t\t\t\tif (c.indexOf(name) == 0)\n\t\t\t\t\t\treturn c.substring(name.length, c.length)\n\t\t\t\t}\n\t\t\t\treturn ''\n\t\t\t}\n\t\t},\n\t\t// Executing a custom JS function each time a GraphQL request is made\n\t\tonRequest: headers =\u003e {\n\t\t\tvar token = getCookie('neap_cookie')\n\t\t\tif (token)\n\t\t\t\theaders.Authorization = 'bearer ' + token\n\t\t}\n\t}\n}\n```\n\nWe can update the GraphiQL interface as follow:\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/nicolasdao/graphql-serverless/master/img/graphiql_dark_theme.png\" width=\"600\"/\u003e\u003c/p\u003e\n\nThe differences are:\n- Custom page name\n- Custom favicon\n- Changing from the default 'light' theme to a dark one\n- Custom logo\n- Custom javascript \n- Custom function running each time a GraphQl request is made. In our case, we're updating the HTTP headers to add a bearer token stored in a 'neap_cookie' cookie.\n\nTo use a custom CSS rather than relying on the 'light' or 'dark' theme, you can use the `css` property:\n\n```js\nconst graphqlOptions = {\n  schema: executableSchema,\n  graphiql: { \n    endpoint: '/graphiql',\n    head: {\n      // Adding a dark theme\n      css: [\n        'https://neap.co/resources/css/graphiql/0.0.1/dark_style.css', \n        'https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700|Source+Code+Pro:200,400,700']\n    }\n  }\n}\n```\n\n\u003e WARNING: Using the `css` property will override completely any other out-of-the-box css.\n\n## Managing GraphQl Errors\n\nBy default, any uncaught errors are marshalled to the graphql response similar to this:\n```js\n{\n  \"errors\": [\n    {\n      \"message\": \"Product with id 20 does not exist.\",\n      \"locations\": [\n        {\n          \"line\": 2,\n          \"column\": 3\n        }\n      ],\n      \"path\": [\n        \"products\"\n      ]\n    }\n  ],\n  \"data\": {\n    \"products\": null\n  }\n}\n```\n\nThis type of uncaught error also yield a 500 HTTP code. A piece of code that could produce the error above could be:\n```js\nconst productResolver = {\n  Query: {\n    products(root, { id }, context) {\n      const results = id ? productMocks.filter(p =\u003e p.id == id) : productMocks\n      if (results.length \u003e 0)\n        return results\n      else\n        throw new Error(`Product with id ${id} does not exist.`)\n    }\n  }\n}\n```\n\nHowever, there are situation where you may want to control the error being returned in one of the following ways:\n- Controlling the HTTP code based on the type of error.\n- Hide the details of the error (e.g. the full stack trace) in certain conditions (e.g. production environment).\n\nThis can be achieved thanks to the `graphqlError` helper method.\n\n```js\nconst { graphqlHandler, graphqlError } = require('graphql-serverless')\n\nconst productResolver = {\n  Query: {\n    products(root, { id }, context) {\n      const results = id ? productMocks.filter(p =\u003e p.id == id) : productMocks\n      if (results.length \u003e 0)\n        return results\n      else\n        throw graphqlError({ code: 404, text: `Product with id ${id} does not exist.` })\n    }\n  }\n}\n```\n\nIn case of errors, the response will look like this:\n\n```js\n{\n  \"errors\": [\n    {\n      \"message\": \"Product with id 123 does not exist.\"\n    }\n  ],\n  \"data\": {\n    \"products\": null\n  }\n}\n```\n\nThe `graphqlError` function also supports serializing errors:\n\n```js\nthrow graphqlError({ code: 422, errors:[error] })\n```\n\nThe output in case of errors is similar to:\n\n```js\n{\n  \"errors\": [\n    {\n      \"message\": \"Some error message\",\n      \"locations\": [\n        {\n          \"line\": 382,\n          \"col\": 17,\n          \"method\": \"wrapErrors\",\n          \"path\": \"/Users/nicolasdao/Documents/myproject/src/services/_utils.js\"\n        },\n        {\n          \"line\": 65,\n          \"col\": 19,\n          \"method\": \"onFulfilled\",\n          \"path\": \"/Users/nicolasdao/Documents/myproject/src/services/core/node_modules/co/index.js\"\n        }\n      ]\n    }\n  ],\n  \"data\": {\n    \"products\": null\n  }\n}\n```\n\nIf the stack information in the `locations` field are sensitive, they can be turned off as follow:\n\n```js\nthrow graphqlError({ code: 422, errors:[error], noStack:true })\n```\n\n### API\n\n__*graphqlError('Oops, the product does not exist.')*__\n\nReturns a GraphQL error response with the above error message and a HTTP 500. \n\n__*graphqlError('Oops, the product does not exist.', { alternateMessage: 'Internal Server Error', hide: true })*__\n\nReturns a GraphQL error response with error message 'Internal Server Error' (if the `hide` property is set to `true`) and a HTTP 500. \n\n__*graphqlError(404, 'Oops, the product does not exist.')*__\n\nReturns a GraphQL error response with the above error message and a HTTP 404.\n\n__*graphqlError(404, 'Oops, the product does not exist.', { alternateMessage: 'Internal Server Error', hide: true })*__\n\nReturns a GraphQL error response with error message 'Internal Server Error' (if the `hide` property is set to `true`) and a HTTP 404. \n\n## Controling GraphQl Server Behavior With Custom Middleware\n\nThis section is broken down in 3 parts:\n- [Overview](#overview)\n- [Transforming The GraphQl Response](#transforming-the-graphql-response)\n- [Full API Definition](#full-api-definition)\n\n### Overview\nAt the end, __graphql-serverless__ is simply another Express-like middleware, and as such, we've added the ability to react differently based on other middleware that may have manipulated the request object previously. Those early middleware can affect the behavior of _graphql-serverless_ thanks to the `graphql` property of the `request` object. \n\nLet's take the `index.js` code from the previous [__*Basics*__](#basics) section and add this to it:\n\n```js\n// index.js\n\nconst customMiddleware = (req, res, next) =\u003e {\n  req.graphql = {\n    query: `query { products(id:1){ id name shortDescription } }`\n  }\n  next()\n}\n\n// app.all(['/', '/graphiql'], graphqlHandler(graphqlOptions))\napp.all(['/', '/graphiql'], customMiddleware, graphqlHandler(graphqlOptions))\n\n// STEP 4. Starting the server \neval(app.listen('app', 4000))\n```\n\nStart your server with `node index.js`\nBrowse to [http://localhost:4000/graphiql](http://localhost:4000/graphiql)\nExecute the following GraphQl query:\n```js\nquery{\n  products(id:2){\n    id\n    name\n  }\n}\n```\n\nNormally, you would expect teh following response based on the logic of the code demoed in the [__*Basics*__](#basics) section:\n```js\n{\n  \"data\": {\n    \"products\": [\n      {\n        \"id\": \"2\",\n        \"name\": \"Product B\"\n      }\n    ]\n  }\n}\n```\n\nBut instead, you will receive:\n```js\n{\n  \"data\": {\n    \"products\": [\n      {\n        \"id\": \"1\",\n        \"name\": \"Product A\",\n        \"shortDescription\": \"First product.\"\n      }\n    ]\n  }\n}\n```\n\nAs you can see, the `customMiddleware` we created has allowed us to spoof the original query and replace it with `query { products(id:1){ id name shortDescription } }`.\n\nThis ability is one of the key feature allowing a middleware like [__*graphql-authorize*__](https://github.com/nicolasdao/graphql-authorize.git) which can remove certain fields from the response based on the user's rights. \n\n### Transforming The GraphQl Response\n\nAnother usefull capability is the modification of any GraphQl response. Let's modify the `customMiddleware` function we defined previously:\n\n```js\nconst customMiddleware = (req, res, next) =\u003e {\n  req.graphql = {\n    // query: `query { products(id:1){ id name shortDescription } }`\n    transform: graphQlresponse =\u003e Object.assign({ magicProperty: { message: 'Magic', creator: 'Nicolas Dao' } }, graphQlresponse)\n  }\n  next()\n}\n```\n\nExecuting the previous GraphQl query will yield the following response:\n```js\n{\n  \"magicProperty\": {\n    \"message\": \"Magic\",\n    \"creator\": \"Nicolas Dao\"\n  },\n  \"data\": {\n    \"products\": [\n      {\n        \"id\": \"2\",\n        \"name\": \"Product B\"\n      }\n    ]\n  }\n}\n```\n\n#### Custom Errors \u0026 Warnings\n\nTwo other properties that are very usefull allow to add warning or error messages:\n\n```js\nconst customMiddleware = (req, res, next) =\u003e {\n  req.graphql = {\n    // query: `query { products(id:1){ id name shortDescription } }`\n    transform: graphQlresponse =\u003e Object.assign({ magicProperty: { message: 'Magic', creator: 'Nicolas Dao' } }, graphQlresponse),\n    warnings: [{ message: 'Hello, I am a warning.' }],\n    errors: [{ message: 'Hello, I am an error.' }]\n  }\n  next()\n}\n```\n\nExecuting the previous GraphQl query will yield the following response:\n```js\n{\n  \"magicProperty\": {\n    \"message\": \"Magic\",\n    \"creator\": \"Nicolas Dao\"\n  },\n  \"data\": {\n    \"products\": [\n      {\n        \"id\": \"2\",\n        \"name\": \"Product B\"\n      }\n    ]\n  },\n  \"errors\": [\n    {\n      \"message\": \"Hello, I am an error.\"\n    }\n  ],\n  \"warnings\": [\n    {\n      \"message\": \"Hello, I am a warning.\"\n    }\n  ]\n}\n```\n\n### Full API Definition \n\n| Properties    | type   | Description  |\n| :------------ |:------:| :----------- |\n| query         | String | Valid GraphQl query. |\n| variables     | Object | Valid GraphQl variable object. |\n| operationName | String | GraphQl query operation. |\n| transform     | Function | Function accepting a single argument representing the original GraphQl object. This function can affect that result by either mutating it, or returning a new object. |\n| warnings      | Array  | Array of objects representing a warning. The conventional structure is as follow: { message:String, location: String, path:String } |\n| errors        | Array  | Array of objects representing an error. The conventional structure is as follow: { message:String, location: String, path:String } |\n\n# Contributing\n```\nnpm test\n```\n\n# This Is What We re Up To\nWe are Neap, an Australian Technology consultancy powering the startup ecosystem in Sydney. We simply love building Tech and also meeting new people, so don't hesitate to connect with us at [https://neap.co](https://neap.co).\n\nOur other open-sourced projects:\n#### Web Framework \u0026 Deployment Tools\n* [__*webfunc*__](https://github.com/nicolasdao/webfunc): Write code for serverless similar to Express once, deploy everywhere. \n* [__*now-flow*__](https://github.com/nicolasdao/now-flow): Automate your Zeit Now Deployments.\n\n#### GraphQL\n* [__*graphql-serverless*__](https://github.com/nicolasdao/graphql-serverless): GraphQL (incl. a GraphiQL interface) middleware for [webfunc](https://github.com/nicolasdao/webfunc).\n* [__*schemaglue*__](https://github.com/nicolasdao/schemaglue): Naturally breaks down your monolithic graphql schema into bits and pieces and then glue them back together.\n* [__*graphql-s2s*__](https://github.com/nicolasdao/graphql-s2s): Add GraphQL Schema support for type inheritance, generic typing, metadata decoration. Transpile the enriched GraphQL string schema into the standard string schema understood by graphql.js and the Apollo server client.\n* [__*graphql-authorize*__](https://github.com/nicolasdao/graphql-authorize.git): Authorization middleware for [graphql-serverless](https://github.com/nicolasdao/graphql-serverless). Add inline authorization straight into your GraphQl schema to restrict access to certain fields based on your user's rights.\n\n#### React \u0026 React Native\n* [__*react-native-game-engine*__](https://github.com/bberak/react-native-game-engine): A lightweight game engine for react native.\n* [__*react-native-game-engine-handbook*__](https://github.com/bberak/react-native-game-engine-handbook): A React Native app showcasing some examples using react-native-game-engine.\n\n#### Tools\n* [__*aws-cloudwatch-logger*__](https://github.com/nicolasdao/aws-cloudwatch-logger): Promise based logger for AWS CloudWatch LogStream.\n\n# License\nCopyright (c) 2018, Neap Pty Ltd.\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n* Neither the name of Neap Pty Ltd nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL NEAP PTY LTD BE LIABLE FOR ANY\nDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n\u003cp align=\"center\"\u003e\u003ca href=\"https://neap.co\" target=\"_blank\"\u003e\u003cimg src=\"https://neap.co/img/neap_color_horizontal.png\" alt=\"Neap Pty Ltd logo\" title=\"Neap\" height=\"89\" width=\"200\"/\u003e\u003c/a\u003e\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnicolasdao%2Fgraphql-serverless","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnicolasdao%2Fgraphql-serverless","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnicolasdao%2Fgraphql-serverless/lists"}