{"id":13407375,"url":"https://github.com/graphql-community/koa-graphql","last_synced_at":"2025-05-15T12:04:58.841Z","repository":{"id":36288404,"uuid":"40592926","full_name":"graphql-community/koa-graphql","owner":"graphql-community","description":"Create a GraphQL HTTP server with Koa.","archived":false,"fork":false,"pushed_at":"2023-01-24T05:39:34.000Z","size":2365,"stargazers_count":843,"open_issues_count":6,"forks_count":62,"subscribers_count":12,"default_branch":"main","last_synced_at":"2025-05-09T04:01:45.088Z","etag":null,"topics":["graphql","koa","koa-graphql","koa-middleware"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/graphql-community.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2015-08-12T09:42:54.000Z","updated_at":"2024-08-10T12:27:30.000Z","dependencies_parsed_at":"2023-02-13T18:16:01.973Z","dependency_job_id":null,"html_url":"https://github.com/graphql-community/koa-graphql","commit_stats":null,"previous_names":["chentsulin/koa-gql","chentsulin/koa-graphql"],"tags_count":41,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphql-community%2Fkoa-graphql","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphql-community%2Fkoa-graphql/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphql-community%2Fkoa-graphql/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphql-community%2Fkoa-graphql/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/graphql-community","download_url":"https://codeload.github.com/graphql-community/koa-graphql/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254337612,"owners_count":22054253,"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":["graphql","koa","koa-graphql","koa-middleware"],"created_at":"2024-07-30T20:00:38.758Z","updated_at":"2025-05-15T12:04:53.829Z","avatar_url":"https://github.com/graphql-community.png","language":"TypeScript","funding_links":[],"categories":["Lib/Framework/API/Dev Tool","TypeScript"],"sub_categories":[],"readme":"# GraphQL Koa Middleware\n\n[![npm version](https://badge.fury.io/js/koa-graphql.svg)](https://badge.fury.io/js/koa-graphql)\n[![Build Status](https://github.com/graphql-community/koa-graphql/workflows/CI/badge.svg?branch=main)](https://github.com/graphql-community/koa-graphql/actions?query=branch%3Amain)\n[![Coverage Status](https://codecov.io/gh/graphql-community/koa-graphql/branch/main/graph/badge.svg)](https://codecov.io/gh/graphql-community/koa-graphql)\n\nCreate a GraphQL HTTP server with [Koa](https://koajs.com/).\n\nPort from [express-graphql](https://github.com/graphql/express-graphql).\n\n## Installation\n\n```\nnpm install --save koa-graphql\n```\n\n### TypeScript\n\nThis module includes a [TypeScript](https://www.typescriptlang.org/)\ndeclaration file to enable auto complete in compatible editors and type\ninformation for TypeScript projects.\n\n## Simple Setup\n\nMount `koa-graphql` as a route handler:\n\n```js\nconst Koa = require('koa');\nconst mount = require('koa-mount');\nconst { graphqlHTTP } = require('koa-graphql');\n\nconst app = new Koa();\n\napp.use(\n  mount(\n    '/graphql',\n    graphqlHTTP({\n      schema: MyGraphQLSchema,\n      graphiql: true,\n    }),\n  ),\n);\n\napp.listen(4000);\n```\n\n## Setup with Koa Router\n\nWith `@koa/router`:\n\n```js\nconst Koa = require('koa');\nconst Router = require('@koa/router');\nconst { graphqlHTTP } = require('koa-graphql');\n\nconst app = new Koa();\nconst router = new Router();\n\nrouter.all(\n  '/graphql',\n  graphqlHTTP({\n    schema: MyGraphQLSchema,\n    graphiql: true,\n  }),\n);\n\napp.use(router.routes()).use(router.allowedMethods());\n```\n\n## Setup with Koa v1\n\nFor Koa 1, use [koa-convert](https://github.com/koajs/convert) to convert the middleware:\n\n```js\nconst koa = require('koa');\nconst mount = require('koa-mount'); // koa-mount@1.x\nconst convert = require('koa-convert');\nconst { graphqlHTTP } = require('koa-graphql');\n\nconst app = koa();\n\napp.use(\n  mount(\n    '/graphql',\n    convert.back(\n      graphqlHTTP({\n        schema: MyGraphQLSchema,\n        graphiql: true,\n      }),\n    ),\n  ),\n);\n```\n\n## Setup with Subscription Support\n\n```js\nconst Koa = require('koa');\nconst mount = require('koa-mount');\nconst { graphqlHTTP } = require('koa-graphql');\nconst typeDefs = require('./schema');\nconst resolvers = require('./resolvers');\nconst { makeExecutableSchema } = require('graphql-tools');\nconst schema = makeExecutableSchema({\n  typeDefs: typeDefs,\n  resolvers: resolvers,\n});\nconst { execute, subscribe } = require('graphql');\nconst { createServer } = require('http');\nconst { SubscriptionServer } = require('subscriptions-transport-ws');\nconst PORT = 4000;\nconst app = new Koa();\napp.use(\n  mount(\n    '/graphql',\n    graphqlHTTP({\n      schema: schema,\n      graphiql: {\n        subscriptionEndpoint: `ws://localhost:${PORT}/subscriptions`,\n      },\n    }),\n  ),\n);\nconst ws = createServer(app.callback());\nws.listen(PORT, () =\u003e {\n  // Set up the WebSocket for handling GraphQL subscriptions.\n  new SubscriptionServer(\n    {\n      execute,\n      subscribe,\n      schema,\n    },\n    {\n      server: ws,\n      path: '/subscriptions',\n    },\n  );\n});\n```\n\n## Options\n\nThe `graphqlHTTP` function accepts the following options:\n\n- **`schema`**: A `GraphQLSchema` instance from [`graphql-js`][].\n  A `schema` _must_ be provided.\n\n- **`graphiql`**: If `true`, presents [GraphiQL][] when the GraphQL endpoint is\n  loaded in a browser. We recommend that you set `graphiql` to `true` when your\n  app is in development, because it's quite useful. You may or may not want it\n  in production.\n  Alternatively, instead of `true` you can pass in an options object:\n\n  - **`defaultQuery`**: An optional GraphQL string to use when no query\n    is provided and no stored query exists from a previous session.\n    If `undefined` is provided, GraphiQL will use its own default query.\n\n  - **`headerEditorEnabled`**: An optional boolean which enables the header editor when true.\n    Defaults to `false`.\n\n  - **`subscriptionEndpoint`**: An optional GraphQL string contains the WebSocket server url for subscription.\n\n  - **`websocketClient`**: An optional GraphQL string for websocket client used for subscription, `v0`: subscriptions-transport-ws, `v1`: graphql-ws. Defaults to `v0` if not provided\n\n  - **`shouldPersistHeaders`**\n\n  - **`editorTheme`**: By passing an object you may change the theme of GraphiQL.\n    Details are below in the [Custom GraphiQL themes](#custom-graphiql-themes) section.\n\n- **`rootValue`**: A value to pass as the `rootValue` to the `execute()`\n  function from [`graphql-js/src/execute.js`](https://github.com/graphql/graphql-js/blob/main/src/execution/execute.js#L129).\n\n- **`context`**: A value to pass as the `context` to the `execute()`\n  function from [`graphql-js/src/execute.js`](https://github.com/graphql/graphql-js/blob/main/src/execution/execute.js#L130). If `context` is not provided, the\n  `ctx` object is passed as the context.\n\n- **`pretty`**: If `true`, any JSON response will be pretty-printed.\n\n- **`extensions`**: An optional function for adding additional metadata to the\n  GraphQL response as a key-value object. The result will be added to the\n  `\"extensions\"` field in the resulting JSON. This is often a useful place to\n  add development time metadata such as the runtime of a query or the amount\n  of resources consumed. This may be an async function. The function is\n  given one object as an argument: `{ document, variables, operationName, result, context }`.\n\n- **`validationRules`**: Optional additional validation rules that queries must\n  satisfy in addition to those defined by the GraphQL spec.\n\n- **`customValidateFn`**: An optional function which will be used to validate\n  instead of default `validate` from `graphql-js`.\n\n- **`customExecuteFn`**: An optional function which will be used to execute\n  instead of default `execute` from `graphql-js`.\n\n- **`customFormatErrorFn`**: An optional function which will be used to format any\n  errors produced by fulfilling a GraphQL operation. If no function is\n  provided, GraphQL's default spec-compliant [`formatError`][] function will be used.\n\n- **`customParseFn`**: An optional function which will be used to create a document\n  instead of the default `parse` from `graphql-js`.\n\n- **`formatError`**: is deprecated and replaced by `customFormatErrorFn`. It will be\n  removed in version 1.0.0.\n\n- **`fieldResolver`**\n\n- **`typeResolver`**\n\nIn addition to an object defining each option, options can also be provided as\na function (or async function) which returns this options object. This function\nis provided the arguments `(request, response, graphQLParams)` and is called\nafter the request has been parsed.\n\nThe `graphQLParams` is provided as the object `{ query, variables, operationName, raw }`.\n\n```js\napp.use(\n  mount(\n    '/graphql',\n    graphqlHTTP(async (request, response, ctx, graphQLParams) =\u003e ({\n      schema: MyGraphQLSchema,\n      rootValue: await someFunctionToGetRootValue(request),\n      graphiql: true,\n    })),\n  ),\n);\n```\n\n## HTTP Usage\n\nOnce installed at a path, `koa-graphql` will accept requests with\nthe parameters:\n\n- **`query`**: A string GraphQL document to be executed.\n\n- **`variables`**: The runtime values to use for any GraphQL query variables\n  as a JSON object.\n\n- **`operationName`**: If the provided `query` contains multiple named\n  operations, this specifies which operation should be executed. If not\n  provided, a 400 error will be returned if the `query` contains multiple\n  named operations.\n\n- **`raw`**: If the `graphiql` option is enabled and the `raw` parameter is\n  provided, raw JSON will always be returned instead of GraphiQL even when\n  loaded from a browser.\n\nGraphQL will first look for each parameter in the query string of a URL:\n\n```\n/graphql?query=query+getUser($id:ID){user(id:$id){name}}\u0026variables={\"id\":\"4\"}\n```\n\nIf not found in the query string, it will look in the POST request body.\n\nIf a previous middleware has already parsed the POST body, the `request.body`\nvalue will be used. Use [`multer`][] or a similar middleware to add support\nfor `multipart/form-data` content, which may be useful for GraphQL mutations\ninvolving uploading files. See an [example using multer](https://github.com/graphql-community/koa-graphql/blob/e1a98f3548203a3c41fedf3d4267846785480d28/src/__tests__/http-test.js#L664-L732).\n\nIf the POST body has not yet been parsed, `koa-graphql` will interpret it\ndepending on the provided _Content-Type_ header.\n\n- **`application/json`**: the POST body will be parsed as a JSON\n  object of parameters.\n\n- **`application/x-www-form-urlencoded`**: the POST body will be\n  parsed as a url-encoded string of key-value pairs.\n\n- **`application/graphql`**: the POST body will be parsed as GraphQL\n  query string, which provides the `query` parameter.\n\n## Combining with Other koa Middleware\n\nBy default, the koa request is passed as the GraphQL `context`.\nSince most koa middleware operates by adding extra data to the\nrequest object, this means you can use most koa middleware just by inserting it before `graphqlHTTP` is mounted. This covers scenarios such as authenticating the user, handling file uploads, or mounting GraphQL on a dynamic endpoint.\n\nThis example uses [`koa-session`][] to provide GraphQL with the currently logged-in session.\n\n```js\nconst Koa = require('koa');\nconst mount = require('koa-mount');\nconst session = require('koa-session');\nconst { graphqlHTTP } = require('koa-graphql');\n\nconst app = new Koa();\napp.keys = ['some secret'];\napp.use(session(app));\napp.use(function* (next) {\n  this.session.id = 'me';\n  yield next;\n});\n\napp.use(\n  mount(\n    '/graphql',\n    graphqlHTTP({\n      schema: MySessionAwareGraphQLSchema,\n      graphiql: true,\n    }),\n  ),\n);\n```\n\nThen in your type definitions, you can access the ctx via the third \"context\" argument in your `resolve` function:\n\n```js\nnew GraphQLObjectType({\n  name: 'MyType',\n  fields: {\n    myField: {\n      type: GraphQLString,\n      resolve(parentValue, args, ctx) {\n        // use `ctx.session` here\n      },\n    },\n  },\n});\n```\n\n## Providing Extensions\n\nThe GraphQL response allows for adding additional information in a response to\na GraphQL query via a field in the response called `\"extensions\"`. This is added\nby providing an `extensions` function when using `graphqlHTTP`. The function\nmust return a JSON-serializable Object.\n\nWhen called, this is provided an argument which you can use to get information\nabout the GraphQL request:\n\n`{ document, variables, operationName, result, context }`\n\nThis example illustrates adding the amount of time consumed by running the\nprovided query, which could perhaps be used by your development tools.\n\n```js\nconst { graphqlHTTP } = require('koa-graphql');\n\nconst app = new Koa();\n\nconst extensions = ({\n  document,\n  variables,\n  operationName,\n  result,\n  context,\n}) =\u003e {\n  return {\n    runTime: Date.now() - context.startTime,\n  };\n};\n\napp.use(\n  mount(\n    '/graphql',\n    graphqlHTTP((request) =\u003e {\n      return {\n        schema: MyGraphQLSchema,\n        context: { startTime: Date.now() },\n        graphiql: true,\n        extensions,\n      };\n    }),\n  ),\n);\n```\n\nWhen querying this endpoint, it would include this information in the result,\nfor example:\n\n```js\n{\n  \"data\": { ... },\n  \"extensions\": {\n    \"runTime\": 135\n  }\n}\n```\n\n## Additional Validation Rules\n\nGraphQL's [validation phase](https://graphql.github.io/graphql-spec/#sec-Validation) checks the query to ensure that it can be successfully executed against the schema. The `validationRules` option allows for additional rules to be run during this phase. Rules are applied to each node in an AST representing the query using the Visitor pattern.\n\nA validation rule is a function which returns a visitor for one or more node Types. Below is an example of a validation preventing the specific field name `metadata` from being queried. For more examples, see the [`specifiedRules`](https://github.com/graphql/graphql-js/tree/main/src/validation/rules) in the [graphql-js](https://github.com/graphql/graphql-js) package.\n\n```js\nimport { GraphQLError } from 'graphql';\n\nexport function DisallowMetadataQueries(context) {\n  return {\n    Field(node) {\n      const fieldName = node.name.value;\n\n      if (fieldName === 'metadata') {\n        context.reportError(\n          new GraphQLError(\n            `Validation: Requesting the field ${fieldName} is not allowed`,\n          ),\n        );\n      }\n    },\n  };\n}\n```\n\n### Disabling Introspection\n\nDisabling introspection does not reflect best practices and does not necessarily make your\napplication any more secure. Nevertheless, disabling introspection is possible by utilizing the\n`NoSchemaIntrospectionCustomRule` provided by the [graphql-js](https://github.com/graphql/graphql-js)\npackage.\n\n```js\nimport { NoSchemaIntrospectionCustomRule } from 'graphql';\n\napp.use(\n  mount(\n    '/graphql',\n    graphqlHTTP((request) =\u003e {\n      return {\n        schema: MyGraphQLSchema,\n        validationRules: [NoSchemaIntrospectionCustomRule],\n      };\n    }),\n  ),\n);\n```\n\n## Custom GraphiQL Themes\n\nTo use custom GraphiQL theme you should pass to `graphiql` option an object with\nthe property `editorTheme`. It could be a string with the name of a theme from `CodeMirror`\n\n```js\nrouter.all(\n  '/graphql',\n  graphqlHTTP({\n    schema: MyGraphQLSchema,\n    graphiql: {\n      editorTheme: 'blackboard',\n    },\n  }),\n);\n```\n\n[List of available CodeMirror themes](https://codemirror.net/demo/theme.html)\n\nor an object with `url` and `name` properties where `url` should lead to\nyour custom theme and `name` would be passed to the `GraphiQL`\nreact element on creation as the `editorTheme` property\n\n```js\nrouter.all(\n  '/graphql',\n  graphqlHTTP({\n    schema: MyGraphQLSchema,\n    graphiql: {\n      editorTheme: {\n        name: 'blackboard',\n        url: 'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.53.2/theme/erlang-dark.css',\n      },\n    },\n  }),\n);\n```\n\nFor details see the [GraphiQL spec](https://github.com/graphql/graphiql/tree/master/packages/graphiql#applying-an-editor-theme)\n\n## Additional Validation Rules\n\nGraphQL's [validation phase](https://graphql.github.io/graphql-spec/#sec-Validation) checks the query to ensure that it can be successfully executed against the schema. The `validationRules` option allows for additional rules to be run during this phase. Rules are applied to each node in an AST representing the query using the Visitor pattern.\n\nA validation rule is a function which returns a visitor for one or more node Types. Below is an example of a validation preventing the specific field name `metadata` from being queried. For more examples see the [`specifiedRules`](https://github.com/graphql/graphql-js/tree/main/src/validation/rules) in the [graphql-js](https://github.com/graphql/graphql-js) package.\n\n```js\nimport { GraphQLError } from 'graphql';\n\nexport function DisallowMetadataQueries(context) {\n  return {\n    Field(node) {\n      const fieldName = node.name.value;\n\n      if (fieldName === 'metadata') {\n        context.reportError(\n          new GraphQLError(\n            `Validation: Requesting the field ${fieldName} is not allowed`,\n          ),\n        );\n      }\n    },\n  };\n}\n```\n\n## Debugging Tips\n\nDuring development, it's useful to get more information from errors, such as\nstack traces. Providing a function to `customFormatErrorFn` enables this:\n\n```js\ncustomFormatErrorFn: (error, ctx) =\u003e ({\n  message: error.message,\n  locations: error.locations,\n  stack: error.stack ? error.stack.split('\\n') : [],\n  path: error.path,\n});\n```\n\n### Examples\n\n- [tests](https://github.com/graphql-community/koa-graphql/blob/main/src/__tests__/http-test.js)\n\n### Other Relevant Projects\n\nPlease checkout [awesome-graphql](https://github.com/chentsulin/awesome-graphql).\n\n### Contributing\n\nWelcome pull requests!\n\n### License\n\nMIT\n\n[`graphql-js`]: https://github.com/graphql/graphql-js\n[`formaterror`]: https://github.com/graphql/graphql-js/blob/main/src/error/formatError.js\n[graphiql]: https://github.com/graphql/graphiql\n[`multer`]: https://github.com/expressjs/multer\n[`koa-session`]: https://github.com/koajs/session\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraphql-community%2Fkoa-graphql","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgraphql-community%2Fkoa-graphql","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraphql-community%2Fkoa-graphql/lists"}