Skip to content

fix(link): send QR create options as multipart/form-data#135

Closed
jaredwray wants to merge 1 commit into
mainfrom
claude/focused-wright-aftivd
Closed

fix(link): send QR create options as multipart/form-data#135
jaredwray wants to merge 1 commit into
mainfrom
claude/focused-wright-aftivd

Conversation

@jaredwray

Copy link
Copy Markdown
Contributor

Problem

Custom options on QR codes don't work between the SDK and the API. Calling link.createQrCode(code, { title, backgroundColor, color, size }) is rejected by the Hyphen API with HTTP 400 (tracked as #133). A plain createQrCode(code) with no options works, which masked the bug.

Root cause

The API endpoint POST /organizations/:organizationId/link/codes/:codeId/qrs/ consumes multipart/form-data:

  • qr.schema.ts declares consumes: ['multipart/form-data']; the body schema validates each text field as a multipart field ({ value }) and the logo as an uploaded file (isFile: true).
  • app.ts registers @fastify/multipart with attachFieldsToBody: true, and the route handler reads each field via rawPayload[key].value / rawPayload[key]._buf.

The SDK's createQrCode, however, sent a JSON body with content-type: application/json. When custom options are present, the JSON string values fail the multipart body-schema validation → HTTP 400. With no options the body is empty, so it slips through — which is why only the custom-options path was broken.

Fix (SDK only)

createQrCode now builds a FormData body:

  • appends only the options that were provided (title, backgroundColor, color, size);
  • uploads logo as a file (base64 is decoded to bytes and sent as a Blob);
  • drops the JSON content-type header so fetch sets multipart/form-data with its generated boundary (@cacheable/net passes FormData straight through to fetch).

The apix side is correct as designed (the logo is intentionally a file upload with a 1MB limit), so no API change is needed — the SDK simply now conforms to the documented contract.

Tests

Verification

  • biome check clean; tsc --noEmit clean.
  • The new/updated createQrCode unit tests pass and cover the method 100% without network.
  • ⚠️ The live integration tests (incl. the re-enabled one) could not be run in this environment because api.hyphen.ai is not in the network egress allowlist (every live call returns 403 Host not in allowlist). They should pass in CI where egress and credentials are configured.

https://claude.ai/code/session_011Cn9uaUZa7n8MsPgBP79Dd


Generated by Claude Code

The Hyphen API's `POST .../link/codes/:code/qrs/` endpoint consumes
`multipart/form-data` (the logo is an uploaded file, and each text field
is validated as a multipart field). `createQrCode` was sending a JSON
body, so any request that included custom options (title, backgroundColor,
color, size) failed the multipart body-schema validation and was rejected
with HTTP 400; only the no-options call slipped through.

Build the request as `FormData`, appending only the options that were
provided and uploading the logo as a file, and drop the JSON content-type
header so fetch sets `multipart/form-data` with its generated boundary.

Update the request-body unit test to assert on the multipart body, add a
no-options case, and re-enable the custom-options integration test
(resolves #133).

https://claude.ai/code/session_011Cn9uaUZa7n8MsPgBP79Dd
@jaredwray jaredwray closed this Jun 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Flaky/failing test: should create a QR code with custom options returns HTTP 400

2 participants