API-Docker

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

    comes from -- `exec->inspect($id)->{ExitCode}`, a separate call --
    which the method's documentation never mentioned.
  - `images->build`, `->pull` and `->push` now always return an ArrayRef
    of events. `_request` used to try `decode_json` on the whole body
    first and only fall back to line-by-line parsing, so a stream that
    carried exactly one JSON object came back as a HashRef while a
    multi-event stream came back as an ArrayRef, and every caller had to
    check `ref` before iterating. Measured on Podman: `POST /build?q=1`
    emits exactly one object, which is the case that used to change
    shape. The ordinary single-JSON-object endpoints (`/version`,
    `/containers/{id}/json`, ...) are untouched and still return a
    HashRef -- the streaming behaviour is now requested explicitly with
    the new `ndjson => 1` transport option rather than guessed from the
    body. The option is named for the format and not `stream`, which is
    already a query parameter of `/events` and
    `/containers/{id}/stats`.
    `system->events` takes the same option. It was reaching an ArrayRef
    only through the implicit fallback that has now gone, so without it
    the endpoint would have quietly started returning an undecoded
    string. Measured on Podman for one container create/init/start/
    died/remove cycle: five newline-delimited objects, and the body is
    not valid JSON as a whole. Its POD now also says to always pass
    `until`, since the transport buffers the whole response and an
    unbounded event stream therefore never returns.
    Note for anyone scanning these events: a failed build is still HTTP
    200 with the failure carried as an `errorDetail` object inside the
    stream, confirmed on Podman for a Dockerfile whose `RUN` exits 7.
    A failed *pull* differs there -- Podman answers 404 with a plain
    `{"message":...}` body where Docker streams `errorDetail` on a 200 --
    so `pull` can croak as well as report an error event.
  - Bring the cpanfile in line with what the code loads. `URI` was
    required and is used nowhere in `lib/` or `t/`, so every consumer
    installed it for nothing; it is gone. `Carp` (loaded by eight of the
    twelve modules) and `IO::Socket::INET` (loaded by
    API::Docker::Role::HTTP beside its already-declared `IO::Socket::UNIX`
    sibling) were undeclared and are now required, as is `Exporter`
    under `on test` for the mock helper. Nothing else in the tree loads
    an undeclared module: `SOCK_STREAM` in the HTTP role comes from
    IO::Socket, which IO::Socket::UNIX and IO::Socket::INET both
    re-export, and `Path::Tiny` appears in `lib/` only inside the
    API::Docker::API::Images SYNOPSIS, so it stays a test dependency.
  - Fix every image push failing with a 400. The X-Registry-Auth header
    was encoded as base64url with the padding stripped; the engine
    decodes it with Go's `base64.URLEncoding`, which requires padding
    and answers `failed to parse "X-Registry-Auth" header ... unexpected
    EOF` without it. That hit authenticated and anonymous pushes alike
    -- the anonymous payload is `{}`, which encodes to three characters
    and one `=`. Measured against a local registry: before, all three
    tags of a test image came back 400 and nothing reached the registry;
    after, all three are there.
    The test that covered this could not have caught it. Its decode
    helper computed the missing padding and appended it before decoding,
    so the assertions passed either way. It now decodes what the engine
    would get, and a separate case pins the exact padded header.
  - Document that this client speaks the Docker Engine HTTP API over a
    socket and never shells out to the `docker` binary, so any engine
    serving that API works -- Podman's rootless socket needs nothing
    but `DOCKER_HOST`. The new CONTAINER ENGINES section also states
    what socket discovery deliberately does not do: Docker contexts
    (`currentContext`, `~/.docker/contexts/meta/*/meta.json`) are never
    consulted, unlike the `docker` CLI, docker-java or Testcontainers.

0.002     2026-05-17 05:36:20Z
  - HTTP role: `_request` now accepts a `headers => {}` option to set
    extra HTTP request headers. Headers are sanitised against CR/LF
    injection. Used by `images->push` to send `X-Registry-Auth`, and
    available to any caller that needs custom headers.
  - `images->push` now always sends an `X-Registry-Auth` header — the
    Docker Engine refuses pushes without it (`HTTP 400: missing
    X-Registry-Auth: invalid X-Registry-Auth header: EOF`). A new `auth`
    option accepts a hashref of credentials (`username`, `password`,
    `serveraddress`, or `identitytoken`) which is JSON-encoded and
    base64url-wrapped per the Docker Engine spec. Without `auth` the
    header carries an empty JSON object so unauthenticated/public
    pushes succeed where they previously failed at the HTTP layer.

0.001     2026-04-29 00:40:43Z
    - Initial release as API::Docker
    - Docker Engine API client with Unix socket and TCP support
    - Auto-negotiate API version from daemon
    - Container, Image, Network, Volume, System, and Exec APIs
    - Pure Perl implementation with minimal dependencies (no LWP)
    - HTTP/1.1 transport with chunked transfer encoding support



( run in 0.925 second using v1.01-cache-2.11-cpan-364913b4093 )