REST API on AWS
StreamHub's public API serves stream metadata, chat, subscriptions, and clips to web and mobile clients. Consistent resource naming, cursor pagination, and structured errors let third-party integrations ship without breaking every release.
Resource design principles
REST conventions for StreamHub
- Nouns, not verbs:
/streams/{id}not/getStream?id=123. - Plural collections:
/streams,/users/{id}/followers. - Nested resources sparingly:
/streams/{id}/clips— max two levels deep. - Actions as sub-resources:
POST /streams/{id}/followfor non-CRUD operations. - HTTP methods map to semantics: GET read, POST create, PUT replace, PATCH update, DELETE remove.
# StreamHub resource map (subset)
/streams:
GET: list streams (paginated)
POST: create stream (authenticated streamer)
/streams/{stream_id}:
GET: stream metadata
PATCH: update title, category
/streams/{stream_id}/clips:
GET: list clips
POST: create clip from timestamp
/users/{user_id}/subscriptions:
GET: list followed streamers
POST: follow streamer
Pagination
| Aspect | Offset pagination | Cursor pagination |
|---|---|---|
| Query | ?page=3&limit=20 | ?cursor=eyJpZCI6MTIzfQ&limit=20 |
| Performance | O(offset) — slow at high pages | O(limit) — constant time with index |
| Consistency | Duplicates/skips if data shifts during paging | Stable if sorted by indexed cursor field |
| StreamHub use | Admin dashboards (small datasets) | Public stream feed, chat history |
Query
Offset pagination?page=3&limit=20Cursor pagination?cursor=eyJpZCI6MTIzfQ&limit=20Performance
Offset paginationO(offset) — slow at high pagesCursor paginationO(limit) — constant time with indexConsistency
Offset paginationDuplicates/skips if data shifts during pagingCursor paginationStable if sorted by indexed cursor fieldStreamHub use
Offset paginationAdmin dashboards (small datasets)Cursor paginationPublic stream feed, chat history
{
"data": [
{ "stream_id": "live_9912", "title": "Friday Night Ranked" }
],
"pagination": {
"next_cursor": "eyJzdHJlYW1faWQiOiJsaXZlXzk5MTIifQ",
"has_more": true,
"limit": 20
}
}
Versioning
| Strategy | Example | Trade-off |
|---|---|---|
| URL path | /v1/streams | Explicit, easy to route; clutters URLs |
| Header | Accept: application/vnd.streamhub.v2+json | Clean URLs; harder to test in browser |
| Query param | /streams?version=2 | Simple but easy to forget |
URL path
Example/v1/streamsTrade-offExplicit, easy to route; clutters URLsHeader
ExampleAccept: application/vnd.streamhub.v2+jsonTrade-offClean URLs; harder to test in browserQuery param
Example/streams?version=2Trade-offSimple but easy to forget
StreamHub uses URL path versioning (/v1/) for public API; internal gRPC uses protobuf package versioning.
Never break existing clients — add fields, don't rename or remove without a new version.
Error contract
{
"error": {
"code": "STREAM_NOT_FOUND",
"message": "Stream live_9912 does not exist or has ended.",
"details": { "stream_id": "live_9912" },
"request_id": "req_8a3f2b1c"
}
}
HTTP status conventions
- 200/201/204: Success (200 read, 201 create, 204 delete).
- 400: Client error — bad input, validation failure.
- 401/403: Unauthenticated vs unauthorized.
- 404: Resource not found (don't leak existence of private resources — use 403).
- 409: Conflict — duplicate follow, idempotency key mismatch.
- 429: Rate limited — include
Retry-After. - 500/503: Server error — include
request_idfor support lookup.
OpenAPI specification
openapi: 3.1.0
info:
title: StreamHub Public API
version: 1.0.0
paths:
/v1/streams/{stream_id}:
get:
operationId: getStream
parameters:
- name: stream_id
in: path
required: true
schema:
type: string
responses:
"200":
description: Stream metadata
content:
application/json:
schema:
$ref: "#/components/schemas/Stream"
"404":
description: Stream not found
Quick recall
Everything you need if you only revisit this box.
- Resources are nouns; HTTP methods carry semantics; keep nesting shallow.
- Cursor pagination scales; offset pagination breaks at high page numbers.
- Version via URL path (/v1/) for public APIs; never break clients silently.
- Structured errors: code, message, details, request_id — not bare strings.
- OpenAPI documents the contract; generate client SDKs and validation from it.
- Idempotency-Key header on all mutating POST endpoints.
Test yourself
Answer these before moving on — recall is what makes it stick.