« »
3/14/2015

[BrainDump] Versioning an HTTP API

I sometime share privately what I call a #BrainDump over a specific subject I just learned or thought about. A #BrainDump can be described as a snapshot of my current state of mind (or state of art in the current blog post) over a particular subject.

First step, let's specify an API version

    • ... in the header
      • cons:
        • requires an http client (curl/postman) to test endpoint
      • ... with accept (accept: application/vnd.haveibeenpwned+json; version=2.0)
        • pros:
          • allow the client to specify both a schema and a version
        • cons:
          • just like the other solutions, this one is also not standard: "Per the RFC, accept headers should only be used to specify the media type. Versioning is not media type, therefore using accept headers is IMO misuse.source
      • ... with user-defined header  (X-VersionX-Restful-Interface-Version)
    • ... in the URI
      • pros:
        • easy to try GET requests directly from the browser
      • cons:
        • not standard per HTTP RFC
        • does not respect REST principle
      • ... inside a sub-domain (v1.api.domain.com)
        • pros:
          • easy to configure backends with a reverse-proxy
      • ... inside the path 
        • format: /v1/
          • pros:
            • easy to configure backends with a reverse-proxy
          • used by:
        • format: /YYYYMMDD
          • pros:
            • the client does not need to remember API version
            • the client only asks for the API that was working at YYYYMMDD
          • cons:
            • between the client development and release the API may have changed
          • used by:
      • ... inside the query-string (?v=1)
        • wait, what?
    • ... once the request has been authenticated
      • assumption: each requests needs the be authenticated, then retrieve what API version the authenticated user has configured
      • pros:
        • easy to do analytics on API version usage
        • easy to inform users that access soon-to-be-removed API version
      • cons:
        • an authentication step is required
        • a user can only access to one API version at a time
        • no explicit contract between the client and the server 
        • the API version selection is hidden from the client
      • used by:

Then handle multiple API versions server-side

    • ... forwarding each request to the right API server using a reverse-proxy
      • pros:
        • stale API servers are easier to remove from production
      • cons:
        • it requires (at least) 2 running servers per API version
        • need to maintain multiple HTTP servers (branch) with security patches
        • need to maintain multiple running API servers in various versions
    • ... putting every version inside a single-code base, servers are load-balanced
      • each running server have to handle multiple-versions
      • pros:
        • a lot less duplicated code between handlers
        • easier server management
      • cons:
        • business models are often poluted with old behaviours
    • ... using an API migration middleware server (this is a work-in-progress)
      • assumption: the latest API version always exposes more data than the previous one
        • In other words the huge limitation of that approach is that changes HAVE TO be additive
      • how it works:
        • HTTP front <-> API Middleware Server (APIMS) <-> Up-to-date API Server (APIS)
          • for latency, both the APIMS and the APIS SHOULD be on the same node
          • for availability, of course both the APMS and APIS should be replicated across servers
        • Each HTTP request SHOULD go through the APIMS
          • if the request specify v4 and that latest API version is v6 the middleware
          • APIMS receiving request from client (asking for v4)
            •  -> up(req) (v4->v5)
              •  -> up(req) (v5->v6)
                •  -> forward request to APIS
                  • APIS (v6) process the request
                • <- APIS response
              • <- down(res) (v6->v5)
            • <- down(res) (v5->v4)
          • APIMS sending response to client
          • Note: it should be possible to bypass the APIMS if the requested API version is the latest one
        • a migration file CAN be implemented for each new version (vN-1->vN). Each migration file should implement the above interface
          • up(req: Request, next : Function(error))
            • used to update an API request from vN to vN+1
            • if an `error` is specified in `next` the APIMS can directly answer the request thus breaking the contract
          • down(res: Response, next: Function(error))
            • used to downgrade an API response from vN to vN-1
      • pros:
        • API versioning is decoupled from the API server
        • developers only needs to deploy the latest API version
        • devops only need to ensure the latest API version is running
      • cons:
        • does not handle every case 
          • e.g. a piece of data was available in v1 but is not available in v2 thus the middleware can't add it on the down stage

This post is simply an overview of documented practice, if you know (or better: use) other way to version HTTP API, don't hesitate to share them in the comment section below!
« »
 
 
Made with on a hot august night from an airplane the 19th of March 2017.