From 71fa86ceb9eac5d182efb0486262b5d7f3bd2f69 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Mon, 29 May 2023 15:42:33 +0200 Subject: [PATCH] Add a /version API endpoint * Introduce the `VersionInfo` struct, build from the vergen environment variables * Add the `version` handler to construct and return the version info * Update the README --- README.md | 25 +++++++++++++++++++++++++ src/lib.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ac68da4..501d208 100644 --- a/README.md +++ b/README.md @@ -216,6 +216,31 @@ an address fails or if the position is out of bounds of the map, nothing is returned (HTTP 404). If the maps cannot/have not been downloaded or cached yet, a service unavailable error is returned (HTTP 503). +## Version endpoint + +The `/version` endpoint provides information of the current version and build +of the service. This can be used to check if it needs to be updated. +Again, there is no path and no query parameters, just: + +```http +GET /version +``` + +### Version responses + +The response uses the JSON format and typically looks like this: + +```json +{ + "version": "0.2.7", + "timestamp": "2023-05-29T13:34:34.701323159Z", + "git_sha": "bb5962d", + "git_timestamp": "2023-05-29T15:32:17.000000000+02:00" +} +``` + +(Build and git information in example output may be out of date.) + ## License Sinoptik is licensed under the MIT license (see the `LICENSE` file or diff --git a/src/lib.rs b/src/lib.rs index 5f4e85c..4abdda1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,6 +21,7 @@ use rocket::fairing::AdHoc; use rocket::http::Status; use rocket::response::Responder; use rocket::serde::json::Json; +use rocket::serde::Serialize; use rocket::{get, routes, Build, Request, Rocket, State}; use self::forecast::{forecast, Forecast, Metric}; @@ -84,13 +85,41 @@ impl<'r, 'o: 'r> Responder<'r, 'o> for Error { } } -/// Result type that defaults to [`Error`] as the default error type. -pub(crate) type Result = std::result::Result; - #[derive(Responder)] #[response(content_type = "image/png")] struct PngImageData(Vec); +/// Result type that defaults to [`Error`] as the default error type. +pub(crate) type Result = std::result::Result; + +/// The version information as JSON response. +#[derive(Debug, Serialize)] +#[serde(crate = "rocket::serde")] +struct VersionInfo { + /// The version of the build. + version: String, + + /// The timestamp of the build. + timestamp: String, + + /// The (most recent) git SHA used for the build. + git_sha: String, + + /// The timestamp of the last git commit used for the build. + git_timestamp: String, +} +impl VersionInfo { + /// Retrieves the version information from the environment variables. + fn new() -> Self { + Self { + version: String::from(env!("CARGO_PKG_VERSION")), + timestamp: String::from(env!("VERGEN_BUILD_TIMESTAMP")), + git_sha: String::from(&env!("VERGEN_GIT_SHA")[0..7]), + git_timestamp: String::from(env!("VERGEN_GIT_COMMIT_TIMESTAMP")), + } + } +} + /// Handler for retrieving the forecast for an address. #[get("/forecast?
&")] async fn forecast_address( @@ -150,6 +179,12 @@ async fn map_geo( image_data.map(PngImageData) } +/// Returns the version information. +#[get("/version", format = "application/json")] +async fn version() -> Result> { + Ok(Json(VersionInfo::new())) +} + /// Sets up Rocket. fn rocket(maps_handle: MapsHandle) -> Rocket { let maps_refresher = maps::run(Arc::clone(&maps_handle)); @@ -157,7 +192,13 @@ fn rocket(maps_handle: MapsHandle) -> Rocket { rocket::build() .mount( "/", - routes![forecast_address, forecast_geo, map_address, map_geo], + routes![ + forecast_address, + forecast_geo, + map_address, + map_geo, + version + ], ) .manage(maps_handle) .attach(AdHoc::on_liftoff("Maps refresher", |_| {