Custom Code Outbound

Add your own custom policy coded in TypeScript. See below for more details on how to build your own policy.

Configuration#

{
  "name": "my-custom-code-outbound-policy",
  "policyType": "custom-code-outbound",
  "handler": {
    "export": "default",
    "module": "$import(./modules/YOUR_MODULE)",
    "options": {
      "config1": "YOUR_VALUE",
      "config2": true
    }
  }
}

Options#

  • name the name of your policy instance. This is used as a reference in your routes.
  • policyType the identifier of the policy. This is used by the Zuplo UI. Value should be custom-code-outbound.
  • handler/export The name of the exported type. Value should be YOUR_EXPORT.
  • handler/module the module containing the policy. Value should be $import(./modules/YOUR_MODULE).
  • handler/options The options for this policy:
    Tip

    The outbound policy will only execute if the response status code is 'ok' (e.g. response.ok === true or the status code is 200-299) - see response.ok on MDN.

    Writing A Policy

    Custom policies can be written to extend the functionality of your gateway. This document is about outbound policies that can intercept the request and, if required, modify it before passing down the chain.

    The outbound custom policy is similar to the inbound custom policy but also accepts a Response parameter. The outbound policy must return a valid Response (or throw an error, which will result in a 500 Internal Server Error for your consumer, not recommended).

    Tip

    Note that both ZuploRequest and Response are based on the web standards Request and Response. ZuploRequest adds a few additional properties for convenience, like user and params.

    export type OutboundPolicyHandler<TOptions = any> = (
      response: Response,
      request: ZuploRequest,
      context: ZuploContext,
      options: TOptions,
      policyName: string,
    ) => Promise<ZuploRequest | Response>;

    A common use case for outbound policies is to change the body of the response. In this example, we'll imagine we are proxying the /todos example api at https://jsonplaceholder.typicode.com/todos.

    The format of the /todos response looks like this

    [
      {
        "userId": 1,
        "id": 1,
        "title": "delectus aut autem",
        "completed": false
      },
      {
        "userId": 1,
        "id": 2,
        "title": "quis ut nam facilis et officia qui",
        "completed": false
      },

    We will write an outbound policy that does two things

    1. Removes the userId property
    2. Adds a new outbound header called color

    Here's the code:

    export default async function (
      response: Response,
      request: ZuploRequest,
      context: ZuploContext,
      options: any,
      policyName: string,
    ) {
      if (response.status !== 200) {
        // if we get an unexpected response code, something went wrong, just let the response flow
        return response;
      }
     
      const data = (await response.json()) as any[]; // we know this is JSON and an array
      data.forEach((item) => {
        delete item.userId;
      });
     
      // create a new response
      const newResponse = new Response(JSON.stringify(data), {
        status: response.status,
        headers: response.headers,
      });
     
      // let's add an additional header as an example, for good measure
      newResponse.headers.set("color", "yellow");
     
      return newResponse;
    }
    Tip

    Note, that because we're not using the original response here (we just use the new one called newResponse) we didn't need to clone the original response before reading the body with .json(). If you need to read the body and use that same instance you must first clone() to avoid runtime errors such as "Body is unusable".

    Adding headers

    Note if you just need to add headers, it more efficient not read the body stream and reuse it, e.g.

    export default async function (
      response: Response,
      request: ZuploRequest,
      context: ZuploContext,
      options: any,
      policyName: string,
    ) {
      // create a new response
      const newResponse = new Response(response.body, {
        status: response.status,
        headers: response.headers,
      });
     
      // let's add an additional header as an example, for good measure
      newResponse.headers.set("color", "yellow");
     
      return newResponse;
    }

    Was this article helpful?

    Do you have any questions?Contact us
    Check out ourproduct changelog