Scille / parsec-cloud

Open source Dropbox-like file sharing with full client encryption !
https://parsec.cloud
Other
265 stars 40 forks source link

API versioning spec #2540

Open touilleMan opened 2 years ago

touilleMan commented 2 years ago

What is the API ?

The API refers to everything exchanged between Parsec clients or between Parsec client and Parsec server.

The different layers are:

api layer stored example
data yes FileManifest, UserCertificate
protocol no vlob_update, user_create
transport no Websocket + handshake, HTTP POST + authorization headers

What about local data ?

Data with only a local persistency (i.e. LocalManifest) are not currently part of the Data API.

The rational is to consider they are much easier to migrate to a new format: when a Parsec client starts it can choose to reuse the local data (regular case), apply a conversion to the local data (upgrade path 1) or to simply remove/ignore the incompatible data (upgrade path 2).

Upgrade path 1 is typically what is done when a change in the local data format is released while upgrade path 2 is taken when starting a new client on much older data (where the upgrade has been dropped) or an older client on newer data (i.e. rollback to a previous Parsec version).

However this is far form perfect:

So in a nutshell things work fine as long as Data API keeps as strict backward compatibility (i.e. only adding optional fields that can be omitted without changing the meaning of the rest of the data).

This is what has been observed so far, hence why the Data API has no version/revision information (unlike for the Transport/Protocol API), hence why we considered the local data as not part of the API.

Current status

As we said, Data API has no version/revision information, so full forward (client in version n can read data generated by client in version n-1) and backward (client in version n generate data that can be can read by client in version n-1) compatibility is expected.

Regarding Transport/Protocol API, parsec/api/version.py defines version/revision supported:

https://github.com/Scille/parsec-cloud/blob/7ba22e3ade40a4c28996a3f0e84f3467d2f5cfec/parsec/api/version.py#L11-L14

This is used during API handshake:

Currently there is three major versions of the Transport/Protocol API:

Breaking/non-breaking changes

So each time a change in the API breaks existing client we provide it a new major API version. On top of that, each time a modification on the API that extend without breakage, the revision of the API is bumped.

It should be noted that client and server don't have a symmetrical role when dealing with compatibility: if client and server have different API revisions we consider it's the client job to handle the differences.

If client is older than server (e.g. client in APIv2.3 vs server in APIv2.10):

If client is newer than server (e.g. client in APIv2.3 vs server in APIv2.0):

Non breaking changes

[^1]: In theory a new required field can also be added to the command response. But the field appear pretty much optional from the client point of view: it is always present on newer servers and never present on older ones.

Breaking changes

[^2]: In theory this is a non-breaking changes, though it is pretty much useless given the client has to handle compatibility with older server (hence seems just simpler to always send the field). On top it seems rather odd that turning a field optional would not modify the overall meaning of the command (the field should basically not be used in the first place).

Example

Considering the following fictional API changes:

api version change
1.0 add user_get
1.1 add user_create, user_get can return a new not_found status
1.2 modify user_get to add a page parameter
2.0 remove user_get

We would have:

server v1.0 server v1.1 server v1.2 server v2.0
client v1.0 ✔️ ✔️
client v1.1 ✔️ ✔️
client v1.2 ✔️
client v2.0

With:

FirelightFlagboy commented 2 years ago

the Data API has no version/revision information [...] we considered the local data as not part of the API.

Even if the data is not part of the Api, I recommend to add a version field to that data.