moby/moby
API server
Purpose
daemon/server/ implements the HTTP plumbing of the Engine API. It owns route registration, request lifecycle, middleware chain, error-to-status mapping, and the small backend interfaces each handler depends on. It does not know about containers, images, or networks directly — those live behind backend interfaces that Daemon implements.
Layout
daemon/server/
├── server.go # Server struct, mux, otel http handler, error response
├── middleware.go
├── middleware/ # Version, CORS, debug, experimental, auth (UID), prometheus
├── httpstatus/ # error -> HTTP status code translation
├── httputils/ # decoders, JSON helpers, hijack support
├── router/ # one package per resource group (container, image, network, ...)
├── backend/ # backend interfaces (ContainerBackend, etc.)
├── buildbackend/ # builder backend interface
├── imagebackend/ # image backend interface
├── networkbackend/ # network backend interface
├── volumebackend/ # volume backend interface
├── swarmbackend/ # swarm backend interfaceRequest path
graph LR Listener --> Mux[gorilla/mux + version matcher] Mux --> OTEL[otelhttp wrapper] OTEL --> MWChain[middleware chain] MWChain --> Handler[router.Route handler] Handler --> Backend[Backend interface impl] Backend --> Daemon[Daemon]
The dispatcher is Server.makeHTTPHandler in daemon/server/server.go. It:
- Wraps the route in
otelhttp.NewHandlerfor OpenTelemetry tracing. - Sets
dockerversion.UAStringKeyand an OTel "trigger=api" baggage value on the context. - Builds the middleware chain via
handlerWithGlobalMiddlewares. - Calls the route's
httputils.APIFunc(ctx, w, r, vars). - On error, maps to an HTTP status via
httpstatus.FromErrorand writes either plain text (for clients on API < 1.24, the now-unsupported floor) or a JSONcommon.ErrorResponse. - Returns HTTP 499 if the client disconnected mid-request.
Routers
Each resource group is a router.Router implementation in daemon/server/router/<group>/:
| Router | Endpoints handled |
|---|---|
container/ |
/containers/..., /exec/..., /_ping-adjacent control routes. |
image/ |
/images/..., image search, history, prune. |
build/ |
/build, /build/prune, /build/cancel (delegates to BuildKit or classic). |
network/ |
/networks/.... |
volume/ |
/volumes/.... |
system/ |
/info, /version, /events, /df, /auth, /_ping. |
swarm/ |
/swarm, /services, /tasks, /nodes, /secrets, /configs. |
plugin/ |
/plugins/... (managed plugins). |
session/ |
/session (BuildKit hijacked stream). |
grpc/ |
/grpc for BuildKit gRPC over HTTP/2. |
checkpoint/ |
/containers/{name}/checkpoints (CRIU experimental). |
debug/ |
/debug/pprof/..., profiling endpoints (when --debug). |
distribution/ |
/distribution/.../json for inspecting registry manifests. |
router.Router and router.Route are tiny interfaces in daemon/server/router/router.go; they exist so that route registration, method, and path are all data, not code.
Versioning
Every route is mounted twice by Server.CreateMux:
m.Path(versionMatcher + r.Path()).Methods(r.Method()).Handler(f)
m.Path(r.Path()).Methods(r.Method()).Handler(f)Where versionMatcher = "/v{version:[0-9.]+}". Handlers that need to vary per API version pull the version mux variable and use daemon/internal/versions/. The minimum API version is enforced in the VersionMiddleware (daemon/server/middleware/version.go). Default and minimum versions live in daemon/config/.
Middleware
Middleware is a function type in daemon/server/middleware/. Built-in chain:
| Middleware | Source | Role |
|---|---|---|
VersionMiddleware |
version.go |
Enforces min/max API version, sets headers. |
CORSMiddleware |
cors.go |
Configurable CORS for the TCP socket. |
UIDAllowlistMiddleware |
uid_allowlist.go |
Restricts socket access by peer UID where supported. |
ExperimentalMiddleware |
experimental.go |
Gates experimental endpoints on daemon config. |
DebugRequestMiddleware |
debug.go |
Logs request bodies in debug mode (with redactions). |
The Prometheus middleware (daemon/server/middleware/prometheus.go) emits per-route counters when metrics are enabled. The authorization plugin chain lives in pkg/authorization/ and is wired into the server when the --authorization-plugin flag is set.
Hijacked streams
/containers/{name}/attach, /exec/{id}/start, and /grpc upgrade the HTTP connection. Helpers in daemon/server/httputils/ implement the hijack handshake; the routers call them and then hand off raw net.Conn instances to the relevant backend.
Error mapping
Errors flowing back to the handler are mapped to HTTP status codes by httpstatus.FromError in daemon/server/httpstatus/. It walks the error chain and matches against errdefs.Is* predicates (errdefs/). For example, errdefs.NotFound becomes 404, errdefs.InvalidParameter becomes 400, errdefs.Conflict becomes 409.
Tests
server_test.go next to the server file covers the dispatcher. Per-router unit tests live alongside each handler (container_routes_test.go, etc.) and use small fakes for the backend interfaces.
Entry points for modification
- New endpoint: declare a method on the relevant backend interface, implement it on
Daemon, register arouter.Routein the matching router package, updateapi/swagger.yaml. - New middleware: implement
middleware.Middlewareand register viaServer.UseMiddlewareindaemon/command. - New error type: add an
errdefs.Is*predicate and updatehttpstatus.FromError.
See also
- API endpoints for the full surface.
- Daemon core for the backend implementations.
api/README.mdfor the Swagger workflow.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.