fix: DIRECT-GET-LAST body-only format + allow-direct attribute - #6
Conversation
NATS v2.14+ returns '408 Bad Request' when DIRECT.GET receives the subject in BOTH the API path AND the last_by_subj body field. Fix: use $JS.API.DIRECT.GET.<stream> with last_by_subj in body only. Also add allow-direct attribute to Nats::Stream, default False. False booleans are omitted from stream config (to-map fix). TDD: RED-GREEN - Test validates body-only format (was path+subject) - Test validates allow-direct present when True - Test validates allow-direct omitted when False (default)
Code Review —
|
| Metric | Value |
|---|---|
| Files changed | 3 |
| Lines added | +89 |
| Lines removed | −4 |
| New tests | 6 (3 standalone + 3 integrated) |
| Security scan | Clean |
| Debug artifacts | Clean |
Reviewed by Hermes Agent
There was a problem hiding this comment.
Pull request overview
Adjusts JetStream Direct Get Last request formatting to avoid NATS v2.14+ 408 Bad Request responses caused by duplicating the subject in both the API subject and request body, and adds support for the stream allow_direct configuration flag while preventing default False booleans from being serialized.
Changes:
- Switches
DIRECT-GET-LAST/get-last-msgto a body-only format ($JS.API.DIRECT.GET.<stream>+last_by_subjin payload). - Adds
allow-directattribute toNats::Streamand updatesto-mapto omitFalsebooleans (so defaults aren’t serialized). - Adds/updates tests to cover body-only direct-get-last and
allow_directserialization behavior.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| lib/Nats/JetStream.rakumod | Updates Direct Get Last subject formatting, adds allow-direct, and tweaks serialization to omit False booleans. |
| t/jetstream.rakutest | Updates existing JetStream tests to validate body-only direct-get-last and allow_direct inclusion/omission. |
| t/direct-get-last.rakutest | Adds a focused regression test script for direct-get-last formatting and allow_direct behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| } | ||
|
|
||
| # Direct get last message for a subject | ||
| method get-last-msg(Str $subject) { | ||
| $!nats.request: sprintf(DIRECT-GET-LAST, $!name, $subject), to-json { :last_by_subj($subject) } | ||
| $!nats.request: sprintf(DIRECT-GET-LAST, $!name), to-json { :last_by_subj($subject) } |
There was a problem hiding this comment.
Done in 5ee7ed0 \u2014 removed the dead parameter and simplified to always use with in the payload instead of .
| #!/usr/bin/env raku | ||
| use Nats::JetStream; | ||
| use Nats; | ||
| use Test::Mock; | ||
| use JSON::Fast; |
There was a problem hiding this comment.
Done \u2014 added to . \n\nThe fix is pushed to (could not push to upstream). \n\nPatch:\n
- Remove unused :$subject parameter (dead code — sprintf ignored 3rd arg) - Fix payload field: last_by_subj→last_by_seq (was passing sequence number under wrong field name) - Simplify: always use DIRECT-GET path (get-msg is seq-based, never subject-based)
Code Review —
|
| Comment | Issue | Resolution |
|---|---|---|
| #3408858810 | get-msg dead :$subject param |
Fixed in 5ee7ed0 — removed parameter, simplified to DIRECT-GET only |
| #3408858816 | t/direct-get-last.rakutest missing use lib 'lib' |
Fixed in 535124b — added use lib 'lib'; (pushed to hermes-fco/nats.raku:fix/direct-get-last) |
📊 Stats
| Metric | Value |
|---|---|
| Files changed | 3 |
| Lines added | +95 |
| Lines removed | −10 |
| New tests | 1 test file (t/direct-get-last.rakutest, 3 tests) |
| Security scan | Clean (no secrets, debug, merge conflicts) |
| New since last review | 2 commits (5ee7ed0, 535124b) |
Reviewed by Hermes Agent
Problem
Nats::Stream.get-last-msgsends subject in both the API path AND thelast_by_subjbody field:NATS v2.14+ returns
408 Bad Requestfor this duplicate format.Fix
DIRECT-GET-LASTchanged from$JS.API.DIRECT.GET.%s.%sto$JS.API.DIRECT.GET.%s— subject only in bodyget-last-msgpasses only stream name tosprintfallow-directattribute added toNats::Stream(defaultFalse, omitted when false)to-mapskipsFalsebooleans so defaults are not serializedTDD: RED → GREEN