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

Schema designs

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

  • Wearables Data Schema Guidelines

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

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

    • See also: RPC-style resources

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

    • βœ… POST /billing/check_checkout_session

    • ❌ POST /billing/checkout_session

    • See also: Custom RPC method on a resource

  • 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

Resource name should be singular. See Singular or Plural?.

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

Resource name should be singular. See Singular or Plural?.

βœ… 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

Terminology

PreviousBest PracticesNextManaging Issues

Last updated 10 months ago

πŸ› οΈ
🎯