From 7014e175fb43fbc493ff5bc948e3374ca4dc905a Mon Sep 17 00:00:00 2001 From: sarahxsanders Date: Mon, 9 Jun 2025 19:13:44 -0400 Subject: [PATCH 1/6] move migrate from express graphql guide to graphqlJS docs --- website/pages/docs/_meta.ts | 1 + .../docs/migrating-from-express-graphql.mdx | 186 ++++++++++++++++++ 2 files changed, 187 insertions(+) create mode 100644 website/pages/docs/migrating-from-express-graphql.mdx diff --git a/website/pages/docs/_meta.ts b/website/pages/docs/_meta.ts index 97c5bc2b2e..ee6d1c47cf 100644 --- a/website/pages/docs/_meta.ts +++ b/website/pages/docs/_meta.ts @@ -6,6 +6,7 @@ const meta = { }, 'getting-started': '', 'running-an-express-graphql-server': '', + 'migrating-from-express-graphql': '', 'graphql-clients': '', 'basic-types': '', 'passing-arguments': '', diff --git a/website/pages/docs/migrating-from-express-graphql.mdx b/website/pages/docs/migrating-from-express-graphql.mdx new file mode 100644 index 0000000000..cd834f6cfa --- /dev/null +++ b/website/pages/docs/migrating-from-express-graphql.mdx @@ -0,0 +1,186 @@ +--- +title: Migrate from Express GraphQL to GraphQL over HTTP +sidebarTitle: Migrate from Express GraphQL +--- + +# Migrate from Express GraphQL to GraphQL over HTTP + +When GraphQL was open-sourced in 2015, `express-graphql` quickly became the +default way to run a GraphQL server in JavaScript. Built as middleware for Express, +it provided a simple and reliable way to serve GraphQL queries using Node.js. + +While `express-graphql` still receives occasional updates for security and spec alignment, it is no longer actively developed. This limits its suitability for projects that need more control over request handling, streaming, or support for modern deployment environments. + +[`graphql-http`](https://github.com/graphql/graphql-http) is a lightweight implementation of the [GraphQL over HTTP specification](https://graphql.github.io/graphql-over-http/draft/). It's framework-agnostic, built to be composable, and easy to integrate into different server environments. Unlike `express-graphql`, it can run in a wide range of environments, not just Express. + +This guide is for developers currently using `express-graphql` who want to +modernize their stack, adopt the HTTP spec, or decouple their GraphQL server +from Express. + +## Benefits of migrating + +### `express-graphql` has limited future support + +The library is no longer under active development. While it is still maintained for security and spec compliance, it is not evolving with the GraphQL ecosystem. This makes it less flexible for long-term projects. + +### `graphql-http` is spec-compliant by default + +The GraphQL over HTTP specification defines how GraphQL should be transported over HTTP, including request methods, status codes, content types, and more. `graphql-http` follows this spec precisely, helping your server behave predictably and remain compatible with future tooling. + +### It's framework-agnostic by design + +Instead of relying on Express, `graphql-http` is built on the standard Web `Request` and `Response` interfaces. It works with Express, Fastify, Node's native HTTP server, and can also be used in serverless and edge environments. + +### It fits into modern JavaScript stacks + +`graphql-http` supports ESM and works well with modern build tools and lightweight deployment platforms. Its composable design makes it easy to customize, wrap, and integrate into different application architectures. + +### Designed for future compatibility + +As GraphQL evolves, tools and platforms increasingly expect spec-compliant behavior. Migration to `graphql-http` helps ensure your +server will support future capabilities without relying on workarounds. + +## Migration guide + +The following steps walk through how to migrate an existing `express-graphql` server to use `graphql-http`. The steps assume you already have a working Express app using `express-graphql`. + +### Prerequisites + +Before you begin, make sure you have: + +- Node.js 16 or later +- A GraphQL schema +- An existing Express app configured with `express-graphql` + +### Step 1: Install graphql-http and the Express adapter + +Install the core `graphql-http` package along with its Express adapter: + +```bash +npm install graphql graphql-http @graphql-http/express +``` + +The `graphql` package is a peer dependency of `graphql-http`, and must be installed if it isn't already. + +### Step 2: Remove express-graphql middleware + +In your Express server file, remove the `express-graphql` middleware: + +```js +// Before (using express-graphql) +import { graphqlHTTP } from 'express-graphql'; + +app.use('/graphql', graphqlHTTP({ + schema, + graphiql: true, +})); +``` + +### Step 3: Add graphql-http middleware with createHandler + +Replace it with the `graphql-http` handler using the Express adapter: + +```js +import express from 'express'; +import { createHandler } from 'graphql-http/lib/use/express'; +import { schema } from './schema.js'; + +const app = express(); + +app.all('/graphql', createHandler({ schema })); + +app.listen(4000); +``` + +- Use `app.all()` to allow both `GET` and `POST` requests. +- The handler accepts an options object similar to `express-graphql`. + +### Step 4: Handle context, error formatting, and extensions + +You can provide options like `context`, `rootValue`, and `formatError`: + +```js +app.all('/graphql', createHandler({ + schema, + context: async (req, res) => { + return { user: await authenticate(req) }; + }, + formatError: (error) => ({ + message: error.message, + path: error.path, + }), +})); +``` + +- `context` can be a static object or an async function. +- You can also pass `rootValue`, or extend responses with custom logic. + +### Step 5: Add a GraphQL IDE (optional) + +Unlike `express-graphql`, `graphql-http` does not include a built-in GraphQL IDE. If you want to add one: + +- Use a plugin that serves an interactive GraphQL UI alongside your endpoint +- Or serve a static HTML page that loads your preferred IDE from a CDN + +In either case, make sure to restrict access in production environments. + +### Step 6: Test your setup + +After migrating, verify that your server responds correctly: + +- Send queries and mutations using your preferred client. +- Check for proper HTTP status codes and response shapes. +- If you're using streaming features like `@defer`, ensure your client can handle `multipart/mixed` responses. + +## Best practices + +When migrating from `express-graphql` to `graphql-http`, there are a few key differences and potential pitfalls to keep in mind. These tips can help you avoid common issues and ensure a smoother transition. + +### Be aware of different error behavior + +`graphql-http` follows the GraphQL over HTTP spec closely, which means error formatting and status codes may differ from what you're used to with `express-graphql`. For example: + +- Invalid queries may return a `400 Bad Request` instead of a `200 OK`. +- Errors in parsing or validation are surfaced earlier and more strictly. +- You can customize error output using the `formatError` option, but it must conform to the spec. + +This can affect client expectations if they were relying on `express-graphql`'s more lenient defaults. + +### Consider IDE support in development + +`express-graphql` includes GraphiQL by default in development mode. `graphql-http` does not. + +To restore this functionality, consider: + +- Use a middleware plugin that serves an in-browser IDE. +- Host a static IDE page at a separate endpoint. +- Ensure the IDE is only available in non-production environments. + +### Watch for framework-specific middleware behavior + +Since `graphql-http` is framework-agnostic, it does not handle things like body parsing, CORS, or compression. You'll need to ensure those are handled appropriately by your Express setup: + +```js +import cors from 'cors'; +import express from 'express'; + +app.use(cors()); +app.use(express.json()); +``` + +This gives you more control but requires a bit more setup. + +### Understand streaming and file upload limitations + +`graphql-http` supports streaming via `multipart/mixed`, which enables features like `@defer`. However: + +- Many clients don't yet support this content type. +- File uploads are not built-in, and must be handled outside the core handler. + +Test your client integration carefully if you rely on these features. + +## What's next + +Once you're up and running with `graphql-http`, you can start extending your server with validation rules, monitoring, custom error handling, or alternative transports. For more advanced use cases, consider combining `graphql-http` with tools like [`envelop`](https://the-guild.dev/graphql/envelop) or [`graphql-yoga`](https://the-guild.dev/graphql/yoga-server). + +For details on the GraphQL over HTTP specification, see the [official spec draft](https://graphql.github.io/graphql-over-http/draft/). \ No newline at end of file From f836688b7642048001d590451a137b2c7d16c69c Mon Sep 17 00:00:00 2001 From: sarahxsanders Date: Tue, 10 Jun 2025 19:36:23 -0400 Subject: [PATCH 2/6] feedback --- .../docs/migrating-from-express-graphql.mdx | 63 ++++++++++++++----- 1 file changed, 46 insertions(+), 17 deletions(-) diff --git a/website/pages/docs/migrating-from-express-graphql.mdx b/website/pages/docs/migrating-from-express-graphql.mdx index cd834f6cfa..6973874a72 100644 --- a/website/pages/docs/migrating-from-express-graphql.mdx +++ b/website/pages/docs/migrating-from-express-graphql.mdx @@ -5,13 +5,15 @@ sidebarTitle: Migrate from Express GraphQL # Migrate from Express GraphQL to GraphQL over HTTP -When GraphQL was open-sourced in 2015, `express-graphql` quickly became the -default way to run a GraphQL server in JavaScript. Built as middleware for Express, -it provided a simple and reliable way to serve GraphQL queries using Node.js. +When GraphQL was open-sourced in 2015, `express-graphql` quickly became the standard way to run a GraphQL server in Node.js. +Built as middleware for Express, it offered a simple and reliable development experience. However, it hasn’t received a +feature update since 2018 and is no longer actively maintained. For modern applications, it lacks support for new transport +features, fine-grained request handling, and deployment flexibility. -While `express-graphql` still receives occasional updates for security and spec alignment, it is no longer actively developed. This limits its suitability for projects that need more control over request handling, streaming, or support for modern deployment environments. - -[`graphql-http`](https://github.com/graphql/graphql-http) is a lightweight implementation of the [GraphQL over HTTP specification](https://graphql.github.io/graphql-over-http/draft/). It's framework-agnostic, built to be composable, and easy to integrate into different server environments. Unlike `express-graphql`, it can run in a wide range of environments, not just Express. +[`graphql-http`](https://github.com/graphql/graphql-http) is a lightweight implementation of +the [GraphQL over HTTP specification](https://graphql.github.io/graphql-over-http/draft/). It's framework-agnostic, built to be +composable, and easy to integrate into different server environments. Unlike `express-graphql`, it can run in a wide range of +environments, not just Express. This guide is for developers currently using `express-graphql` who want to modernize their stack, adopt the HTTP spec, or decouple their GraphQL server @@ -40,6 +42,20 @@ Instead of relying on Express, `graphql-http` is built on the standard Web `Requ As GraphQL evolves, tools and platforms increasingly expect spec-compliant behavior. Migration to `graphql-http` helps ensure your server will support future capabilities without relying on workarounds. +### Understand current limitations + +Although `graphql-http` is a strong foundation for modern GraphQL servers, it's important to note what it doesn't include: + +- It doesn't support subscriptions or experimental features like incremental delivery (`@defer` / `@stream`) out of the box. +- These limitations are by design. `graphql-http` strictly adheres to the current +[GraphQL over HTTP specification](https://graphql.github.io/graphql-over-http/draft/), which does +not yet define behavior for those features. +- If your application needs support for subscriptions or live queries, consider using complementary libraries like +[`graphql-ws`](https://github.com/enisdenjo/graphql-ws) or [`graphql-sse`](https://github.com/enisdenjo/graphql-sse). + +These are not limitations unique to `graphql-http`. `express-graphql` does not support these features either, but it's important +to set the right expectations about extensibility. + ## Migration guide The following steps walk through how to migrate an existing `express-graphql` server to use `graphql-http`. The steps assume you already have a working Express app using `express-graphql`. @@ -119,8 +135,13 @@ app.all('/graphql', createHandler({ Unlike `express-graphql`, `graphql-http` does not include a built-in GraphQL IDE. If you want to add one: -- Use a plugin that serves an interactive GraphQL UI alongside your endpoint -- Or serve a static HTML page that loads your preferred IDE from a CDN +- Use a tool like [Ruru](https://www.npmjs.com/package/ruru) to serve an interactive GraphQL UI locally: + + ```bash + npx ruru -SP -p 4001 -e http://localhost:4000/graphql + ``` + +- Or serve a static HTML page that embeds [GraphiQL](https://github.com/graphql/graphiql) from a CDN. In either case, make sure to restrict access in production environments. @@ -130,7 +151,8 @@ After migrating, verify that your server responds correctly: - Send queries and mutations using your preferred client. - Check for proper HTTP status codes and response shapes. -- If you're using streaming features like `@defer`, ensure your client can handle `multipart/mixed` responses. +- If you're experimenting with streaming features like `@defer`, test that your client can handle multipart/mixed responses. +Support for this content type is still limited in many tools. ## Best practices @@ -152,7 +174,7 @@ This can affect client expectations if they were relying on `express-graphql`'s To restore this functionality, consider: -- Use a middleware plugin that serves an in-browser IDE. +- Use a development tool like Ruru to serve an in-browser IDE. - Host a static IDE page at a separate endpoint. - Ensure the IDE is only available in non-production environments. @@ -172,15 +194,22 @@ This gives you more control but requires a bit more setup. ### Understand streaming and file upload limitations -`graphql-http` supports streaming via `multipart/mixed`, which enables features like `@defer`. However: +`graphql-http` aims to support the GraphQL over HTTP spec, including response streaming via `multipart/mixed`. However, +support for features like `@defer` and `@stream` is still evolving. These capabilities are experimental in both `graphql-js` +and `graphql-http`, and may require additional setup. -- Many clients don't yet support this content type. -- File uploads are not built-in, and must be handled outside the core handler. - -Test your client integration carefully if you rely on these features. +- Most GraphQL clients don’t yet support multipart responses. +- Server-side support for streaming may be incomplete or inconsistent. +- If your app relies on incremental delivery, consider using a transport library like +[`graphql-sse`](https://github.com/enisdenjo/graphql-sse) instead. ## What's next -Once you're up and running with `graphql-http`, you can start extending your server with validation rules, monitoring, custom error handling, or alternative transports. For more advanced use cases, consider combining `graphql-http` with tools like [`envelop`](https://the-guild.dev/graphql/envelop) or [`graphql-yoga`](https://the-guild.dev/graphql/yoga-server). +For advanced customization, consider integrating `graphql-http` with [Envelop](https://the-guild.dev/graphql/envelop), a +plugin-based GraphQL execution layer. + +If you’re looking for a batteries-included solution that includes transport, subscriptions, and a GraphQL IDE, +[GraphQL Yoga](https://the-guild.dev/graphql/yoga-server) might be a better fit. It builds on Envelop and provides its +own transport layer, separate from `graphql-http`. -For details on the GraphQL over HTTP specification, see the [official spec draft](https://graphql.github.io/graphql-over-http/draft/). \ No newline at end of file +For a list of other spec-compliant server implementations, see the [`graphql-http` server list](https://github.com/graphql/graphql-http?tab=readme-ov-file#servers). From ed02dbb6bc36c055b9a5a39c7077def336794354 Mon Sep 17 00:00:00 2001 From: Benjie Date: Thu, 12 Jun 2025 15:42:00 +0100 Subject: [PATCH 3/6] Apply suggestions from code review Co-authored-by: Yaacov Rydzinski --- website/pages/docs/migrating-from-express-graphql.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/website/pages/docs/migrating-from-express-graphql.mdx b/website/pages/docs/migrating-from-express-graphql.mdx index 6973874a72..61acc0b590 100644 --- a/website/pages/docs/migrating-from-express-graphql.mdx +++ b/website/pages/docs/migrating-from-express-graphql.mdx @@ -21,9 +21,9 @@ from Express. ## Benefits of migrating -### `express-graphql` has limited future support +### `express-graphql` is no longer supported -The library is no longer under active development. While it is still maintained for security and spec compliance, it is not evolving with the GraphQL ecosystem. This makes it less flexible for long-term projects. +The library has not received updates for some time. As a deprecated package, it is not evolving with the GraphQL ecosystem. This makes it less flexible for long-term projects. ### `graphql-http` is spec-compliant by default @@ -194,9 +194,9 @@ This gives you more control but requires a bit more setup. ### Understand streaming and file upload limitations -`graphql-http` aims to support the GraphQL over HTTP spec, including response streaming via `multipart/mixed`. However, -support for features like `@defer` and `@stream` is still evolving. These capabilities are experimental in both `graphql-js` -and `graphql-http`, and may require additional setup. +`graphql-http` aims to support the GraphQL over HTTP spec, including eventually supporting response streaming. However, +support for features like `@defer` and `@stream` is still evolving. These capabilities are experimental in `graphql-js` +and not yet supported by `graphql-http`. - Most GraphQL clients don’t yet support multipart responses. - Server-side support for streaming may be incomplete or inconsistent. From b51a59d8be5722fd06c8151465b565de7ab6f3e8 Mon Sep 17 00:00:00 2001 From: Benjie Date: Thu, 12 Jun 2025 15:58:30 +0100 Subject: [PATCH 4/6] Apply suggestions from code review --- .../docs/migrating-from-express-graphql.mdx | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/website/pages/docs/migrating-from-express-graphql.mdx b/website/pages/docs/migrating-from-express-graphql.mdx index 61acc0b590..2c6c0b6e44 100644 --- a/website/pages/docs/migrating-from-express-graphql.mdx +++ b/website/pages/docs/migrating-from-express-graphql.mdx @@ -151,8 +151,8 @@ After migrating, verify that your server responds correctly: - Send queries and mutations using your preferred client. - Check for proper HTTP status codes and response shapes. -- If you're experimenting with streaming features like `@defer`, test that your client can handle multipart/mixed responses. -Support for this content type is still limited in many tools. +- Check the GraphQL `context` and related variables are populated correctly and + that your dataloaders and authorization logic are functioning as expected. ## Best practices @@ -205,11 +205,9 @@ and not yet supported by `graphql-http`. ## What's next -For advanced customization, consider integrating `graphql-http` with [Envelop](https://the-guild.dev/graphql/envelop), a -plugin-based GraphQL execution layer. - -If you’re looking for a batteries-included solution that includes transport, subscriptions, and a GraphQL IDE, -[GraphQL Yoga](https://the-guild.dev/graphql/yoga-server) might be a better fit. It builds on Envelop and provides its -own transport layer, separate from `graphql-http`. - -For a list of other spec-compliant server implementations, see the [`graphql-http` server list](https://github.com/graphql/graphql-http?tab=readme-ov-file#servers). +`graphql-http` is the reference implementation of the GraphQL-over-HTTP specification, +but there are many other servers you can use to serve your GraphQL API, each with +different features and trade-offs. For a list of other spec-compliant server +implementations see the +[`graphql-http` server list](https://github.com/graphql/graphql-http?tab=readme-ov-file#servers), and don't forget to check out the +[Tools and Libraries page on graphql.org](https://graphql.org/community/tools-and-libraries/?tags=server_javascript). From 42f22ce5a42ce11bdee7bdbba807f4ff29b3794b Mon Sep 17 00:00:00 2001 From: sarahxsanders Date: Thu, 19 Jun 2025 21:18:07 -0400 Subject: [PATCH 5/6] resolve feedback --- .../docs/migrating-from-express-graphql.mdx | 49 ++++++++++--------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/website/pages/docs/migrating-from-express-graphql.mdx b/website/pages/docs/migrating-from-express-graphql.mdx index 6973874a72..41d9a36cae 100644 --- a/website/pages/docs/migrating-from-express-graphql.mdx +++ b/website/pages/docs/migrating-from-express-graphql.mdx @@ -73,7 +73,7 @@ Before you begin, make sure you have: Install the core `graphql-http` package along with its Express adapter: ```bash -npm install graphql graphql-http @graphql-http/express +npm install graphql graphql-http ``` The `graphql` package is a peer dependency of `graphql-http`, and must be installed if it isn't already. @@ -109,29 +109,41 @@ app.listen(4000); ``` - Use `app.all()` to allow both `GET` and `POST` requests. -- The handler accepts an options object similar to `express-graphql`. +- The handler accepts an options object for GraphQL-specific settings like `schema`, +`rootValue`, and `context`, but doesn’t handle server-level features such as middleware +or request preprocessing like `express-graphql` did. ### Step 4: Handle context, error formatting, and extensions You can provide options like `context`, `rootValue`, and `formatError`: ```js +import { GraphQLError } from 'graphql'; + app.all('/graphql', createHandler({ schema, context: async (req, res) => { - return { user: await authenticate(req) }; + const user = await authenticate(req); + return { user }; }, - formatError: (error) => ({ - message: error.message, - path: error.path, - }), + formatError: (error) => + new GraphQLError(error.message, { + nodes: error.nodes, + path: error.path, + extensions: { + code: 'INTERNAL_SERVER_ERROR', + timestamp: Date.now(), + }, + }), })); ``` - `context` can be a static object or an async function. -- You can also pass `rootValue`, or extend responses with custom logic. +- You can also pass `rootValue` or other GraphQL-specific options. +- To modify the HTTP response, such as adding headers or extensions, you’ll need +to do that outside of graphql-http, using Express middleware or route handlers. -### Step 5: Add a GraphQL IDE (optional) +### Step 5: Add a GraphQL IDE Unlike `express-graphql`, `graphql-http` does not include a built-in GraphQL IDE. If you want to add one: @@ -168,16 +180,6 @@ When migrating from `express-graphql` to `graphql-http`, there are a few key dif This can affect client expectations if they were relying on `express-graphql`'s more lenient defaults. -### Consider IDE support in development - -`express-graphql` includes GraphiQL by default in development mode. `graphql-http` does not. - -To restore this functionality, consider: - -- Use a development tool like Ruru to serve an in-browser IDE. -- Host a static IDE page at a separate endpoint. -- Ensure the IDE is only available in non-production environments. - ### Watch for framework-specific middleware behavior Since `graphql-http` is framework-agnostic, it does not handle things like body parsing, CORS, or compression. You'll need to ensure those are handled appropriately by your Express setup: @@ -198,10 +200,11 @@ This gives you more control but requires a bit more setup. support for features like `@defer` and `@stream` is still evolving. These capabilities are experimental in both `graphql-js` and `graphql-http`, and may require additional setup. -- Most GraphQL clients don’t yet support multipart responses. -- Server-side support for streaming may be incomplete or inconsistent. -- If your app relies on incremental delivery, consider using a transport library like -[`graphql-sse`](https://github.com/enisdenjo/graphql-sse) instead. +- Some GraphQL clients have begun adding support for multipart responses, but broad adoption is still evolving. +- `graphql-http` does not support streaming features such as `@defer` or `@stream`, as these are not part of the +current GraphQL over HTTP specification. +- If your app relies on incremental delivery, use a transport library like [`graphql-sse`](https://github.com/enisdenjo/graphql-sse), +but note that it replaces `graphql-http` and must be used as your server handler. ## What's next From 5fb03dcab684c047cbf4dd1707162757429b6c28 Mon Sep 17 00:00:00 2001 From: sarahxsanders Date: Thu, 19 Jun 2025 21:19:48 -0400 Subject: [PATCH 6/6] cspell.yml file --- cspell.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/cspell.yml b/cspell.yml index fa53d1eb2d..b118f7e130 100644 --- a/cspell.yml +++ b/cspell.yml @@ -39,6 +39,7 @@ overrides: - Graphile - precompiled - debuggable + - dataloaders ignoreRegExpList: - u\{[0-9a-f]{1,8}\}