3.1 Messages and bodies

Everything in RS2 moves as a message. A service is a function from a message to a message (1.1); understanding the message model explains a lot of the runtime's behavior.

What a message is

A message is the familiar HTTP shape:

  • a method (GET, PUT, …) and a URL (path + query),
  • headers,
  • a body, and
  • a media type describing the body.

The same structure is used for requests, responses, and the in-flight value that flows through a pipeline. That uniformity is why steps compose: a response is a message a later step can act on.

Bodies: bytes or stream

A body is either materialized bytes or a stream. This matters for large payloads: a file write streams from the client to disk without ever holding the whole thing in memory, and a read streams back the same way. The runtime only materializes (buffers fully) a body when an operation genuinely needs the bytes — and even then it's capped (default 100 MB; an over-cap materialization fails with payload_too_large/limit_exceeded rather than exhausting memory).

The practical upshot for you as a caller: large uploads and downloads are efficient by default, and you don't manage buffering.

Media types are mandatory and meaningful

Every body carries a media type — it's not optional metadata. The file service derives it from the resource's extension (never by sniffing content); an unknown extension becomes application/octet-stream. The data service uses application/json, and when a record has a schema it includes a schema pointer in the Content-Type (e.g. application/json; schema="…/.schema.json").

Because media types are explicit, content negotiation and downstream handling are predictable rather than guessed.

Provenance: can this body be replayed?

A subtle but important property the runtime tracks is a body's provenance — roughly, whether it can be read again:

  • Materialized — the bytes are in hand and can be re-read.
  • Replayable — the source can be re-fetched if needed.
  • Ephemeral — a one-shot stream that can't be rewound.

You rarely set this yourself, but it's why some pipeline behaviors differ for streaming bodies: a segment whose input is a large, ephemeral stream can't be snapshotted, so it runs at most once (Part 7's segments). When you see "streaming bodies aren't retried," provenance is the reason.

Why this matters downstream

Three later behaviors fall out of this model:

  • Conditional requests (ETag/If-None-Match) work because stores version every resource — see 4.2.
  • Schema-carrying content types let clients discover validation rules — 4.5.
  • Materialization caps and streaming retry limits are limit/pipeline behaviors — Parts 7 and 9.

Next: how messages get routed to the right service.


Part 2 — Getting Started · Manual home · Next: 3.2 Tenants and mounts →