Handbook
  • πŸ‘‹Junction Handbook
  • ⛰️Why are we here?
    • πŸš€Vision and mission
    • πŸ“–Useful things to read
  • πŸ’₯How to Junction
    • πŸ’›Operating principles
    • πŸ“…Company Cadence
      • Weekly Standups
      • Biweekly All Hands
      • Biweekly Happy Hours
    • πŸ—£οΈCommunication
      • Guidelines
      • Effective communication
  • πŸ’ͺHow we'll support you
    • πŸ›«Onboarding
    • ✨Benefits
    • 🀝Share options
    • πŸ’¬Sharing your view
    • πŸ’΅Compensation
    • πŸ“”Policies
      • πŸ’³Expenses
      • πŸ–οΈVacations
      • πŸ§’Caregiver policy
  • πŸ› οΈEngineering
    • πŸ”°Engineering Values
    • πŸͺ—Engineering Cycles
    • 🎯Best Practices
      • API Design Guidelines
    • πŸ•£Managing Issues
      • ♨️Issue Priority
      • ⬇️Communicating Downtime
    • πŸ“žOn call
    • πŸš€Progression
      • πŸͺœEngineering Levels
        • Junior Engineer
        • Mid Engineer
        • Senior Engineer
        • Staff Engineer
Powered by GitBook
On this page
  • Schema designs
  • General
  • Vital API and Org Management API
  • Field naming
  • General
  • Standard fields
  • Pagination
  • General
  • Cursor-based pagination (Recommended)
  • Offset-based pagination
  • Resource Paths
  • Pathing hierarchical resources
  • Singular or Plural?
  • Standard Terminology
  1. Engineering
  2. Best Practices

API Design Guidelines

PreviousBest PracticesNextManaging Issues

Last updated 10 months ago

Schema designs

This document covers general API structure. For data schema design of specific vertical, check out the following:

General

Vital API and Org Management API

Core concepts:

  • Each Vital customer is represented as an Org.

  • Vital API comprises of multiple regional environments (US, EU, etc)

  • Within each Vital API regional environment, an Org can have one or more groups of Users, represented as Teams.

Vital API is the SaaS application plane:

  • βœ… It provides user management and order management capabilities for each Team.

  • βœ… It provides access to all structured data associated with Users and Orders.

  • βœ… It is responsible for ingesting new data, both via regular polling and receiving pushed data from providers and labs.

  • ❌ It cannot be used to inspect or change any settings of the Teams or the Orgs.

Org Management API is the SaaS control plane:

  • βœ… It provides administrative capability for the Orgs themselves, such as Billing and (Admin) Memberships.

  • βœ… It provides the means to create and delete Teams, as well as

  • βœ… It manages all aspects of Team configurations and settings.

  • ❌ It cannot be used to access users, orders, and associated data of any specific Team.

Case studies:

  • Considering the requirement for programmatically customizing Brand Information:

    • Brand Information is a team configuration.

    • Therefore, it should be exposed through the Org Management API.

  • Considering the requirement to expose Body Temperature data:

    • Body Temperature data are associated data of a User in a Team.

    • Therefore, it should be exposed through the Vital API.

Field naming

General

  • Prefer full name over abbreviation. Use abbreviation sparingly, and only when it is an established, unambiguous terms of art.

    • βœ… HRV instead of heart rate variability

    • βœ… API instead of application programming interface

    • ❌ HR instead of heart rate

    • ❌ DoB instead of date of birth

Standard fields

Pagination

General

Prefer cursor-based pagination whenever possible. For example:

  • The dataset only needs to be forward paginated.

  • The endpoint provides a comprehensive filtering and sorting options.

Use offset-based pagination only when the use case strictly requires:

  1. bidirectional pagination; and

  2. the ability to jump between pages.

… which is rarely observed in practice.

It is always preferrable to provide more filtering options β€” so that the result set can be narrowed down β€” over providing precise offset-based pagination to walk over the whole dataset.

Cursor-based pagination (Recommended)

Query parameter:

  • next_cursor (optional): The cursor for fetching the next page.

Response field:

  • The top-level item array (of the current page) should be named after the entity in plural form.

  • The cursor for the next page must be provided at $.next_cursor. If there is no more data, $.next_cursor must be null.

GET /v2/data?next_cursor=bm90IGlwc3VtIGxvcmVuIGlwc3Vt

{
  "credentials": [
    { ... },
    { ... },
  ],
  "next_cursor": "bG9yZW0gaXBzdW0gbG9yZW0gaXBzdW0="
}

Offset-based pagination

Query parameters:

  • page (optional): The page index to fetch; one-based.

  • size (optional): The page size to use.

Response field:

  • The top-level item array (of the current page) should be named after the entity in plural form.

  • $.page: The current page index; one-based.

  • $.size: The page size used.

  • $.pages: The total number of pages.

  • $.total: The total number of items.

GET /v2/lab_tests/markers?page=2

