Skip to content

Design for evolution

No version in the path

An HTTP API SHOULD NOT carry a version (number) in its URL.

Bad example

GET /v1/movies/

Instead, the API altogether should be designed with evolution in mind.

Design schema for change

When designing a JSON schema for the given purpose, later change should always be considered. Since clients SHOULD disregard additional or unexpected fields (robustness principle), this leaves room for good design choices.

Badly evolvable

{
  "title": "Love Actually",
  "releaseYear": "2003",
  "coverImage": "https://some.cdn/covers/thumb/IfyM3jlk.jpg"
}

Well evolvable instead

{
  "title": "Love Actually",
  "release":
    {
      "year": "2003"
    },
  "cover":
    {
      "url": "https://some.cdn/covers/thumb/IfyM3jlk.jpg"
    }
}

# ... can easily and non-backward-breakingly evolve into…

{
  "title": "Love Actually",
  "release":
    {
      "year": "2003"
    },
  "globalReleaseDates":
    [
      {"date": "2003-11-19", "country": "DE"},
      // …
    ]
  "cover":
    {
      "url": "https://some.cdn/covers/thumb/IfyM3jlk.jpg",
      "alt": "Official release poster",
      "width": 300,
      "height": 600
    }
}

When querying, the data would still be intuitively readable: * movie.release.year reads as well as * movie.releaseYear.

Consider collections early

Some items can be expected to evolve into multiple representations with time. Those should be designed as collections, even if it's only 1 in a first draft.

Bad:

"cover":
  {
    "url": "https://some.cdn/covers/thumb/IfyM3jlk.jpg",
    "alt": "Official release poster",
    "width": 300,
    "height": 600
  }

Good:

"media": [
  {
    "url": "https://some.cdn/covers/thumb/IfyM3jlk.jpg",
    "alt": "Official release poster",
    "mediaType": "image/jpeg",
    "purpose": "cover",
    "width": 300,
    "height": 600
  },{
    "url": "https://some.cdn/covers/huge/IfyM3jlk.jpg",
    "alt": "Official release poster",
    "mediaType": "image/jpeg",
    "purpose": "cover",
    "width": 3700,
    "height": 2800
  },{
    "url": "https://some.cdn/teasers-trailers/fAgmOOp44.mpg",
    "alt": "Teaser / Trailer",
    "mediaType": "video/mpeg",
    "purpose": "trailer",
    "width": 3700,
    "height": 2800
  }
]

Using fold methods in the client code it is simple to fetch the desired item if only one is required.