Factory.ai

Open-Source Wikis

/

Grafana

/

Backend

/

API layer

grafana/grafana

API layer

pkg/api/ is the legacy REST surface — the HTTP handlers that have powered Grafana since the Go server was introduced in 2014. New endpoints increasingly live in app-platform style under apps/ and pkg/apis/, but pkg/api/ is still the dominant external API.

Layout

pkg/api/
├── api.go                  # Route table — wires every endpoint to a handler
├── http_server.go          # HTTPServer struct that holds all service dependencies
├── routing/                # Tree of RouteRegister abstraction over httprouter
├── response/               # Helpers for building JSON responses with status codes
├── apierrors/              # Mapping from typed errors to HTTP status codes
├── dtos/                   # Request/response Go structs (DTOs)
├── pluginproxy/            # /api/datasources/proxy/* and /api/plugins/* proxies
├── frontendlogging/        # Browser logging endpoint helpers
├── webassets/              # Resolved index.html for the SPA
├── static/                 # Static asset handling
├── avatar/                 # Gravatar proxying
├── <resource>.go           # Per-resource handlers: dashboard.go, folder.go, …
└── <resource>_test.go      # Co-located tests

There are roughly 80 resource files in pkg/api/ and another 80 test files — each a thin handler that authenticates the request, resolves the right service, and returns JSON.

Routing

Routes are declared in pkg/api/api.go using a RouteRegister-based DSL:

r.Get("/api/dashboards/uid/:uid", routing.Wrap(hs.GetDashboard))
r.Group("/api/folders", func(folderRoute routing.RouteRegister) {
    folderRoute.Get("/", middleware.ReqOrgAdmin, routing.Wrap(hs.GetFolders))
    folderRoute.Get("/:uid", middleware.CanAdminPlugins, routing.Wrap(hs.GetFolderByUID))
    // ...
}, middleware.ReqSignedIn)

routing.Wrap adapts a func(c *contextmodel.ReqContext) response.Response handler into a stdlib http.HandlerFunc. The routing package abstracts over the underlying mux (pkg/web/) so handlers always see a *ReqContext carrying the authenticated identity and request-scoped helpers.

Middleware chain

The middleware tree is constructed in pkg/middleware/middleware.go. A typical request travels through:

graph LR
    R[Request] --> RID[RequestID]
    RID --> Logger[Access log]
    Logger --> Recov[Recovery]
    Recov --> CORS[CORS]
    CORS --> Auth[Authentication<br/>contexthandler.go]
    Auth --> RBAC[RBAC checks<br/>per-route]
    RBAC --> Quota[Quota]
    Quota --> Handler

Authentication lives in pkg/services/contexthandler/contexthandler.go and dispatches to the auth-method clients in pkg/services/authn/ (basic, OAuth, JWT, anonymous, render token, service account, …).

HTTPServer struct

HTTPServer in pkg/api/http_server.go is the god-struct for the legacy API: it holds references to every service that any handler needs. New service dependencies are added by:

  1. Adding the field to HTTPServer.
  2. Adding the parameter to ProvideHTTPServer(...).
  3. Letting Wire fill it in.

This file regularly grows / shrinks during refactors. Newer subsystems prefer to have their own api/ subpackage rather than living on HTTPServer directly.

Errors and responses

  • Handlers return response.Response — a small wrapper over status code + body + headers.
  • Typed errors from services are mapped to HTTP statuses in pkg/api/apierrors/ using errutil codes (pkg/util/errutil/).
  • The convention is to return response.Err(err) for service errors and response.JSON(http.StatusOK, body) for success.

Swagger / OpenAPI

Swagger annotations (go-swagger) are sprinkled across handler comments. make swagger-gen aggregates these into:

  • public/api-merged.json — full merged spec.
  • public/api-spec.json — OSS-only.

The aggregated spec is used by @grafana/api-clients to generate TypeScript clients (yarn generate-apis).

App-platform endpoints

Newer code routes through the apiserver instead of pkg/api/. The shape:

  • A resource is declared in apps/<name>/kinds/ (CUE).
  • Codegen produces Go types and (in apps/<name>/pkg/apis/) the Kubernetes-style group/version/resource registration.
  • The aggregator (pkg/aggregator/) and pkg/services/apiserver/ make the resource available under /apis/<group>/<version>/<resource>.

For consumers, both the legacy /api/... paths and the new /apis/... paths coexist and may serve overlapping data — see Unified storage for how the two layers interact.

Key source files

File Purpose
pkg/api/api.go Route table — single source of truth for all legacy endpoints
pkg/api/http_server.go HTTPServer dependencies struct
pkg/api/routing/ RouteRegister abstraction
pkg/api/response/response.go Response helpers
pkg/api/apierrors/ Typed-error → status mapping
pkg/middleware/middleware.go Middleware chain
pkg/services/contexthandler/contexthandler.go Auth dispatcher / *ReqContext builder

Where to start when modifying the API

  • Add a new endpoint to an existing resource: edit the resource's .go file in pkg/api/, add to api.go, write the test, regenerate Swagger.
  • Add a new resource entirely: prefer creating a new app under apps/<name>/ with CUE schemas and make gen-apps — this is the future direction.
  • Change a request DTO: update pkg/api/dtos/, then make swagger-gen and (if a TS client uses it) yarn generate-apis.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

API layer – Grafana wiki | Factory