{
  "markers": [
    { ... },
    { ... },
  ],
  "total": 1000,
  "page": 2,
  "size": 50,
  "pages": 20
}

Resource Paths

Pathing hierarchical resources

General

  • Use underscore when a resource name comprises of multiple words. Do not use break it into multiple subpaths to refer to the one particular resource or one RPC method.

    • βœ… /team_etl_pipelines

    • ❌ /team/etl/pipelines

    • βœ… /introspect/historical_pull

    • ❌ /introspect/historical/pull

  • Custom RPC method should be an imperative clause (starting with a verb).

    • βœ… POST /billing/check_checkout_session

    • ❌ POST /billing/checkout_session

  • Cancellation should be a Custom RPC method.

    • It must not use the DELETE verb.

    • For cancellations that would result in resource deletion, consider calling these deletions instead of cancellations.

Top-level resources

A specific uniquely identifiable resource must be pathed as:

**resource**/{resource_id}

e.g., **user**/a13f0e7d-18a1-4262-a096-ee7319fa4692

Nested resources

If it is a nested resource, unless there is a compelling API ergonomic argument, it should be nested under its parent as:

**parent**/{parent_id}/**child**/{child_id}

e.g., **org**/{parent_id}/**team**/{team_id} in Org Management API

βœ… A compelling API ergonomic argument should include these factors:

  • A Death Valley in cardinality: The cardinality of the child resource is many orders of magnitude higher than that of the parent resource.

    • e.g., Vital API: team ↔ user & order

  • Requestor is the parent: The parent resource can be consistently inferred from the requestor authentication.

    • e.g., Vital API: team ↔ user & order β€” both can consistently infer the parent Team ID from requestor AuthN.

❌ An example of a non-compelling argument could be:

  • β€œOrg Management /v1/org/{}/team/{} should be shortened to /v1/team/{}.”

    • The domain was provisioned to support multiple Orgs, despite banning it at UX level.

    • We cannot consistently infer the Org from (at least) the Auth0 authentication, because an Auth0 user can be associated with multiple Orgs.

Singular or Plural?

RESTful collection resources

If a domain entity being exposed is representable as a RESTful collection resource, where you can:

  • List some or all resources, with optional filtering and sorting queries.

  • Retrieve one specific resource by its unique identifier or an alias like latest.

  • (Optionally) Create one new resource

  • (Optionally) Delete one existing resource by a unique identifier

  • (Optionally) Patch one existing resource by a unique identifier

You should use a singular path.

For example, for an API that exposes a collection of apples:

  • List all apples: GET /v3/apple

  • Get a specific apple: GET /v3/apple/{apple_id}

  • Create a new apple: POST /v3/apple

  • Delete a specific apple: DELETE /v3/apple/{apple_id}

  • Patch a specific apple: PATCH /v3/apple/{apple_id}

Using a singular noun ensures that all methods manipulating apples share a consistent URL prefix.

RPC-style resources

When in doubt, prefer singular.

Having said that, sometimes APIs cannot be represented as a RESTful collection resource. For example:

  • We have a deliberate reason not to provide the ability to retrieve individual resources.

  • The endpoint is an action (verb), rather than a resource (countable noun).

In these scenarios, you may use a plural name.

For example, in the Org Management API, the Team ETL Pipeline endpoints (as well as Team Custom Credentials, and Team API Keys) are all designed to be a set of RPC-style, **batch-**centric operations:

  • List all active Team ETL Pipeline config

    • GET /v1/org/{}/team_etl_pipelines/{env}/{region}

  • Set active Team ETL Pipeline config

    • POST /v1/org/{}/team_etl_pipelines/{env}/{region}

    • It has create-or-replace semantic, as well as broadcast semantic (set this config against multiple teams).

    • This endpoint does not satisfy the RESTful collection style.

  • Clear Team ETL Pipeline config

    • DELETE /v1/org/{}/team_etl_pipelines/{env}/{region}

    • Likewise, this endpoint has broadcast semantic for targeting multiple teams.

    • This endpoint does not satisfy the RESTful collection style.

So these endpoints use a /team_etl_pipeline**s**/** (plural) common prefix. This creates a subtle yet important distintion from RESTful collection resources which β€” as defined above β€” use singular noun in URL paths.

Custom RPC method on a resource

For endpoints that perform an action not fitting the RESTful verbs, name the endpoint with the verb or an imperative clause, and place it as a subpath under the subject being actioned. For example:

  1. POST /v1/org/{}/billing/check_checkout_session (imperative clause)

  2. POST /v3/order/testkit/register (verb)

  3. POST /v3/order/{}/cancel (verb)

These endpoints must use the POST HTTP verb.

Standard Terminology

See also:

See also:

Resource name should be singular. See .

Resource name should be singular. See .

πŸ› οΈ
🎯
Wearables Data Schema Guidelines
Standard fields
RPC-style resources
Custom RPC method on a resource
Singular or Plural?
Singular or Plural?
Terminology