Express Partial Response Middleware

raw JSON →
1.0.4 verified Thu Apr 23 auth: no javascript maintenance

express-partial-response is an Express.js middleware designed to filter parts of JSON responses based on a `fields` query-string parameter. It mimics the "Partial Response" feature found in Google APIs, allowing clients to request only a subset of data from an API endpoint, thereby reducing bandwidth and processing on the client side. The current stable version is 1.0.4. The project appears to be in a maintenance state, with no recent major updates mentioned, suggesting a stable and complete feature set rather than active development. Its core functionality is powered by the `json-mask` library, which handles the actual JSON object filtering according to the specified field syntax. This middleware differentiates itself by providing a direct, out-of-the-box integration for Express applications, simplifying the implementation of partial responses without requiring manual integration of `json-mask` into every route.

error TypeError: app.use() requires a middleware function but got a Object
cause The `partialResponse` function was passed directly to `app.use()` without being called first, meaning `app.use()` received the factory function itself rather than the middleware instance.
fix
Call the partialResponse function to get the actual middleware. Correct usage is app.use(partialResponse()); or app.use(partialResponse({ options }));.
error Response is not filtered as expected (or is empty) when using the 'fields' query parameter.
cause The `fields` query string parameter contains an incorrect or malformed `json-mask` syntax, causing the underlying `json-mask` library to either filter incorrectly or return an empty object.
fix
Double-check the fields query parameter against the json-mask syntax documentation. Common mistakes include typos, incorrect nesting parentheses, or missing commas.
error ReferenceError: require is not defined (in an ESM context)
cause Attempting to use `const partialResponse = require('express-partial-response');` in an ES Module (`type: "module"` in `package.json` or `.mjs` file).
fix
This package is CJS-only. You must either use a CommonJS environment, or if you must use ESM, use dynamic import() (e.g., const partialResponse = await import('express-partial-response'); const middleware = partialResponse.default();) or a build tool that handles CJS-to-ESM conversion.
gotcha The syntax for the `fields` query parameter is handled by the underlying `json-mask` library. Developers must refer to `json-mask`'s documentation for complex filtering patterns, nested fields, and array handling, as `express-partial-response` simply passes the string.
fix Consult the `json-mask` library documentation (e.g., `https://github.com/nemtsov/json-mask#syntax`) for the correct and full syntax of the `fields` parameter.
gotcha This middleware is designed exclusively for JSON responses. If applied to routes that return other content types (like HTML, plain text, or files) and `res.json()` is not eventually called, the middleware will have no effect or might lead to unexpected behavior.
fix Ensure `express-partial-response` is only used on routes that are expected to respond with JSON data. Consider applying it selectively using route-specific middleware if some routes serve non-JSON content.
gotcha As a general principle with field filtering, ensure that the fields available for filtering do not inadvertently expose sensitive data that should otherwise be protected. While the middleware filters based on client input, the original data might contain sensitive fields that could be exposed if requested via a wildcard or an overly broad mask. The `json-mask` library itself does not offer mechanisms for field-level access control.
fix Implement robust server-side authorization and data serialization logic to explicitly omit sensitive fields before they reach the `res.json()` call, or before `express-partial-response` processes them. Do not rely solely on client-requested field masks for security.
gotcha This package is written in CommonJS (CJS) and does not officially support ES Modules (ESM) directly. Attempting to use `import` statements in an ESM project will lead to errors.
fix If working in a pure ESM project, you might need to use dynamic `import()` or configure your bundler to handle CJS modules. Alternatively, ensure your project is configured for CommonJS or use `require()` syntax.
npm install express-partial-response
yarn add express-partial-response
pnpm add express-partial-response

This quickstart demonstrates how to set up `express-partial-response` middleware with an Express application, creating two example routes (`/users/:id` and `/products`) that return JSON data. It shows how the middleware automatically filters the response based on the `?fields=` query parameter, illustrating various `json-mask` syntax examples with `curl` commands.

const express = require('express');
const partialResponse = require('express-partial-response');
const app = express();

// Apply the partial response middleware globally
app.use(partialResponse({ query: 'fields' })); // Default query param is 'fields'

app.get('/users/:id', (req, res) => {
  const userId = req.params.id;
  const users = [
    {
      id: '1',
      firstName: 'Mohandas',
      lastName: 'Gandhi',
      email: 'm.gandhi@example.com',
      addresses: [{ street: '123 Peace Rd', city: 'Ahimsa', country: 'India' }],
      aliases: [
        { firstName: 'Mahatma', lastName: 'Gandhi' },
        { firstName: 'Bapu', title: 'Father of the Nation' }
      ],
      secretInfo: 'Top Secret - Only for internal use'
    },
    {
      id: '2',
      firstName: 'Nelson',
      lastName: 'Mandela',
      email: 'n.mandela@example.com',
      addresses: [{ street: '456 Freedom St', city: 'Ubuntu', country: 'South Africa' }],
      aliases: [
        { firstName: 'Madiba', lastName: 'Mandela' }
      ],
      secretInfo: 'Top Secret - Only for internal use'
    }
  ];
  const user = users.find(u => u.id === userId);
  if (user) {
    res.json(user);
  } else {
    res.status(404).json({ message: 'User not found' });
  }
});

app.get('/products', (req, res) => {
  const products = [
    { id: 'a1', name: 'Laptop', price: 1200, category: 'Electronics', description: 'Powerful laptop', supplier: 'TechCorp' },
    { id: 'b2', name: 'Mouse', price: 25, category: 'Electronics', description: 'Wireless mouse', supplier: 'AccessoryCo' }
  ];
  res.json(products);
});

const port = process.env.PORT ?? 4000;
app.listen(port, () => {
  console.log(`Server running on http://localhost:${port}`);
  console.log('\nTry these examples:');
  console.log(`- Get user 1's first name and alias first names: curl 'http://localhost:${port}/users/1?fields=firstName,aliases(firstName)'`);
  console.log(`- Get user 2's id and email: curl 'http://localhost:${port}/users/2?fields=id,email'`);
  console.log(`- Get product names and prices: curl 'http://localhost:${port}/products?fields=name,price'`);
  console.log(`- Get all fields for user 1 (no 'fields' param): curl 'http://localhost:${port}/users/1'`);
});