Zuplo
Guides

Health Check Handler

Part of running a reliable API Gateway is ensuring that the service is healthy and available. With Zuplo, it is easy to setup 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 excersise some of the most important policies (such as authentication) and then make a simple request to your backend to ensure that it is 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:

JSONconfig/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 is reachable and functioning. If you have multiple backend services you can check each of them.

TypeScriptmodules/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 }); } }
Last modified on