Advanced
Use this page for uploads, downloads, lost updates, cache and shared bases. Each section is one feature. Add it only when you need it. Each snippet goes under a route of a surface (surfaces.app.routes) unless it says otherwise.
Upload a file
Section titled “Upload a file”Declare a multipart input. A file field says which media types and which size it accepts.
attach: method: post inputMedia: multipart bodyLimit: 25MiB input: type: object required: [file] properties: file: { file: { media: [image/png, application/pdf], maxSize: 20MiB } } caption: { type: string, maxLength: 200 } output: NoteA file of another type or above maxSize is refused with a 400. A body above bodyLimit is refused with a 413.
Download a file
Section titled “Download a file”An output that is a file is a download. The handler returns the bytes or a stream; each server guide shows how.
export: method: get output: { file: { media: [application/pdf, text/csv] } }Catch lost updates
Section titled “Catch lost updates”Ask the client for the version it read. With the version in the body, a stale write answers 409; with If-Match, 412 (below).
notes: kind: collection id: { noteId: NoteId } item: Note concurrency: { version: body.expectedVersion, field: version } ops: update: { input: UpdateNote }field is the property of Note the version is compared with. seampact adds expectedVersion to the input: do not declare it in UpdateNote.
Every response that carries a note writes its ETag from field.
To send the version in the If-Match header instead, write version: header.If-Match:
concurrency: { version: header.If-Match, field: version }- A write without the header, or with an empty one, answers
428. - A stale tag answers
412: the handler returns thepreconditionFailederror (see “Write a handler” in your server guide). - The tag can be strong (
"7") or weak (W/"7"). The handler receives the version unquoted:7. Each server guide shows the comparison.
Cache a read
Section titled “Cache a read”# contract/api.yaml, top levelconventions: cache: { families: { minute: 60s } }# on a GET route, or on a node above itcache: { freshness: minute, etag: true }A family is a named freshness, such as minute: 60s, that routes reuse. freshness names a family from conventions.cache.families. etag: true adds conditional GET. Write cache on a GET route or on a node above it.
Several success statuses
Section titled “Several success statuses”responses replaces output when a route answers more than one way, such as a 202 with a Location header.
export: method: post responses: 202: headers: { Location: { type: string, format: uri-reference } }Share a base between apis
Section titled “Share a base between apis”Put what several apis share (schemes, identities, errors, conventions) in a base file. extends copies its parts into this api. A name defined in both files is an error.
# top of contract/api.yamlextends: ./base.yamlA pack is a set of conventions you reuse, such as a paging style. Add it with packs:. See Convention packs.
- Next: Check it in CI, or go back to the contract pages.
- In depth: Routes, Inherited settings, Lists, cache and lifecycle and the worked example.