WHAT YOU'LL LEARN
  • how to create a custom HTTP route handler with dependency injection
  • how to register the route in webiny.config.tsx
  • why a redeployment is required when adding routes

Overview
anchor

The Api.Route extension lets you register custom HTTP routes on the Webiny API Gateway and GraphQL Lambda. Route handlers are plain TypeScript classes with full dependency injection support — the same DI pattern used throughout the rest of the API.

Unlike pure application code changes, adding a route modifies both the runtime routing layer (Fastify) and the cloud infrastructure (API Gateway). A redeployment with yarn webiny deploy api is required whenever you add, change, or remove a route.

Creating a Route Handler
anchor

Create a TypeScript file in your extensions/ directory and implement Route.Interface:

extensions/MyApiRoute.ts
import { Logger, Route } from "webiny/api";

class MyApiRouteImpl implements Route.Interface {
  public constructor(private logger: Logger.Interface) {}

  public async execute(request: Route.Request, reply: Route.Reply): Promise<void> {
    this.logger.info("Handling request", { url: request.url });
    return reply.send({ message: "Hello from my custom route!" });
  }
}

export default Route.createImplementation({
  implementation: MyApiRouteImpl,
  dependencies: [Logger]
});

Registering the Route
anchor

Add Api.Route to webiny.config.tsx with the method, path, and src props:

webiny.config.tsx
import React from "react";
import { Api } from "webiny/extensions";

export const Extensions = () => {
  return (
    <>
      {/* ... other extensions */}
      <Api.Route method={"GET"} path={"/my-api-route"} src={"/extensions/MyApiRoute.ts"} />
    </>
  );
};

The src path must include the .ts extension — omitting it will cause a build failure.

Props Reference
anchor

PropTypeRequiredDescription
pathstringYesRoute path, must start with /. Use {paramName} for path parameters.
methodstringYesHTTP method: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, or ANY
srcstringYesPath to the handler file, including the .ts extension
routeNamestringNoPulumi resource name (kebab-case). Auto-derived from path and method if omitted.

Use ANY as the method to match all HTTP methods on a given path.

Deploying the Route
anchor

Adding, changing, or removing a route requires a full API redeployment. Route registration modifies API Gateway configuration — it is not a pure application code change.

After registering a route in webiny.config.tsx, deploy the API:

yarn webiny deploy api

During development, use watch mode for automatic redeployment on code changes:

yarn webiny watch api

Watch mode does not re-provision infrastructure. If you change the path or method in webiny.config.tsx, run yarn webiny deploy api explicitly.

Working With Path Parameters and Request Data
anchor

Use {paramName} in the path to capture path parameters, then access them via request.params:

extensions/GetOrderRoute.ts
import { Logger, Route } from "webiny/api";

interface OrderParams {
  orderId: string;
}

class GetOrderRouteImpl implements Route.Interface {
  public constructor(private logger: Logger.Interface) {}

  public async execute(request: Route.Request, reply: Route.Reply): Promise<void> {
    const { orderId } = request.params as OrderParams;
    const { limit } = request.query as { limit?: string };

    this.logger.info("Fetching order", { orderId });

    return reply.code(200).send({ orderId, limit: limit ?? "10" });
  }
}

export default Route.createImplementation({
  implementation: GetOrderRouteImpl,
  dependencies: [Logger]
});
webiny.config.tsx
<Api.Route method={"GET"} path={"/orders/{orderId}"} src={"/extensions/GetOrderRoute.ts"} />

Route.Request
anchor

PropertyTypeDescription
bodyunknownParsed request body
headersRecord<string, string \| string[] \| undefined>Request headers
methodstringHTTP method
urlstringFull request URL
paramsunknownPath parameters (e.g. { orderId: "abc" })
queryunknownQuery string parameters

Route.Reply
anchor

MethodDescription
reply.send(data?)Send the response body
reply.code(statusCode)Set the HTTP status code (chainable)
reply.header(key, value)Set a response header (chainable)

Methods are chainable:

return reply.code(201).header("X-Request-Id", "abc123").send({ created: true });