Add swagger for validator-api (#1239)

* validator-api: add swagger openapi

* Lock file
This commit is contained in:
Jon Häggblad
2022-05-03 12:25:53 +02:00
committed by durch
parent b8ce97e005
commit c77ccddcb3
11 changed files with 143 additions and 22 deletions
+3 -2
View File
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use rocket::fairing::AdHoc;
use rocket_okapi::openapi_get_routes;
use std::time::Duration;
pub(crate) mod local_guard;
@@ -18,7 +19,7 @@ pub(crate) fn stage_full() -> AdHoc {
AdHoc::on_ignite("Node Status API Stage", |rocket| async {
rocket.mount(
"/v1/status",
routes![
openapi_get_routes![
routes::mixnode_report,
routes::gateway_report,
routes::mixnode_uptime_history,
@@ -40,7 +41,7 @@ pub(crate) fn stage_minimal() -> AdHoc {
AdHoc::on_ignite("Node Status API Stage", |rocket| async {
rocket.mount(
"/v1/status",
routes![
openapi_get_routes![
routes::get_mixnode_status,
routes::get_mixnode_stake_saturation,
routes::get_mixnode_inclusion_probability,
+50 -6
View File
@@ -3,9 +3,16 @@
use crate::node_status_api::utils::NodeUptimes;
use crate::storage::models::NodeStatus;
use okapi::openapi3::{Responses, SchemaObject};
use rocket::http::{ContentType, Status};
use rocket::response::{self, Responder, Response};
use rocket::Request;
use rocket_okapi::gen::OpenApiGenerator;
use rocket_okapi::response::OpenApiResponderInner;
use rocket_okapi::util::ensure_status_code_exists;
use schemars::gen::SchemaGenerator;
use schemars::schema::{InstanceType, Schema};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;
use std::fmt::{self, Display, Formatter};
@@ -17,7 +24,7 @@ use time::OffsetDateTime;
pub struct InvalidUptime;
// value in range 0-100
#[derive(Clone, Copy, Serialize, Deserialize, Debug, Default)]
#[derive(Clone, Copy, Serialize, Deserialize, Debug, Default, JsonSchema)]
pub struct Uptime(u8);
impl Uptime {
@@ -97,7 +104,7 @@ impl TryFrom<i64> for Uptime {
}
}
#[derive(Clone, Serialize, Deserialize, Debug)]
#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema)]
pub struct MixnodeStatusReport {
pub(crate) identity: String,
pub(crate) owner: String,
@@ -134,7 +141,7 @@ impl MixnodeStatusReport {
}
}
#[derive(Clone, Serialize, Deserialize, Debug)]
#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema)]
pub struct GatewayStatusReport {
pub(crate) identity: String,
pub(crate) owner: String,
@@ -171,7 +178,7 @@ impl GatewayStatusReport {
}
}
#[derive(Clone, Serialize, Deserialize, Debug)]
#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema)]
pub struct MixnodeUptimeHistory {
pub(crate) identity: String,
pub(crate) owner: String,
@@ -189,7 +196,7 @@ impl MixnodeUptimeHistory {
}
}
#[derive(Clone, Serialize, Deserialize, Debug)]
#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema)]
pub struct GatewayUptimeHistory {
pub(crate) identity: String,
pub(crate) owner: String,
@@ -207,7 +214,7 @@ impl GatewayUptimeHistory {
}
}
#[derive(Clone, Serialize, Deserialize, Debug)]
#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema)]
pub struct HistoricalUptime {
// ISO 8601 date string
// I think this is more than enough, we don't need the uber precision of timezone offsets, etc
@@ -240,6 +247,43 @@ impl<'r, 'o: 'r> Responder<'r, 'o> for ErrorResponse {
}
}
impl JsonSchema for ErrorResponse {
fn schema_name() -> String {
"ErrorResponse".to_owned()
}
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
let mut schema_object = SchemaObject {
instance_type: Some(InstanceType::Object.into()),
..SchemaObject::default()
};
let object_validation = schema_object.object();
object_validation
.properties
.insert("error_message".to_owned(), gen.subschema_for::<String>());
object_validation
.required
.insert("error_message".to_owned());
// Status does not implement JsonSchema so we just explicitly specify the inner type.
object_validation
.properties
.insert("status".to_owned(), gen.subschema_for::<u16>());
object_validation.required.insert("status".to_owned());
Schema::Object(schema_object)
}
}
impl OpenApiResponderInner for ErrorResponse {
fn responses(_gen: &mut OpenApiGenerator) -> rocket_okapi::Result<Responses> {
let mut responses = Responses::default();
ensure_status_code_exists(&mut responses, 404);
Ok(responses)
}
}
#[derive(Debug, thiserror::Error)]
pub enum ValidatorApiStorageError {
MixnodeReportNotFound(String),
@@ -11,6 +11,7 @@ use mixnet_contract_common::reward_params::{NodeRewardParams, RewardParams};
use rocket::http::Status;
use rocket::serde::json::Json;
use rocket::State;
use rocket_okapi::openapi;
use validator_api_requests::models::{
CoreNodeStatusResponse, InclusionProbabilityResponse, MixnodeStatusResponse,
RewardEstimationResponse, StakeSaturationResponse,
@@ -18,6 +19,7 @@ use validator_api_requests::models::{
use super::models::Uptime;
#[openapi(tag = "mixnode")]
#[get("/mixnode/<identity>/report")]
pub(crate) async fn mixnode_report(
storage: &State<ValidatorApiStorage>,
@@ -30,6 +32,7 @@ pub(crate) async fn mixnode_report(
.map_err(|err| ErrorResponse::new(err.to_string(), Status::NotFound))
}
#[openapi(tag = "mixnode")]
#[get("/gateway/<identity>/report")]
pub(crate) async fn gateway_report(
storage: &State<ValidatorApiStorage>,
@@ -42,6 +45,7 @@ pub(crate) async fn gateway_report(
.map_err(|err| ErrorResponse::new(err.to_string(), Status::NotFound))
}
#[openapi(tag = "mixnode")]
#[get("/mixnode/<identity>/history")]
pub(crate) async fn mixnode_uptime_history(
storage: &State<ValidatorApiStorage>,
@@ -54,6 +58,7 @@ pub(crate) async fn mixnode_uptime_history(
.map_err(|err| ErrorResponse::new(err.to_string(), Status::NotFound))
}
#[openapi(tag = "mixnode")]
#[get("/gateway/<identity>/history")]
pub(crate) async fn gateway_uptime_history(
storage: &State<ValidatorApiStorage>,
@@ -66,6 +71,7 @@ pub(crate) async fn gateway_uptime_history(
.map_err(|err| ErrorResponse::new(err.to_string(), Status::NotFound))
}
#[openapi(tag = "mixnode")]
#[get("/mixnode/<identity>/core-status-count?<since>")]
pub(crate) async fn mixnode_core_status_count(
storage: &State<ValidatorApiStorage>,
@@ -83,6 +89,7 @@ pub(crate) async fn mixnode_core_status_count(
})
}
#[openapi(tag = "mixnode")]
#[get("/gateway/<identity>/core-status-count?<since>")]
pub(crate) async fn gateway_core_status_count(
storage: &State<ValidatorApiStorage>,
@@ -100,6 +107,7 @@ pub(crate) async fn gateway_core_status_count(
})
}
#[openapi(tag = "mixnode")]
#[get("/mixnode/<identity>/status")]
pub(crate) async fn get_mixnode_status(
cache: &State<ValidatorCache>,
@@ -110,6 +118,7 @@ pub(crate) async fn get_mixnode_status(
})
}
#[openapi(tag = "mixnode")]
#[get("/mixnode/<identity>/reward-estimation")]
pub(crate) async fn get_mixnode_reward_estimation(
cache: &State<ValidatorCache>,
@@ -165,6 +174,7 @@ pub(crate) async fn get_mixnode_reward_estimation(
}
}
#[openapi(tag = "mixnode")]
#[get("/mixnode/<identity>/stake-saturation")]
pub(crate) async fn get_mixnode_stake_saturation(
cache: &State<ValidatorCache>,
@@ -193,6 +203,7 @@ pub(crate) async fn get_mixnode_stake_saturation(
}
}
#[openapi(tag = "mixnode")]
#[get("/mixnode/<identity>/inclusion-probability")]
pub(crate) async fn get_mixnode_inclusion_probability(
cache: &State<ValidatorCache>,