graphqlUploadExpress.js 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. // @ts-check
  2. "use strict";
  3. const defaultProcessRequest = require("./processRequest.js");
  4. /**
  5. * Creates [Express](https://expressjs.com) middleware that processes incoming
  6. * [GraphQL multipart requests](https://github.com/jaydenseric/graphql-multipart-request-spec)
  7. * using {@linkcode processRequest}, ignoring non multipart requests. It sets
  8. * the request `body` to be similar to a conventional GraphQL POST request for
  9. * following GraphQL middleware to consume.
  10. * @param {import("./processRequest.js").ProcessRequestOptions & {
  11. * processRequest?: import("./processRequest.js").ProcessRequestFunction
  12. * }} options Options.
  13. * @returns Express middleware.
  14. * @example
  15. * Basic [`express-graphql`](https://npm.im/express-graphql) setup:
  16. *
  17. * ```js
  18. * const express = require("express");
  19. * const graphqlHTTP = require("express-graphql");
  20. * const graphqlUploadExpress = require("graphql-upload/graphqlUploadExpress.js");
  21. * const schema = require("./schema.js");
  22. *
  23. * express()
  24. * .use(
  25. * "/graphql",
  26. * graphqlUploadExpress({ maxFileSize: 10000000, maxFiles: 10 }),
  27. * graphqlHTTP({ schema })
  28. * )
  29. * .listen(3000);
  30. * ```
  31. */
  32. function graphqlUploadExpress({
  33. processRequest = defaultProcessRequest,
  34. ...processRequestOptions
  35. } = {}) {
  36. /**
  37. * [Express](https://expressjs.com) middleware that processes incoming
  38. * [GraphQL multipart requests](https://github.com/jaydenseric/graphql-multipart-request-spec)
  39. * using {@linkcode processRequest}, ignoring non multipart requests. It sets
  40. * the request `body` to be similar to a conventional GraphQL POST request for
  41. * following GraphQL middleware to consume.
  42. * @param {import("express").Request} request
  43. * @param {import("express").Response} response
  44. * @param {import("express").NextFunction} next
  45. */
  46. function graphqlUploadExpressMiddleware(request, response, next) {
  47. if (!request.is("multipart/form-data")) return next();
  48. const requestEnd = new Promise((resolve) => request.on("end", resolve));
  49. const { send } = response;
  50. // @ts-ignore Todo: Find a less hacky way to prevent sending a response
  51. // before the request has ended.
  52. response.send =
  53. /** @param {Array<unknown>} args */
  54. (...args) => {
  55. requestEnd.then(() => {
  56. response.send = send;
  57. response.send(...args);
  58. });
  59. };
  60. processRequest(request, response, processRequestOptions)
  61. .then((body) => {
  62. request.body = body;
  63. next();
  64. })
  65. .catch((error) => {
  66. if (error.status && error.expose) response.status(error.status);
  67. next(error);
  68. });
  69. }
  70. return graphqlUploadExpressMiddleware;
  71. }
  72. module.exports = graphqlUploadExpress;