liveBook · Manning

Unique identifier

As explained in API Design Patterns

An identifier is a value that uniquely distinguishes an entity or resource within a relevant system or scope.

A unique identifier is a value that addresses exactly one resource within a defined scope, enabling lookup among a larger collection. Its uniqueness is contextual: a value may be unique among books, across an API, or—given a sufficiently large key space—in practice across all resources. section 6.1 section 6.2.2

Design identifiers to remain useful throughout an API’s lifetime:

  • Keep them permanent and single-use; never recycle an identifier after deletion, or historical references can point to different resources over time. section 6.2.3
  • Make common lookups simple by avoiding URI-reserved characters such as the forward slash. section 6.2.1
  • Generate identifiers quickly with predictable performance, rather than repeatedly searching for unused random values. section 6.2.4
  • Prefer an ASCII representation such as Crockford’s Base32, which avoids confusing characters, supports case-tolerant decoding, and permits optional hyphens. section 6.3.2 section 6.3.3
  • Add a checksum so clients can distinguish a mistyped identifier from a valid identifier that names no existing resource. section 6.2.6
  • Choose a predictable fixed size and match it to the required scope: roughly 13 Base32 characters for a type-local identifier or 25 for a UUID-scale identifier. section 6.4.1

Resource creation and lookup

A server can create a book with an identifier such as books/AHM6A83HENMP~ and later serve GET /books/AHM6A83HENMP~. The stored value should omit the checksum and any presentation metadata; validate the incoming identifier and calculate the checksum when returning it. section 6.4.1 section 6.4.5

Listing 6.1 Generating a random Base32-encoded identifier
const crypto = require('crypto');
const base32Encode = require('base32-encode');
 
function generateId(sizeBytes: number): string {   #1    
  const bytes = crypto.randomBytes(sizeBytes);     #2
  return base32Encode(bytes, 'Crockford');         #3
}

Generate the identifier from cryptographically random bytes and encode those bytes with Crockford’s Base32. section 6.4.2

Treat identifiers as opaque API values rather than embedded resource descriptions. Use strings for cross-resource references, expect references to become stale after deletion or movement, and add request identifiers for deduplicating sensitive non-idempotent operations when the trade-off is justified. section 13.2 section 26.4

How API Design Patterns covers it

How deep it goes
Explains scope, permanence, usability, generation, encoding, sizing, storage, references, and operational edge cases down to implementation guidance.
Examples
Uses people, books, companies, ISBNs, Base32 book paths, random-generation code, resource references, and operation identifiers.
What it assumes
Assumes API resources and lookup methods, while defining identifier properties and generation choices from their practical consequences.
What you can do after
Build it from scratch by selecting scope, format, size, generation, validation, storage, and reference policies for API resources.
How it connects
Connects unique identifiers with API resources, URIs, UUIDs, Unicode normalization, checksums, database storage, cross-references, and request deduplication.

Also explained in

Compare how 9 books explain unique identifier →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of API Design Patterns. The section links point to the parts of the book it draws on.