agentsclimarketplace

Mobile api design

Skill almasumdev/awesome-mobile-backend-agent-skills/.github/skills/api/mobile-api-design

Agent skills for the backend-for-mobile layer: APIs, auth, push, sync, and BaaS integrations.

Install
npx -y skills add almasumdev/awesome-mobile-backend-agent-skills --skill mobile-api-design

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Design mobile-friendly HTTP APIs with predictable pagination, filtering, sorting, sparse/partial responses, and a consistent error envelope. Use when specifying new endpoints or reviewing existing ones for mobile use.

SKILL.md

4.5 KB, as published. Nobody here has run it

Mobile API Design

Instructions

Mobile clients run on flaky networks, long-lived installs, and limited CPU/battery. API shape decisions made on day one outlive any single app version. Design for the pessimistic case: 3G, stale app, cold cache.

1. Resource Shape

Prefer nouns and predictable plurals: /v1/articles, /v1/articles/{id}, /v1/articles/{id}/comments. Keep resource shapes consistent across endpoints -- the same Article object comes back from list, detail, and search.

Every resource has a stable id (ULID or UUIDv7 preferred; monotonic and sortable), created_at and updated_at in ISO 8601 UTC, and a version or etag for optimistic concurrency where applicable.

2. Pagination

Default to opaque cursor pagination. The cursor is a server-encoded token; clients must treat it as opaque bytes.

GET /v1/articles?limit=20&cursor=eyJpZCI6IjAxSFgifQ
{
  "items": [ /* ... */ ],
  "next_cursor": "eyJpZCI6IjAxSFkifQ",
  "has_more": true
}

Implementation (Node/TS, Postgres):

// server
const limit = Math.min(Number(req.query.limit ?? 20), 100);
const cursor = decodeCursor(req.query.cursor); // { id } | null
const rows = await db.query(
  `SELECT * FROM articles
     WHERE ($1::text IS NULL OR id < $1)
     ORDER BY id DESC
     LIMIT $2 + 1`,
  [cursor?.id ?? null, limit],
);
const hasMore = rows.length > limit;
const items = rows.slice(0, limit);
const nextCursor = hasMore ? encodeCursor({ id: items.at(-1)!.id }) : null;
res.json({ items, next_cursor: nextCursor, has_more: hasMore });

Client consumption (Kotlin, OkHttp):

suspend fun loadPage(cursor: String? = null): Page<Article> {
  val url = "https://api.example.com/v1/articles".toHttpUrl().newBuilder()
    .addQueryParameter("limit", "20")
    .apply { cursor?.let { addQueryParameter("cursor", it) } }
    .build()
  return http.get(url).parse<Page<Article>>()
}

Default page size 20, max 100. Clamp silently and echo the effective size.

3. Filtering and Sorting

Use flat query parameters, not nested JSON:

GET /v1/articles?author_id=123&tag=mobile&sort=-published_at
  • Prefix with - for descending (sort=-published_at).
  • Allow comma-separated multi-sort: sort=-published_at,title.
  • Restrict sortable and filterable fields to an allowlist; reject others with 400 INVALID_QUERY.
  • For ranges, use min_ / max_ prefixes: min_published_at=2026-01-01.

4. Partial Responses (Sparse Fieldsets)

Mobile screens rarely need every field. Support a fields parameter to reduce payload:

GET /v1/articles?fields=id,title,author.name

Server applies a projection before serialization. Unknown field names are ignored with a Warning header rather than rejecting the request.

5. Consistent Error Envelope

Every non-2xx response uses the same shape:

{
  "error": {
    "code": "VALIDATION_FAILED",
    "message": "title must not be empty",
    "details": { "field": "title" },
    "request_id": "01HX7..."
  }
}

code is stable across minor versions. Clients match on code, never on message.

6. Timestamps, Money, and Enums

  • Timestamps: RFC 3339 strings in UTC. Never Unix seconds without units.
  • Money: integer minor units plus ISO 4217 currency ({ "amount": 1299, "currency": "USD" }).
  • Enums: lowercase_snake strings; clients bucket unknown values as unknown.

7. Request Identification

Accept X-Request-Id from the client; generate one if missing and echo it. Clients log both their generated id and the server id for cross-referencing.

8. Compression and Caching

Enable gzip and br responses. Set Cache-Control: private, max-age=60 on list reads when data tolerance allows; use ETag + If-None-Match on detail reads to avoid re-downloading unchanged bodies.

Checklist

  • Every list endpoint paginated with opaque cursor and documented default/max limits.
  • Sparse fieldsets supported on payloads > ~2 KB.
  • All non-2xx responses use the shared error envelope with code, message, request_id.
  • Sortable and filterable fields are allowlisted and documented.
  • Timestamps are RFC 3339 UTC; money uses minor units + currency.
  • Unknown enum values documented as bucketed to unknown on the client.
  • X-Request-Id honored and echoed.
  • ETag / Cache-Control set on cacheable reads.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.