Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multiple versions of the same API #202

Merged
merged 3 commits into from
Mar 27, 2024
Merged

Support multiple versions of the same API #202

merged 3 commits into from
Mar 27, 2024

Conversation

jbearer
Copy link
Member

@jbearer jbearer commented Mar 26, 2024

This gives us the capability of making backwards-compatible updates
to a system in production, which in turn reduces the pressure to get
all of our APIs perfect before a launch.

If we want to remove a problematic endpoint or make backwards-incompatible
changes after release, we can release a new major version of the API with
those changes, and continue to serve the old version under a version prefix.
We can tell existing clients to point at the old version of the API, so they
can continue to run for some period of time before updating their software.

This also allows us to do hotfixes in production. For example, suppose there
is some bug which we cannot fix without a breaking change to the API. We can
add a new route with a /hotfix prefix or suffix. Only the affected clients
need to change their code to use the hotfix endpoint. In the next major version,
the hotfix endpoint can replace the original.

Note that we can add new methods and make other backwards-compatible changes
with only a minor version bump, which can replace the existing API instead
of deploying a new version.

Closes #185

jbearer added 3 commits March 25, 2024 15:53
This gives us the capability of making backwards-compatible updates
to a system in production, which in turn reduces the pressure to get
all of our APIs perfect before a launch.

If we want to remove a problematic endpoint or make backwards-incompatible
changes after release, we can release a new major version of the API with
those changes, and continue to serve the old version under a version prefix.
We can tell existing clients to point at the old version of the API, so they
can continue to run for some period of time before updating their software.

This also allows us to do hotfixes in production. For example, suppose there
is some bug which we cannot fix without a breaking change to the API. We can
add a new route with a `/hotfix` prefix or suffix. Only the affected clients
need to change their code to use the hotfix endpoint. In the next major version,
the hotfix endpoint can replace the original.

Note that we can add new methods and make other backwards-compatible changes
with only a minor version bump, which can replace the existing API instead
of deploying a new version.

Closes #185
Surf does not handle redirects correctly: it ends up sending the
same request multiple times _after_ the redirect, which is problematic
for methods with side-effects.
The rationale is that now a base URL like `https://hostname/v1` can
be passed into a client service, which can then access multiple API
modules from that URL, as long as all the modules support v1.
Different modules are still allowed to support different versions,
but this is not the common case.

This makes request parsing and routing a bit more complicated, but
things are greatly simplified by using a middleware to handle version
redirects. Now all the redirect code is isolated and separate from
the actual logic of handling routes.
@jbearer jbearer requested a review from nyospe March 26, 2024 21:02
Copy link
Contributor

@nyospe nyospe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Somewhat nervously, because this is a lot of changes for everything that uses tide-disco, but... 👍

@@ -683,7 +684,12 @@ pub fn app_api_path(org_name: &str, app_name: &str) -> PathBuf {
pub async fn wait_for_server(url: &Url, retries: u64, sleep_ms: u64) {
let dur = Duration::from_millis(sleep_ms);
for _ in 0..retries {
if surf::connect(url).send().await.is_ok() {
if reqwest::Client::new()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 for reqwest. If it wasn't for WebSocket support, I'd petition for replacing our other uses of surf as well.

@jbearer jbearer merged commit c2977e4 into main Mar 27, 2024
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

APIs with multiple supported versions
2 participants