← all lessons

Lesson 9

@httpPayload

@httpPayload

By default, all unbound input/output members are serialized together into a single JSON body — an envelope. @httpPayload overrides that: it binds one member to be the entire HTTP body, on its own.

@http(method: "PUT", uri: "/cities/{cityId}/flag", code: 200)
operation PutFlag {
    input := {
        @required
        @httpLabel
        cityId: String

        @required
        @httpPayload
        image: Blob
    }
}

Here the request body is the blob — no JSON wrapper. This is how you model uploads, raw documents, or any “the body is this one thing” endpoint.

The rules the compiler enforces

  • At most one @httpPayload member per input (and one per output). Two is an error.
  • When a member is the payload, the other members must all be bound somewhere else (@httpLabel, @httpQuery, @httpHeader) — they can’t fall back to the body, because the payload is the body.
  • @httpPayload targets a single shape — commonly a Blob, String, or a structure (which is then serialized as the whole body).

Contrast with the previous lesson: without @httpPayload, image and any other unbound members would be wrapped in a JSON object. With it, image stands alone and everything else must leave the body.

Your turn

Model a flag upload. cityId rides in the URI; the Blob is the raw body.

Note the second check: it asserts the exact value of @httpPayload. That trait is an annotation trait — it carries no data — so its node value is the empty object {}. (Most annotation traits are like this; you’ll usually just check presence, but here we make the shape explicit.)