Back to all articles
API Best Practices

Deprecating Node JS REST APIs in 6 Frameworks

October 28, 2024

Deprecating an API is never is easy (in fact we wrote a full guide on API deprecation) - but many popular Node JS frameworks can ease the pain. Deprecating an API endpoint typically involves notifying consumers that the endpoint is outdated and will be removed in the future. As a developer, you can communicate this two ways

  1. Through API documentation (an OpenAPI spec generated from your framework of choice).
  2. By sending the HTTP Deprecation header.

Here's how different Node.js frameworks handle API deprecation:

1. Fastify

Support Level: Built-in Support via Plugins

Fastify allows you to set custom metadata for routes, and when combined with the fastify-swagger plugin, you can mark routes as deprecated in your OpenAPI documentation.

Fastify API Deprecation Example

Generate an OpenAPI file using fastify-swagger, and use the deprecated property to mark the API endpoint as deprecated . Additionally, send the deprecation header back in the route's implementation.

TypeScripttypescript
const fastify = require("fastify")();
fastify.register(require("fastify-swagger"), {
  exposeRoute: true,
  routePrefix: "/documentation",
  openapi: {
    openapi: "3.0.0",
    info: {
      title: "API Documentation",
      version: "1.0.0",
    },
  },
});

fastify.get(
  "/v1/old-endpoint",
  {
    schema: {
      deprecated: true,
      summary: "Deprecated endpoint",
      description:
        "This endpoint is deprecated and will be removed in the future.",
      response: {
        200: {
          type: "object",
          properties: {
            message: { type: "string" },
          },
        },
      },
    },
  },
  async (request, reply) => {
    // Friday, June 30, 2023 at 23:59:59 UTC in Unix time
    reply.header("Deprecation", "@1688169599");
    return { message: "This endpoint is deprecated." };
  },
);

fastify.listen(3000, (err) => {
  if (err) throw err;
  console.log("Server running on port 3000");
});

2. Express JS

Support Level: Manual Implementation

Express.js doesn't have built-in support for deprecating APIs, but you can implement deprecation logic manually.

Express JS Deprecation Header Example

  • Adding the header at the route level:

    You can add the header directly in your route's response.

    TypeScripttypescript
    const express = require("express");
    const app = express();
    
    app.get("/v1/old-endpoint", (req, res) => {
      res.set("Deprecation", "@1688169599");
      res.send({ message: "This endpoint is deprecated." });
    });
    
    app.listen(3000, () => console.log("Server running on port 3000"));
  • Using Middleware:

    If you are deprecating multiple endpoints, you can use middleware to maximize code reuse.

    TypeScripttypescript
    function deprecationMiddleware(req, res, next) {
      res.set("Deprecation", "@1688169599");
      next();
    }
    
    app.use("/v1/old-endpoint", deprecationMiddleware, (req, res) => {
      res.send({ message: "This endpoint is deprecated." });
    });
    
    app.use("/v1/another-old-endpoint", deprecationMiddleware, (req, res) => {
      res.send({ message: "This endpoint is deprecated." });
    });

Express JS OpenAPI Deprecation Example

You can use the swagger-jsdoc package to generate an OpenAPI file from your routes, and mark them deprecated. You can additionally use swagger-ui-express to serve your docs.

TypeScripttypescript
const express = require("express");
const swaggerJsdoc = require("swagger-jsdoc");
const swaggerUi = require("swagger-ui-express");

const app = express();

const swaggerDefinition = {
  openapi: "3.0.0",
  info: {
    title: "API Documentation",
    version: "1.0.0",
  },
};

const options = {
  swaggerDefinition,
  apis: ["./index.js"], // Path to the API docs
};

const swaggerSpec = swaggerJsdoc(options);

app.use("/docs", swaggerUi.serve, swaggerUi.setup(swaggerSpec));

// In index.js

/**
 * @openapi
 * /v1/old-endpoint:
 *   get:
 *     deprecated: true
 *     summary: Deprecated endpoint
 *     description: This endpoint is deprecated and will be removed in the future.
 *     responses:
 *       200:
 *         description: Successful response
 */
app.get("/v1/old-endpoint", (req, res) => {
  res.set("Deprecation", "@1688169599");
  res.send({ message: "This endpoint is deprecated." });
});

app.listen(3000, () => console.log("Server running on port 3000"));

3. NestJS

Support Level: Built-in Support via Decorators

NestJS is a progressive Node.js framework that uses decorators and metadata, making it easy to mark endpoints as deprecated. With the @nestjs/swagger package, you can integrate Swagger/OpenAPI and use the @ApiOperation() decorator.

NestJS API Deprecation Example

Set the @ApiOperation({ deprecated: true }) directive to handle updating your OpenAPI docs and the @Header("Deprecation", "@1688169599") directive will return the deprecation header for you.

TypeScripttypescript
import { Controller, Get, Header } from "@nestjs/common";
import { ApiOperation, ApiTags } from "@nestjs/swagger";

@ApiTags("API")
@Controller("api")
export class ApiController {
  @Get("v1/old-endpoint")
  @ApiOperation({ deprecated: true })
  @Header("Deprecation", "@1688169599")
  getOldEndpoint() {
    return { message: "This endpoint is deprecated." };
  }
}

4. Hapi.js

Support Level: Built-in Support via Route Options

