Add a REST API test suite and fix the bugs it found (#3693)
- Regenerate api/dist with the current build tooling
The committed dist files were generated by an older version of the yaml
package, so any rebuild rewrites all of them with different anchor
placement and key quoting. Regenerate them from the unchanged sources now,
so later spec changes show up as small diffs. The content of every file
is unchanged; only the formatting differs.
Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com
- Add an end-to-end test suite for the REST API
Nothing exercised the REST controllers, which is how #3687 and #3691
reached users. The new t/plack-api-.t tests send real requests through
app.psgi with a temporary user's API key (helpers in t/lib/DW/Test/API.pm),
so routing, key auth, spec validation, rate limiting, controllers and
backends are all covered. They run in CI's existing plack- step.
t/entry-to-json.t and t/proto-edit-tags.t test LJ::Entry::TO_JSON and
arrayref taglists in postevent/editevent directly, and are added to CI's
posting step. They include regression tests for #3687 and #3691.
Cases that currently fail are marked TODO; the following commits fix
them.
Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com
- Keep omitted fields when editing entries through the API
The API treats a field left out of an edit as unchanged, but
formto_backend read "missing" as "off". A text-only edit removed the
entry's tags, age restriction, backdating, comment settings and slug,
and reset a custom access filter's mask to 0. When editing, fall back to
the entry's current value for each of those fields.
Edits now honour datetime, which was documented but ignored, and keep
the current date when it's left out. text is optional on edit as the
spec says, and an explicit empty subject clears the subject. The spec
now describes these semantics and the 200 response edits already
returned, and documents that count is capped at the site's
scrollback limit.
Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com
- Tighten API key validation
Only return a key from DW::API::Key::get_key when its account is
active. The check runs on every lookup, after the cached key data is
read, so a change to the account takes effect immediately.
Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com
- Return valid error statuses from the entry edit and tag endpoints
Two rest_error calls passed an HTTP method name as the status code, so
responses went out with a status of "POST" or "GET". A maintainer
editing someone else's entry now gets a 403 with a message.
Creating tags only reported an error when two or more tags failed, and
reused one error buffer for every tag. Now any failed tag makes the
request a 400 that carries the error messages. Protocol errors on edit,
such as an invalid date, return 400 as they do when posting, instead of
500.
Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com
- Fix accesslist editing, deletion, and id validation in the API
Adding journals to an accesslist read $body->{journals}, but the spec's
body is a plain array of usernames, so every request died with a 500.
The endpoint now reads the array and responds with the updated list, as
the spec documents.
Deleting an accesslist passed a hashref to delete_trust_group, which
takes a list, so nothing was ever deleted even though the response was
204. trust_groups was called the same way, so its existence checks always
passed. Deleting a missing list is now a 404, and fetching an unused one
is a 400.
Ids outside 1-60 made trust_groups die, which caused 500s; the spec now
bounds them, so they are rejected as 400s.
Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com
- Harden REST request handling
Require the Bearer scheme in the Authorization header, matched
case-insensitively as RFC 6750 and RFC 9110 11.1 specify. Before, any
header that happened to contain a key was accepted, and "bearer" in
lowercase was rejected.
Anchor REST route patterns at the start as well as the end, so routes
no longer match under arbitrary prefixes such as /api/v1/x/spec.
Request bodies in a content type the spec has no schema for now get a
415, instead of dying in validation with a 500. Missing required bodies
and invalid JSON get a 400 that says what went wrong, and validation
errors include their messages, which were always empty before. Bodies
for creating entries, tags and accesslists are now marked required in
the spec.
Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com
- Validate tags given as a list before posting or editing
The REST API sends tags as an arrayref, but common_event_validation
checked the taglist before it was joined, so the stringified reference
always passed. Invalid tags in a list were silently dropped, and the
request still succeeded. Join the list at the start of
common_event_validation, so lists get error 211 the same way tag strings
do. That makes the separate arrayref handling in postevent and editevent
redundant, so remove it.
Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com