How to Monitor PhoenixSwagger with Vigilmon
PhoenixSwagger brings OpenAPI 2.0 documentation to Phoenix applications with a clean DSL for describing controllers, parameters, and response schemas. It auto-generates a swagger.json spec and serves the Swagger UI at /api/swagger. But a Swagger spec is only as useful as the API it documents — if the spec is stale or the endpoints it describes are down, developers consuming your API get false confidence.
This tutorial sets up layered monitoring for a PhoenixSwagger-documented API:
- Swagger spec availability and freshness checks
- HTTP uptime monitoring for documented endpoints with Vigilmon
- Heartbeat monitoring to detect spec drift
- Alerts when documented routes regress
Why Monitor PhoenixSwagger?
| Signal | What it catches |
|---|---|
| Spec availability | Build failures that prevent swagger.json from being generated |
| Swagger UI reachability | Broken static asset pipeline, router misconfiguration |
| Documented endpoint health | API regressions that aren't caught by spec validation |
| Spec freshness | Schema drift where code diverges from documentation |
| Response time | Slow endpoints that pass health checks but degrade the developer experience |
A working Swagger UI with a 200 OK on /api/swagger is not enough — the endpoints it documents can still be broken.
Step 1: Expose a Health Endpoint for Your API
Add a dedicated health route that Vigilmon can poll. Since your Phoenix router already documents routes via PhoenixSwagger, add the health check outside the Swagger scope:
# lib/my_app_web/router.ex
defmodule MyAppWeb.Router do
use MyAppWeb, :router
use PhoenixSwagger
pipeline :api do
plug :accepts, ["json"]
end
scope "/api", MyAppWeb do
pipe_through :api
get "/health", HealthController, :index
# ... your documented routes
resources "/users", UserController, only: [:index, :show, :create]
end
def swagger_info do
%{
info: %{
version: "1.0",
title: "My App API"
}
}
end
end
Create the health controller:
# lib/my_app_web/controllers/health_controller.ex
defmodule MyAppWeb.HealthController do
use MyAppWeb, :controller
def index(conn, _params) do
json(conn, %{status: "ok", timestamp: DateTime.utc_now() |> DateTime.to_iso8601()})
end
end
Verify it works:
curl http://localhost:4000/api/health
# => {"status":"ok","timestamp":"2026-07-03T10:00:00Z"}
Step 2: Add a Swagger Spec Health Check
Beyond the basic health endpoint, verify that the Swagger spec itself is being served. Add a spec check plug:
# lib/my_app_web/plugs/swagger_health.ex
defmodule MyAppWeb.Plugs.SwaggerHealth do
import Plug.Conn
def init(opts), do: opts
def call(%Plug.Conn{request_path: "/api/health/swagger"} = conn, _opts) do
spec_result = check_swagger_spec()
{status, body} = case spec_result do
:ok -> {200, %{status: "ok", swagger: "available"}}
{:error, reason} -> {503, %{status: "error", swagger: reason}}
end
conn
|> put_resp_content_type("application/json")
|> send_resp(status, Jason.encode!(body))
|> halt()
end
def call(conn, _opts), do: conn
defp check_swagger_spec do
spec = MyAppWeb.Router.swagger_spec()
if is_map(spec) and map_size(spec) > 0 do
:ok
else
{:error, "spec empty or missing"}
end
end
end
Register the plug before your router:
# lib/my_app_web/endpoint.ex
plug MyAppWeb.Plugs.SwaggerHealth
plug MyAppWeb.Router
Now GET /api/health/swagger returns 200 when the spec is generated correctly and 503 if something broke the spec generation.
Step 3: Add Vigilmon HTTP Monitors
Set up two monitors in Vigilmon — one for your API health, one for the Swagger spec:
API Health Monitor:
- Log in to vigilmon.online and click Add Monitor.
- Set Type to
HTTP / HTTPS. - Enter your health endpoint:
https://api.yourapp.com/api/health. - Set Check interval to
1 minute. - Set Expected HTTP status to
200. - Under Advanced, add Response body contains:
"status":"ok". - Click Save.
Swagger Spec Monitor:
- Click Add Monitor → HTTP / HTTPS.
- Enter:
https://api.yourapp.com/api/health/swagger. - Set Check interval to
5 minutes(spec generation is heavier than a simple health check). - Set Expected HTTP status to
200. - Add Response body contains:
"swagger":"available". - Click Save.
Step 4: Monitor the Swagger UI Endpoint
Developers accessing your Swagger UI at /api/swagger expect it to load. Add a Vigilmon check:
- Click Add Monitor → HTTP / HTTPS.
- Enter:
https://api.yourapp.com/api/swagger. - Set Check interval to
5 minutes. - Set Expected HTTP status to
200. - Under Advanced, add Response body contains:
swagger-ui(matches the Swagger UI HTML). - Click Save.
This catches router misconfiguration and broken static asset pipelines.
Step 5: Heartbeat Monitoring for Spec Freshness
Use a cron heartbeat to detect when your API code and Swagger spec drift apart. Add a mix task that validates your spec against your router:
# lib/mix/tasks/swagger_validate.ex
defmodule Mix.Tasks.SwaggerValidate do
use Mix.Task
@shortdoc "Validates swagger spec matches current router"
def run(_args) do
Mix.Task.run("app.start")
spec = MyAppWeb.Router.swagger_spec()
paths = Map.keys(spec["paths"] || %{})
if length(paths) == 0 do
IO.puts("ERROR: swagger spec has no paths")
System.halt(1)
else
IO.puts("OK: swagger spec has #{length(paths)} paths")
ping_vigilmon()
end
end
defp ping_vigilmon do
heartbeat_url = System.get_env("VIGILMON_SWAGGER_HEARTBEAT_URL")
if heartbeat_url do
:httpc.request(:get, {String.to_charlist(heartbeat_url), []}, [], [])
end
end
end
Run this as a post-deploy step:
VIGILMON_SWAGGER_HEARTBEAT_URL=https://vigilmon.online/api/heartbeat/YOUR_ID \
mix swagger_validate
To create the heartbeat in Vigilmon:
- Click Add Monitor → Cron / Heartbeat.
- Set expected interval to match your deploy cadence (e.g.,
1 day). - Copy the heartbeat URL into your deploy pipeline environment.
Step 6: Set Up Alerts
Configure alert channels for all three Vigilmon monitors:
- Go to Alert Channels → Add Channel.
- Choose Slack, Email, or PagerDuty.
- Set threshold: alert after 2 consecutive failures.
- Assign the channel to your API health, Swagger spec, and Swagger UI monitors.
For APIs used by external developers, add a Status Page:
- Go to Status Pages → Create Page.
- Add your API health monitor and Swagger UI monitor.
- Share the URL in your API documentation — developers can check API status themselves before filing a bug.
Key Metrics to Watch
| Metric | Vigilmon feature | What to alert on |
|---|---|---|
| API availability | HTTP monitor on /api/health | Any non-200 or timeout |
| Swagger spec availability | HTTP monitor on /api/health/swagger | Any 5xx response |
| Swagger UI reachability | HTTP monitor on /api/swagger | Any non-200 response |
| Spec freshness | Heartbeat monitor | Missing heartbeat after deploy |
| Response time | Response time chart | P95 > 1s over 5 minutes |
| SSL certificate | Cert expiry monitor | Expires in < 14 days |
Conclusion
PhoenixSwagger keeps your API documentation in sync with your code — but monitoring ensures the API it documents stays healthy. With HTTP monitors on your health endpoint, Swagger spec route, and Swagger UI, plus a heartbeat that fires on every successful deploy, Vigilmon gives you confidence that your documented API is actually available when developers need it.
Get started free at vigilmon.online.