Do not attach a body to bodyless requests (fixes 404s under Req >= 0.7) - #64
Do not attach a body to bodyless requests (fixes 404s under Req >= 0.7)#64andrejj wants to merge 1 commit into
Conversation
`encode_body/1` serialized a nil body to the literal "null", so every request without a body (GET/DELETE) carried a JSON body. Older HTTP clients silently dropped that body, but Req >= 0.7 transmits it — and Typesense returns 404 for a GET-with-body on routes like `/collections/:name`. The practical effect with Req 0.7: `OpenApiTypesense.Collections.get_collection/2` (and anything built on it, e.g. ex_typesense's collection existence checks and reindexing) receives a spurious 404 for a collection that exists. Fix: return nil from `encode_body/1` when there is no request-body spec and no body, so Req omits the body entirely. Requests that do carry a body are unaffected.
Reviewer's GuideThis PR fixes incorrect handling of bodyless HTTP requests by ensuring that GET/DELETE requests without a body do not send the literal "null" as a JSON payload, adds a regression test to lock in the new behavior, and documents the fix in the changelog. Sequence diagram for bodyless GET requests with updated encode_body behaviorsequenceDiagram
actor User
participant OpenApiTypesense_Client as OpenApiTypesense.Client
participant Req
participant Typesense
User->>OpenApiTypesense_Client: get_collection(name)
OpenApiTypesense_Client->>OpenApiTypesense_Client: encode_body(opts_request, body)
alt before_fix
Note over OpenApiTypesense_Client: {nil, nil} -> Jason.encode_to_iodata!(nil) == "null"
OpenApiTypesense_Client->>Req: request(method: GET, url, body: "null")
Req->>Typesense: GET /collections/:name with JSON body "null"
Typesense-->>Req: 404 Not Found
Req-->>OpenApiTypesense_Client: {:error, ApiResponse(message: Not Found)}
else after_fix
Note over OpenApiTypesense_Client: {nil, nil} -> nil (no body)
OpenApiTypesense_Client->>Req: request(method: GET, url, body: nil)
Req->>Typesense: GET /collections/:name without body
Typesense-->>Req: 200 OK
Req-->>OpenApiTypesense_Client: {:ok, ApiResponse(collection)}
end
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Gates Passed
3 Quality Gates Passed
See analysis details in CodeScene
Quality Gate Profile: The Bare Minimum
Install CodeScene MCP: safeguard and uplift AI-generated code. Catch issues early with our IDE extension and CLI tool.
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Duplication | 0 |
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
Problem
encode_body/1serializes anilbody to the literal string"null", so every request without a body (GET/DELETE) carries a JSON body. Older Req versions silently dropped that body on bodyless methods, so this was masked. Req >= 0.7 transmits it, and Typesense then returns404 Not Foundfor a GET-with-body on routes like/collections/:name.Concretely, with Req 0.7:
Anything built on
get_collection/2is affected — e.g.ex_typesense's collection existence checks and reindex flow, wherecollection_exists?starts returningfalsefor collections that exist, so reindexing tries to recreate them and fails with "a collection with name ... already exists".list_collectionsfails too, but as aMatchErrorinparse_resp/2(its operation spec has no404entry, soEnum.find/2returnsnil).Root cause is not Req
The request was semantically wrong all along — a GET/DELETE with no body should not send a body. Older Req just tolerated it; Req 0.7 faithfully sends what the library asked for. So this is a library fix, not a Req-compat shim, and it needs no version bound on
req— the output is now correct for any HTTP client.Fix
Return
nilfromencode_body/1when there is no request-body spec and no body, so Req omits the body. Requests that carry a body are unaffected — they never reach the new clause (they either have anopts[:request]content-type spec or a binary body).Bisection that isolates it (identical GET, only the body differs):
body: "null"Verification
build_req_client/2regression test asserting a bodyless GET yieldsreq.body == nil.mix test test/default_client_test.exs→ green (resolves Req 0.7.x, i.e. tested against the version that exposed the bug).get_collection/list_collections/reindex work again under Req 0.7.Notes
Alternative considered: omit the
:bodykey inbuild_req_client/2instead of passingbody: nil. Functionally identical (Req omits a nil body); kept the change localized toencode_body/1.Summary by Sourcery
Prevent JSON bodies from being attached to bodyless HTTP requests to avoid 404 responses from Typesense under newer Req versions.
Bug Fixes:
Documentation:
Tests: