# Health Check Handler

Part of running a reliable API Gateway is ensuring that the service is healthy
and available. With Zuplo, it's easy to set up a health check endpoint that can
be used to ensure the health of both your Zuplo Gateway and your backend (as
well as the connectivity between them).

A typical health check endpoint on your API Gateway will exercise some of the
most important policies (such as authentication) and then make a simple request
to your backend to ensure that it's reachable and functioning.

## Setting up a Health Check Handler

To set up a health check handler, you will need to create a new route in your
Zuplo Gateway. This route will be used to handle health check requests.

You'll create a new route with the path `/health` and the method `GET`. In your
OpenAPI file this would look like:

```json title="config/routes.oas.json"
{
  "paths": {
    "/health": {
      "get": {
        "summary": "Health Check",
        "description": "Checks the health of the API Gateway and backend.",
        "responses": {
          "200": {
            "description": "OK"
          },
          "503": {
            "description": "Service Unavailable"
          }
        },
        "x-zuplo-route": {
          "corsPolicy": "anything-goes",
          "handler": {
            "export": "default",
            "module": "$import(./modules/health)"
          },
          "policies": {
            "inbound": ["my-auth-policy"]
          }
        }
      }
    }
  }
}
```

Next, you'll create a custom handler module that will be used to process the
health check requests. This module will make a simple request to your backend to
ensure that it's reachable and functioning. If you have multiple backend
services you can check each of them.

```ts title="modules/health.ts"
import { ZuploContext, ZuploRequest, ZuploResponse } from "@zuplo/runtime";

export default async function handler(
  request: ZuploRequest,
  context: ZuploContext,
): Promise<ZuploResponse> {
  try {
    // Make a simple request to the backend to check its health
    const responses = await Promise.allSettled([
      fetch("https://backend-1.example.com/health", {
        method: "GET",
        headers: {
          "Content-Type": "application/json",
        },
      }),
      fetch("https://backend-2.example.com/health", {
        method: "GET",
        headers: {
          "Content-Type": "application/json",
        },
      }),
    ]);
    const backendResponse = responses.find(
      (res) => res.status === "fulfilled",
    ) as PromiseFulfilledResult<Response> | undefined;
    if (!backendResponse) {
      context.log.error("All backend health checks failed", { responses });
      return new ZuploResponse("Service Unavailable", { status: 503 });
    } else {
      const failedResponses = responses.filter(
        (res) => res.status === "rejected",
      ) as PromiseRejectedResult[];
      context.log.error("Backend health check failed", {
        statuses: failedResponses.map((res) => res.reason.status),
        statusText: failedResponses.map((res) => res.reason.statusText),
      });
      return new ZuploResponse("Service Unavailable", { status: 503 });
    }
  } catch (error) {
    context.log.error("Error during health check", { error });
    return new ZuploResponse("Service Unavailable", { status: 503 });
  }
}
```