Hapi.js allows you to set route-specific metadata, including marking routes as deprecated, especially when using the hapi-swagger plugin for documentation.

Hapi.js API Deprecation Example

Simply use the top-level deprecated property to update your OpenAPI, and set the deprecation header in your route's response.

TypeScripttypescript
const Hapi = require("@hapi/hapi");
const Inert = require("@hapi/inert");
const Vision = require("@hapi/vision");
const HapiSwagger = require("hapi-swagger");

const server = Hapi.server({
  port: 3000,
  host: "localhost",
});

const init = async () => {
  await server.register([
    Inert,
    Vision,
    {
      plugin: HapiSwagger,
      options: {
        info: {
          title: "API Documentation",
          version: "1.0.0",
        },
      },
    },
  ]);

  server.route({
    method: "GET",
    path: "/v1/old-endpoint",
    options: {
      description: "Deprecated endpoint",
      notes: "This endpoint is deprecated and will be removed in the future.",
      tags: ["api", "deprecated"],
      plugins: {
        "hapi-swagger": {
          deprecated: true,
        },
      },
      handler: (request, h) => {
        const response = h.response({
          message: "This endpoint is deprecated.",
        });
        response.header("Deprecation", "@1688169599");
        return response;
      },
    },
  });

  await server.start();
  console.log("Server running on %s", server.info.uri);
};

init();

5. Restify

Support Level: Manual Implementation

Restify is focused on building RESTful APIs and allows for middleware and custom headers, but doesn't have built-in deprecation support. As far as I can tell, there isn't a widely accepted OpenAPI/Swagger generator either.

Restify API Deprecation Example

This is pretty obvious, but simply return the deprecation header via res.header.

TypeScripttypescript
const restify = require("restify");

const server = restify.createServer();

server.get("/v1/old-endpoint", (req, res, next) => {
  res.header("Deprecation", "@1688169599");
  res.send({ message: "This endpoint is deprecated." });
  next();
});

server.listen(3000, () => {
  console.log("%s listening at %s", server.name, server.url);
});

6. Koa.js

Support Level: Manual Implementation

Koa.js allows you to set response headers and create middleware but doesn't have built-in support for deprecation. I scoured NPM but couldn't find any modules for OpenAPI generation from Koa - but I did find 2 solutions that might work for you.

  1. koa-swagger-decorator: A library that only supports OpenAPI 2.0 (which does have a deprecated property)
  2. Use Tsoa over your Koa API: You can read this awesome guide

Koa.js API Deprecation Example

In case you don't want/care about OpenAPI support, you can just send the deprecation header back.

TypeScripttypescript
const Koa = require("koa");
const app = new Koa();

app.use(async (ctx, next) => {
  if (ctx.path === "/v1/old-endpoint") {
    ctx.set("Deprecation", "@1688169599");
    ctx.body = { message: "This endpoint is deprecated." };
  } else {
    await next();
  }
});

app.listen(3000, () => {
  console.log("Server running on port 3000");
});

Takeaways

Deprecating API endpoints requires a surprising amount of manual effort in most Node JS frameworks - and deprecating an entire API is tedious in all frameworks. Here's my recommendations:

  • Utilizing Middleware: Utilize middleware to set deprecation headers consistently. This seems to be the only way to "deprecate" an entire API in most frameworks.
  • Consider Frameworks with OpenAPI Support: It might be time to ditch legacy frameworks that lack OpenAPI support - your users will thank you. The irony is that you won't have an easy way to deprecate these APIs as you migrate!
Tags:#API Best Practices#API Lifecycle Management#Tutorial#Node.js

Related Articles

Continue learning from the Zuplo Learning Center.

API Key Authentication

How to Implement API Key Authentication: A Complete Guide

Learn how to implement API key authentication from scratch — generation, secure storage, validation, rotation, and per-key rate limiting with practical code examples.

API Documentation

Developer Portal Comparison: Customization, Documentation, and Self-Service

Compare developer portal platforms — Zuplo/Zudoku, ReadMe, Redocly, Stoplight, and SwaggerHub — across customization, auto-generated docs, self-service API keys, and theming.

On this page

1. Fastify2. Express JS3. NestJS4. Hapi.js5. Restify6. Koa.jsTakeaways

Scale your APIs with
confidence.

Start for free or book a demo with our team.
Book a demoStart for Free
SOC 2 TYPE 2High Performer Spring 2025Momentum Leader Spring 2025Best Estimated ROI Spring 2025Easiest To Use Spring 2025Fastest Implementation Spring 2025

Get Updates From Zuplo

Zuplo logo
© 2026 zuplo. All rights reserved.
Products & Features
API ManagementAI GatewayMCP ServersMCP GatewayDeveloper PortalRate LimitingOpenAPI NativeGitOpsProgrammableAPI Key ManagementMulti-cloudAPI GovernanceMonetizationSelf-Serve DevX
Developers
DocumentationBlogLearning CenterCommunityChangelogIntegrations
Product
PricingSupportSign InCustomer Stories
Company
About UsMedia KitCareersStatusTrust & Compliance
Privacy PolicySecurity PoliciesTerms of ServiceTrust & Compliance
Docs
Pricing
Sign Up
Login
ContactBook a demoFAQ
Zuplo logo
DocsPricingSign Up
Login