Skip to content

Commit 135934e

Browse files
authored
support for specifying version numbers in API endpoints (#1115)
1 parent 32b50e1 commit 135934e

71 files changed

Lines changed: 3602 additions & 195 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.adoc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,16 @@ starter.start()
6363
+
6464
We'd like to remove the `HttpServerStarter` altogether, so let us know if you're still using it for some reason.
6565

66+
* https://github.com/oxidecomputer/dropshot/pull/1115[#1115] Dropshot now includes **experimental** support for hosting multiple versions of an API at a single server and routing to the correct version based on the incoming request. See documentation for details. If you don't care about this, you can mostly ignore it, but see "Breaking Changes" below.
67+
+
68+
By "experimental" we only mean that the API may change in upcoming releases.
69+
70+
=== Breaking Changes
71+
72+
* Dropshot now expects that APIs use https://semver.org/[Semver] values for their version string. Concretely, this only means that the `version` argument to `ApiDescription::openapi` (which generates an OpenAPI document) must be a `semver::Version`. Previously, it was `AsRef<str>`.
73+
* If you're invoking `ApiEndpoint::new` directly or constructing one as a literal (both of which are uncommon), you must provide a new `ApiEndpointVersions` value describing which versions this endpoint implements. You can use `ApiEndpointVersions::All` if you don't care about versioning.
74+
75+
6676
== 0.12.0 (released 2024-09-26)
6777

6878
https://github.com/oxidecomputer/dropshot/compare/v0.11.0\...v0.12.0[Full list of commits]

Cargo.lock

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dropshot/Cargo.toml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ percent-encoding = "2.3.1"
3232
rustls = "0.22.4"
3333
rustls-pemfile = "2.1.3"
3434
scopeguard = "1.2.0"
35+
semver = "1.0.23"
3536
serde_json = "1.0.132"
3637
serde_path_to_error = "0.1.16"
3738
serde_urlencoded = "0.7.1"
@@ -105,12 +106,15 @@ trybuild = "1.0.101"
105106
# Used by the https examples and tests
106107
pem = "3.0"
107108
rcgen = "0.13.1"
108-
# Using rustls-tls because it appears the rcgen-generated certificates are not
109-
# supported by the native Windows APIs.
110-
reqwest = { version = "0.12.9", features = ["json", "rustls-tls"] }
111109
# Used in a doc-test demonstrating the WebsocketUpgrade extractor.
112110
tokio-tungstenite = "0.24.0"
113111

112+
[dev-dependencies.reqwest]
113+
version = "0.12.9"
114+
# Using rustls-tls because it appears the rcgen-generated certificates are not
115+
# supported by the native Windows APIs.
116+
features = [ "json", "rustls-tls" ]
117+
114118
[dev-dependencies.rustls-pki-types]
115119
version = "1.10.0"
116120
# Needed for CertificateDer::into_owned

dropshot/examples/api-trait-alternate.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,14 +143,14 @@ mod api {
143143
pub(crate) counter: u64,
144144
}
145145

146-
// A simple function to generate an OpenAPI spec for the trait, without having
147-
// a real implementation available.
146+
// A simple function to generate an OpenAPI spec for the trait, without
147+
// having a real implementation available.
148148
//
149-
// If the interface and implementation (see below) are in different crates, then
150-
// this function would live in the interface crate.
149+
// If the interface and implementation (see below) are in different crates,
150+
// then this function would live in the interface crate.
151151
pub(crate) fn generate_openapi_spec() -> String {
152152
let api = counter_api_mod::stub_api_description().unwrap();
153-
let spec = api.openapi("Counter Server", "1.0.0");
153+
let spec = api.openapi("Counter Server", semver::Version::new(1, 0, 0));
154154
serde_json::to_string_pretty(&spec.json().unwrap()).unwrap()
155155
}
156156
}

dropshot/examples/api-trait-websocket.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,15 @@ mod api {
4343
pub(crate) counter: u8,
4444
}
4545

46-
// A simple function to generate an OpenAPI spec for the server, without having
47-
// a real implementation available.
46+
// A simple function to generate an OpenAPI spec for the server, without
47+
// having a real implementation available.
4848
//
49-
// If the interface and implementation (see below) are in different crates, then
50-
// this function would live in the interface crate.
49+
// If the interface and implementation (see below) are in different crates,
50+
// then this function would live in the interface crate.
5151
pub(crate) fn generate_openapi_spec() -> String {
5252
let my_server = counter_api_mod::stub_api_description().unwrap();
53-
let spec = my_server.openapi("Counter Server", "1.0.0");
53+
let spec =
54+
my_server.openapi("Counter Server", semver::Version::new(1, 0, 0));
5455
serde_json::to_string_pretty(&spec.json().unwrap()).unwrap()
5556
}
5657
}

dropshot/examples/api-trait.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,15 @@ mod api {
5454
pub(crate) counter: u64,
5555
}
5656

57-
// A simple function to generate an OpenAPI spec for the trait, without having
58-
// a real implementation available.
57+
// A simple function to generate an OpenAPI spec for the trait, without
58+
// having a real implementation available.
5959
//
60-
// If the interface and implementation (see below) are in different crates, then
61-
// this function would live in the interface crate.
60+
// If the interface and implementation (see below) are in different crates,
61+
// then this function would live in the interface crate.
6262
pub(crate) fn generate_openapi_spec() -> String {
6363
let description = counter_api_mod::stub_api_description().unwrap();
64-
let spec = description.openapi("Counter Server", "1.0.0");
64+
let spec = description
65+
.openapi("Counter Server", semver::Version::new(1, 0, 0));
6566
serde_json::to_string_pretty(&spec.json().unwrap()).unwrap()
6667
}
6768
}

dropshot/examples/petstore.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ fn main() -> Result<(), String> {
1212
api.register(update_pet_with_form).unwrap();
1313
api.register(find_pets_by_tags).unwrap();
1414

15-
api.openapi("Pet Shop", "")
15+
api.openapi("Pet Shop", semver::Version::new(1, 0, 0))
1616
.write(&mut std::io::stdout())
1717
.map_err(|e| e.to_string())?;
1818

dropshot/examples/schema-with-example.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ fn main() -> Result<(), String> {
5151
let mut api = ApiDescription::new();
5252
api.register(get_foo).unwrap();
5353

54-
api.openapi("Examples", "0.0.0")
54+
api.openapi("Examples", semver::Version::new(0, 0, 0))
5555
.write(&mut std::io::stdout())
5656
.map_err(|e| e.to_string())?;
5757

0 commit comments

Comments
 (0)