sozialhelden / wheelmap-classic

:wheelchair: Legacy "classic" wheelmap.org (deprecated)
http://www.wheelmap.org
GNU Affero General Public License v3.0
47 stars 16 forks source link

API Versioning #468

Open schultyy opened 7 years ago

schultyy commented 7 years ago

This is a ticket which describes the general approach we want to follow when it comes to API versioning. Over the time we collected quite some features which will modify the current API in a way that it's backwards incompatible for current mobile clients. To prevent breakage of the current installed base and ensure that we're able to ship new features the next step in the long term is to introduce a new API version. The one currently in production will be treated as v1, the next one then as v2.

This ticket shall be the place where we can discuss possible implementation strategies and when this is going to happen.

holgerd commented 7 years ago

Plan: 1 PT for estimation by @schultyy

schultyy commented 7 years ago

I start to line up some ideas and thoughts regarding this topic. The current API cannot be touched in terms of URL structure. This would probably break behavior with all mobile clients deployed right now. So what we will do is to keep the old urls alive (/api/<path>).

All new features will be living in the /api/v2/ namespace. A thing which remains to be decided is if we port all existing functionality to v2 as well or if this will be left in /api.

Hoverbear commented 7 years ago

@schultyy It may be valuable to think about what happens for /v3/, /v4/ etc.

For example, say we have v4 of the API do we want the client to have to consider which API version they need to call for each call? Maybe it would be better to say "If there is no /v4/foo then redirect to /v3/foo and so on.

schultyy commented 7 years ago

@Hoverbear Concerning the redirect: You mean issuing a HTTP redirect to the client then?

schultyy commented 7 years ago

The original API namespace has to be preserved: https://github.com/sozialhelden/wheelmap/blob/master/config/routes.rb#L113-L168 to ensure that currently deployed clients still work as expected.

Routes

Inside of the api namespace we will start to define namespaces for v2, v3 etc which then contain the routes to the respective endpoints.

Versions

A new namespace must be defined if an API change breaks current behavior. A breaking change can be one of the following:

Maintenance & Support

At some point we have to decide if it makes sense to drop support for legacy API versions. When do we drop support?

The big problem might be slow adoption of the new(er) API version(s) since users might not update Apps on their mobile devices frequently.

A sensible solution might be the following:

A new version comes out. From that point on new features are only introduced in the new API version. Older, now legacy API versions only receive (critical) bugfixes from now on.

schultyy commented 7 years ago

API Keys

Right now API Keys are passed via query parameter:

https://wheelmap.org/api/<path>?api_key=12345

For future API versions we might consider changing this because now they key will appear in web server logs and also will be cached since it's part of the URL.

schultyy commented 7 years ago

Follow up for API Keys:

Other APIs handle it like this for example:

Hoverbear commented 7 years ago

@schultyy No I mean on the server it just gets transparently passed down. :) The client never notices or cares. Using a 301 redirect would incur a round trip.

Hoverbear commented 7 years ago

I've used the Authorization header before and it works quite well. Well supported too!

schultyy commented 7 years ago

Concerning API Keys:

During my work on #512 I discovered that the iOS client is already using the X-API-KEY header. So it needs to be decided if X-API-KEY shall be kept and made the required way for all clients or the token shall be passed via the Authorization header.

schultyy commented 7 years ago

Also topic we need to look into: How do we communicate API documentation in future? Use the current format or switch to something like Swagger?

schultyy commented 7 years ago

Another topic we ran into the other day during work for another feature:

Right now API responses are rendered via acts_as_api. I would like to keep that library in for the old v1 API but replace it with something else for newer API versions. The reason for that is that API responses shouldn't be coupled with models directly. We will run into scenarios where a response schema doesn't match the database schema and [acts_as_api] is not well equipped for that case. I'm not saying it can't do that but that case is not in the main focus.

A better fit would be the representable gem. It decouples models from their API representations. It also doesn't require an instance of a model to be passed in, so if required we could also use view models instead.

schultyy commented 7 years ago

Adding some notes and results from discussions which took place over the last few days:

We agree on doing API versioning via HTTP Accept-Headers in order to be able to keep URL schemes stable and versioning per resource. With this approach, we will do one thing differently though compared to current best practices:

When a client does not specify any Accept Header or an Accept-Header but without any version it will always get the latest representation/behavior of the resource. Since wheelmap and all API clients started without being aware of different API versions they do not specify any version in the Accept-Header. If we would stick to the latest version of our API this will result in failures eventually because the clients as they are deployed right now expect v1 of any resource. So to still be able to deliver v1 to them, as a default without any Accept-Header or a version specified we will always default to v1.

From a technical point of view, it seems reasonable to use the Versionist gem.

A todo which results out of the decision to use Accept-Headers is, to define a media type the clients then have to use eventually.

holgerd commented 7 years ago

This is on hold for now.