API Design Patterns
API

API Design Patterns

John J. Geewax, 2021

Inhaltsverzeichnis des Buches

  • front matter
  • foreword
  • preface
  • acknowledgments
  • about this book
  • Who should read this book
  • How this book is organized: A roadmap
  • About the code
  • Live book discussion forum
  • Other online resources
  • about the author
  • about the cover illustration
  • Part 1 Introduction
  • 1 Introduction to APIs
  • 1.1 What are web APIs?
  • 1.2 Why do APIs matter?
  • 1.3 What are resource-oriented APIs?
  • 1.4 What makes an API “good”?
  • 1.4.1 Operational
  • 1.4.2 Expressive
  • 1.4.3 Simple
  • 1.4.4 Predictable
  • Summary
  • 2 Introduction to API design patterns
  • 2.1 What are API design patterns?
  • 2.2 Why are API design patterns important?
  • 2.3 Anatomy of an API design pattern
  • 2.3.1 Name and synopsis
  • 2.3.2 Motivation
  • 2.3.3 Overview
  • 2.3.4 Implementation
  • 2.3.5 Trade-offs
  • 2.4 Case study: Twapi, a Twitter-like API
  • 2.4.1 Overview
  • 2.4.2 Listing messages
  • 2.4.3 Exporting data
  • Summary
  • Part 2 Design principles
  • 3 Naming
  • 3.1 Why do names matter?
  • 3.2 What makes a name “good”?
  • 3.2.1 Expressive
  • 3.2.2 Simple
  • 3.2.3 Predictable
  • 3.3 Language, grammar, and syntax
  • 3.3.1 Language
  • 3.3.2 Grammar
  • 3.3.3 Syntax
  • 3.4 Context
  • 3.5 Data types and units
  • 3.6 Case study: What happens when you choose bad names?
  • 3.7 Exercises
  • Summary
  • 4 Resource scope and hierarchy
  • 4.1 What is resource layout?
  • 4.1.1 Types of relationships
  • 4.1.2 Entity relationship diagrams
  • 4.2 Choosing the right relationship
  • 4.2.1 Do you need a relationship at all?
  • 4.2.2 References or in-line data
  • 4.2.3 Hierarchy
  • 4.3 Anti-patterns
  • 4.3.1 Resources for everything
  • 4.3.2 Deep hierarchies
  • 4.3.3 In-line everything
  • 4.4 Exercises
  • Summary
  • 5 Data types and defaults
  • 5.1 Introduction to data types
  • 5.1.1 Missing vs. null
  • 5.2 Booleans
  • 5.3 Numbers
  • 5.3.1 Bounds
  • 5.3.2 Default values
  • 5.3.3 Serialization
  • 5.4 Strings
  • 5.4.1 Bounds
  • 5.4.2 Default values
  • 5.4.3 Serialization
  • 5.5 Enumerations
  • 5.6 Lists
  • 5.6.1 Atomicity
  • 5.6.2 Bounds
  • 5.6.3 Default values
  • 5.7 Maps
  • 5.7.1 Bounds
  • 5.7.2 Default values
  • 5.8 Exercises
  • Summary
  • Part 3 Fundamentals
  • 6 Resource identification
  • 6.1 What is an identifier?
  • 6.2 What makes a good identifier?
  • 6.2.1 Easy to use
  • 6.2.2 Unique
  • 6.2.3 Permanent
  • 6.2.4 Fast and easy to generate
  • 6.2.5 Unpredictable
  • 6.2.6 Readable, shareable, and verifiable
  • 6.2.7 Informationally dense
  • 6.3 What does a good identifier look like?
  • 6.3.1 Data type
  • 6.3.2 Character set
  • 6.3.3 Identifier format
  • 6.3.4 Checksums
  • 6.3.5 Resource type
  • 6.3.6 Hierarchy and uniqueness scope
  • 6.4 Implementation
  • 6.4.1 Size
  • 6.4.2 Generation
  • 6.4.3 Tomb-stoning
  • 6.4.4 Checksum
  • 6.4.5 Database storage
  • 6.5 What about UUIDs?
  • 6.6 Exercises
  • Summary
  • 7 Standard methods
  • 7.1 Motivation
  • 7.2 Overview
  • 7.3 Implementation
  • 7.3.1 Which methods should be supported?
  • 7.3.2 Idempotence and side effects
  • 7.3.3 Get
  • 7.3.4 List
  • 7.3.5 Create
  • 7.3.6 Update
  • 7.3.7 Delete
  • 7.3.8 Replace
  • 7.3.9 Final API definition
  • 7.4 Trade-offs
  • 7.5 Exercises
  • Summary
  • 8 Partial updates and retrievals
  • 8.1 Motivation
  • 8.1.1 Partial retrieval
  • 8.1.2 Partial update
  • 8.2 Overview
  • 8.3 Implementation
  • 8.3.1 Transport
  • 8.3.2 Maps and nested interfaces
  • 8.3.3 Repeated fields
  • 8.3.4 Default values
  • 8.3.5 Implicit field masks
  • 8.3.6 Updating dynamic data structures
  • 8.3.7 Invalid fields
  • 8.3.8 Final API definition
  • 8.4 Trade-offs
  • 8.4.1 Universal support
  • 8.4.2 Alternative implementations
  • 8.5 Exercises
  • Summary
  • 9 Custom methods
  • 9.1 Motivation
  • 9.1.1 Why not just standard methods?
  • 9.2 Overview
  • 9.3 Implementation
  • 9.3.1 Side effects
  • 9.3.2 Resources vs. collections
  • 9.3.3 Stateless custom methods
  • 9.3.4 Final API definition
  • 9.4 Trade-offs
  • 9.5 Exercises
  • Summary
  • 10 Long-running operations
  • 10.1 Motivation
  • 10.2 Overview
  • 10.3 Implementation
  • 10.3.1 What does an LRO look like?
  • 10.3.2 Resource hierarchy
  • 10.3.3 Resolution
  • 10.3.4 Error handling
  • 10.3.5 Monitoring progress
  • 10.3.6 Canceling operations
  • 10.3.7 Pausing and resuming operations
  • 10.3.8 Exploring operations
  • 10.3.9 Persistence
  • 10.3.10 Final API definition
  • 10.4 Trade-offs
  • 10.5 Exercises
  • Summary
  • 11 Rerunnable jobs
  • 11.1 Motivation
  • 11.2 Overview
  • 11.3 Implementation
  • 11.3.1 Job resources
  • 11.3.2 The custom run method
  • 11.3.3 Job execution resources
  • 11.3.4 Final API definition
  • 11.4 Trade-offs
  • 11.5 Exercises
  • Summary
  • Part 4 Resource relationships
  • 12 Singleton sub-resources
  • 12.1 Motivation
  • 12.1.1 Why should we use a singleton sub-resource?
  • 12.2 Overview
  • 12.3 Implementation
  • 12.3.1 Standard methods
  • 12.3.2 Resetting
  • 12.3.3 Hierarchy
  • 12.3.4 Final API definition
  • 12.4 Trade-offs
  • 12.4.1 Atomicity
  • 12.4.2 Exactly one sub-resource
  • 12.5 Exercises
  • Summary
  • 13 Cross references
  • 13.1 Motivation
  • 13.2 Overview
  • 13.3 Implementation
  • 13.3.1 Reference field name
  • 13.3.2 Data integrity
  • 13.3.3 Value vs. reference
  • 13.3.4 Final API definition
  • 13.4 Trade-offs
  • 11.5 Exercises
  • Summary
  • 14 Association resources
  • 14.1 Motivation
  • 14.2 Overview
  • 14.2.1 Association alias methods
  • 14.3 Implementation
  • 14.3.1 Naming the association resource
  • 14.3.2 Standard method behavior
  • 14.3.3 Uniqueness
  • 14.3.4 Read-only fields
  • 14.3.5 Association alias methods
  • 14.3.6 Referential integrity
  • 14.3.7 Final API definition
  • 14.4 Trade-offs
  • 14.4.1 Complexity
  • 14.4.2 Separation of associations
  • 14.5 Exercises
  • Summary
  • 15 Add and remove custom methods
  • 15.1 Motivation
  • 15.2 Overview
  • 15.3 Implementation
  • 15.3.1 Listing associated resources
  • 15.3.2 Data integrity
  • 15.3.3 Final API definition
  • 15.4 Trade-offs
  • 15.4.1 Nonreciprocal relationship
  • 15.4.2 Relationship metadata
  • 15.5 Exercises
  • Summary
  • 16 Polymorphism
  • 16.1 Motivation
  • 16.2 Overview
  • 16.3 Implementation
  • 16.3.1 Deciding when to use polymorphic resources
  • 16.3.2 Polymorphic structure
  • 16.3.3 Polymorphic behavior
  • 16.3.4 Why not polymorphic methods?
  • 16.3.5 Final API definition
  • 16.4 Trade-offs
  • 16.5 Exercises
  • Summary
  • Part 5 Collective operations
  • 17 Copy and move
  • 17.1 Motivation
  • 17.2 Overview
  • 17.3 Implementation
  • 17.3.1 Identifiers
  • 17.3.2 Child resources
  • 17.3.3 Related resources
  • 17.3.4 External data
  • 17.3.5 Inherited metadata
  • 17.3.6 Atomicity
  • 17.3.7 Final API definition
  • 17.4 Trade-offs
  • 17.5 Exercises
  • Summary
  • 18 Batch operations
  • 18.1 Motivation
  • 18.2 Overview
  • 18.3 Implementation
  • 18.3.1 Atomicity
  • 18.3.2 Operation on the collection
  • 18.3.3 Ordering of results
  • 18.3.4 Common fields
  • 18.3.5 Operating across parents
  • 18.3.6 Batch Get
  • 18.3.7 Batch Delete
  • 18.3.8 Batch Create
  • 18.3.9 Batch Update
  • 18.3.10 Final API definition
  • 18.4 Trade-offs
  • 18.5 Exercises
  • Summary
  • 19 Criteria-based deletion
  • 19.1 Motivation
  • 19.2 Overview
  • 19.3 Implementation
  • 19.3.1 Filtering results
  • 19.3.2 Validation only by default
  • 19.3.3 Result count
  • 19.3.4 Result sample set
  • 19.3.5 Consistency
  • 19.3.6 Final API definition
  • 19.4 Trade-offs
  • 19.5 Exercises
  • Summary
  • 20 Anonymous writes
  • 20.1 Motivation
  • 20.2 Overview
  • 20.3 Implementation
  • 20.3.1 Consistency
  • 20.3.2 Final API definition
  • 20.4 Trade-offs
  • 20.5 Exercises
  • Summary
  • 21 Pagination
  • 21.1 Motivation
  • 21.2 Overview
  • 21.3 Implementation
  • 21.3.1 Page size
  • 21.3.2 Page tokens
  • 21.3.3 Total count
  • 21.3.4 Paging inside resources
  • 21.3.5 Final API definition
  • 21.4 Trade-offs
  • 21.4.1 Bi-directional paging
  • 21.4.2 Arbitrary windows
  • 21.5 Anti-pattern: Offsets and limits
  • 21.6 Exercises
  • Summary
  • 22 Filtering
  • 22.1 Motivation
  • 22.2 Overview
  • 22.3 Implementation
  • 22.3.1 Structure
  • 22.3.2 Filter syntax and behavior
  • 22.3.3 Final API definition
  • 22.4 Trade-offs
  • 22.5 Exercises
  • Summary
  • 23 Importing and exporting
  • 23.1 Motivation
  • 23.2 Overview
  • 23.3 Implementation
  • 23.3.1 Import and export methods
  • 23.3.2 Interacting with storage systems
  • 23.3.3 Converting between resources and bytes
  • 23.3.4 Consistency
  • 23.3.5 Identifiers and collisions
  • 23.3.6 Handling related resources
  • 23.3.7 Failures and retries
  • 23.3.8 Filtering and field masks
  • 23.3.9 Final API definition
  • 23.4 Trade-offs
  • 23.5 Exercises
  • Summary
  • Part 6 Safety and security
  • 24 Versioning and compatibility
  • 24.1 Motivation
  • 24.2 Overview
  • 24.2.1 What is compatibility?
  • 24.2.2 Defining backward compatibility
  • 24.3 Implementation
  • 24.3.1 Perpetual stability
  • 24.3.2 Agile instability
  • 24.3.3 Semantic versioning
  • 24.4 Trade-offs
  • 24.4.1 Granularity vs. simplicity
  • 24.4.2 Stability vs. new functionality
  • 24.4.3 Happiness vs. ubiquity
  • 24.5 Exercises
  • Summary
  • 25 Soft deletion
  • 25.1 Motivation
  • 25.2 Overview
  • 25.3 Implementation
  • 25.3.1 Deleted designation
  • 25.3.2 Modifying standard methods
  • 25.3.3 Undeleting
  • 25.3.4 Expunging
  • 25.3.5 Expiration
  • 25.3.6 Referential integrity
  • 25.3.7 Effects on other methods
  • 25.3.8 Adding soft delete across versions
  • 25.3.9 Final API definition
  • 25.4 Trade-offs
  • 25.5 Exercises
  • Summary
  • 26 Request deduplication
  • 26.1 Motivation
  • 26.2 Overview
  • 26.3 Implementation
  • 26.3.1 Request identifier
  • 26.3.2 Response caching
  • 26.3.3 Consistency
  • 26.3.4 Request ID collisions
  • 26.3.5 Cache expiration
  • 26.3.6 Final API definition
  • 26.4 Trade-offs
  • 26.5 Exercises
  • Summary
  • 27 Request validation
  • 27.1 Motivation
  • 27.2 Overview
  • 27.3 Implementation
  • 27.3.1 External dependencies
  • 27.3.2 Special side effects
  • 27.3.3 Final API definition
  • 27.4 Trade-offs
  • 27.5 Exercises
  • Summary
  • 28 Resource revisions
  • 28.1 Motivation
  • 28.2 Overview
  • 28.3 Implementation
  • 28.3.1 Revision identifiers
  • 28.3.2 Creating revisions
  • 28.3.3 Retrieving specific revisions
  • 28.3.4 Listing revisions
  • 28.3.5 Restoring a previous revision
  • 28.3.6 Deleting revisions
  • 28.3.7 Handling child resources
  • 28.3.8 Final API definition
  • 28.4 Trade-offs
  • 28.5 Exercises
  • Summary
  • 29 Request retrial
  • 29.1 Motivation
  • 29.2 Overview
  • 29.2.1 Client-side retry timing
  • 29.2.2 Server-specified retry timing
  • 29.3 Implementation
  • 29.3.1 Retry eligibility
  • 29.3.2 Exponential back-off
  • 29.3.3 Retry After
  • 29.3.4 Final API definition
  • 29.4 Trade-offs
  • 29.5 Exercises
  • Summary
  • 30 Request authentication
  • 30.1 Motivation
  • 30.1.1 Origin
  • 30.1.2 Integrity
  • 30.1.3 Nonrepudiation
  • 30.2 Overview
  • 30.3 Implementation
  • 30.3.1 Credential generation
  • 30.3.2 Registration and credential exchange
  • 30.3.3 Generating and verifying raw signatures
  • 30.3.4 Request fingerprinting
  • 30.3.5 Including the signature
  • 30.3.6 Authenticating requests
  • 30.3.7 Final API definition
  • 30.4 Trade-offs
  • 30.5 Exercises
  • Summary
  • index