API-Docker
view release on metacpan or search on metacpan
malformed status line, a bad `Content-Length` or a stray 1xx all croak
`API::Docker::Error::Truncated` instead of being handed back as a whole
response.
- A status of 400 or above croaks `API::Docker::Error::HTTP` instead of a
plain string, carrying `status`, `reason`, `body` and decoded `data`. It
stringifies exactly as the old string croak did, so text-matching
callers are unaffected.
- `tls => 1` now speaks real TLS over `tcp://`. `cert_path` names the
`docker` CLI's `ca.pem`/`cert.pem`/`key.pem` layout, `tls_insecure`
turns verification off, and `tls` defaults from
`$ENV{DOCKER_TLS_VERIFY}`. `IO::Socket::SSL` is a recommended
dependency, loaded on the first TLS connection.
- New `response => \%h` option fills `status`, `reason` and `headers`,
including for a request that croaked. New `head` verb beside
`get`/`post`/`put`/`delete_request`, which never waits for a body.
- `negotiate_version` croaks, naming `GET /version` and the expected
shape, when the body is not a JSON object carrying an `ApiVersion` of the
form `N.N`.
- New `API::Docker::Role::Filters`, consumed by all eight resource classes
and applied at every `filters` call site: a bare value, a boolean or a
mis-shaped filter is normalised to the engine's JSON map-of-arrays
instead of silently matching nothing.
- JSON request bodies send booleans as real `true`/`false`; a caller may
pass `1`/`0` or a JSON boolean interchangeably.
- `_uri_encode` UTF-8-encodes a decoded character string before
percent-escaping, so a name or tag typed as characters (`ü`, `ä¸`) goes
out as valid UTF-8.
- A request path outside the RFC 3986 origin-form character set is refused
before it reaches the daemon, closing a request-line injection through a
container name or image reference.
- An ArrayRef query parameter expands into one repeated `k=v` pair per
element (`names=a&names=b`), which some endpoints require.
- A bare JSON scalar body (`null`, `true`, a number, a quoted string) is
decoded rather than handed back as raw bytes; `raw` and `ndjson` return
`''` and `[]` for a zero-byte body instead of `undef`.
- Registry credentials reach `images->pull` (`auth`, sent as
`X-Registry-Auth`) and `images->build` (`registry_config`, sent as
`X-Registry-Config`), sent only when given. An already-base64 auth value
in the standard alphabet is respelled URL-safe, which the engine
requires.
- `images->pull` no longer appends a default `tag` onto a reference that
already carries a `:tag` or `@digest`.
- New `images->get`, `->get_all` and `->load`: the image tar roundtrip in
and out of a daemon without a registry. New `images->commit`
(POST /commit) and `images->build_prune` (POST /build/prune, the
BuildKit cache, a different store from the dangling images
`images->prune` deletes).
- New container endpoints: `get_archive`, `put_archive`, `stat_archive`
(the `docker cp` primitives), `changes`, `export`, `resize` and the
one-way half of `attach`. `attach` defaults to `stream => 0, logs => 1`
(replay and return) and refuses a container that is not running unless
`require_running => 0`.
- `containers->start`/`stop`/`restart`/`pause`/`unpause` return 1 when the
call changed the container's state and 0 when it was already in it (the
engine answers a no-op with 304), instead of always undef.
- `containers->stats` croaks `API::Docker::Error::HTTP` when Podman reports
a failure inside a 200 response, instead of handing the error object back
as a reading.
- New `API::Docker::API::Plugins` (`$docker->plugins`): `list`,
`privileges`, `install`, `inspect`, `remove`, `enable`, `disable`,
`upgrade`, `push` and `configure`. Needs a real Docker daemon; Podman
serves no `/plugins`.
- New `API::Docker::API::Secrets` and `API::Docker::API::Configs`: `list`,
`create`, `inspect`, `update` and `remove`. `Data` is base64-encoded for
the caller; `update` takes the current `Version.Index` as a mandatory
concurrency token.
- New `API::Docker::API::System::auth` (POST /auth): check registry
credentials without pulling or pushing. A rejected credential croaks.
- New `API::Docker::API::Distribution` (`inspect`/`exists`,
GET /distribution/{name}/json): ask a registry for a manifest without
pulling. `exists` answers `1`/`0` and tells a registry's own 404 apart
from an engine that serves no such route.
- Declare a minimum Perl of 5.014 (`s///r` in `Role::HTTP`) and add the
core modules `Errno`, `IO::Handle`, `Scalar::Util` and `Socket` to
`cpanfile`. Stop shipping `spec/` and `maint/` in the built dist.
- Swarm (`/swarm`, `/nodes`, `/services`, `/tasks`) is documented as a
permanent scope decision, not a gap: Podman implements none of it and no
consumer needs it. `secrets` and `configs` stand on their own and stay
covered.
0.003 2026-08-27 03:37:00Z
- t/containers.t: the registered cleanup tolerates the container the
happy path already removed, so a live run no longer warns "Cleanup
failed: ... no such container" on every pass. The safety net still
warns on any other failure.
- The `>= 400` croak now falls back to `errorDetail.message` and then to
the flat `error` key when the JSON error body carries no `message`.
Docker answers `{"message":...}`; Podman answers a failed push with
the stream shape instead -- `{"errorDetail":{"message":...},"error":
...}` and no `message` at all -- so the whole JSON object used to be
the croak text and the reason had to be dug out of it by eye. A body
that is not an object still surfaces verbatim.
- `images->build`, `->pull` and `->push` now croak when the engine
reports a failure inside the event stream, instead of returning the
stream and leaving the check to the caller. A failed build, pull or
push is answered with HTTP 200 -- the status line is committed
before the operation is attempted -- and the failure arrives as an
`errorDetail` object among the progress events, so nothing about the
response says the operation broke. Measured against the rootless
Podman socket (5.4.2, API 1.41): a Dockerfile of `FROM alpine:3` /
`RUN exit 7` answers `200 OK` and ends the stream with
`{"errorDetail":{"message":"building at STEP \"RUN exit 7\": while
running runtime: exit status 7\n"},"error":"..."}`, the flat `error`
key carrying the same text. Callers that never scanned for it -- the
documented shape until now -- reported a broken build as a success.
The exception is an `API::Docker::Error::Stream`, a new class whose
whole purpose is that the progress output is not lost with the
return value: `$err->events` is the complete event list, error event
included. It overloads stringification and produces exactly what the
plain croak it replaces produced, reason plus Carp's ` at FILE line
N.` suffix, so existing eval-and-inspect-$@ code needs no change;
`$@ =~ s/...//` on it yields a plain string as it would for any
overloaded object. The trigger is the `errorDetail` key alone, never
the word "error" in payload text.
Which of the three actually takes that route depends on the engine,
and Podman is not Docker here -- measured on the same socket, all
three cases: only `build` answers 200 with the failure in the
stream. A pull of a missing repository answers `403 Forbidden` with
`{"message":"denied: requested access to the resource is denied"}`,
a missing tag answers `404 Not Found` with `{"message":"manifest
unknown: manifest unknown"}`, and a push to an unreachable registry
( run in 0.859 second using v1.01-cache-2.11-cpan-aadc1410aed )