missing swagger data + using closure capture for immutable state
This commit is contained in:
+13
-2
@@ -12,6 +12,7 @@ use nym_bin_common::logging::{maybe_print_banner, setup_logging};
|
||||
use nym_bin_common::output_format::OutputFormat;
|
||||
use nym_bin_common::{bin_info, bin_info_owned};
|
||||
use nym_network_defaults::setup_env;
|
||||
use nym_node::http::api::v1::roles::NodeRoles;
|
||||
use std::error::Error;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
|
||||
@@ -56,8 +57,18 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
api: nym_node::http::api::Config {
|
||||
v1_config: nym_node::http::api::v1::Config {
|
||||
build_information: bin_info_owned!(),
|
||||
gateway: Default::default(),
|
||||
mixnide: Default::default(),
|
||||
roles: NodeRoles {
|
||||
mixnode_enabled: false,
|
||||
gateway_enabled: false,
|
||||
network_requester_enabled: false,
|
||||
},
|
||||
gateway: nym_node::http::api::v1::gateway::Config {
|
||||
details: Some(nym_node::http::api::v1::gateway::types::Gateway {
|
||||
encoded_identity_key: "aaa".to_string(),
|
||||
encoded_sphinx_key: "bbb".to_string(),
|
||||
}),
|
||||
},
|
||||
mixnode: Default::default(),
|
||||
network_requester: Default::default(),
|
||||
},
|
||||
},
|
||||
|
||||
@@ -13,6 +13,7 @@ license.workspace = true
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
bytes = "1.5.0"
|
||||
colored = "2"
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_yaml = "0.9.25"
|
||||
serde_json = { workspace = true }
|
||||
|
||||
@@ -6,13 +6,14 @@ use axum::{
|
||||
middleware::Next,
|
||||
response::IntoResponse,
|
||||
};
|
||||
use colored::*;
|
||||
use hyper::header::{HOST, USER_AGENT};
|
||||
use tracing::{debug, info};
|
||||
use tracing::info;
|
||||
|
||||
/// Simple logger for requests
|
||||
pub async fn logger<B>(req: Request<B>, next: Next<B>) -> impl IntoResponse {
|
||||
let method = req.method().to_string();
|
||||
let uri = req.uri().to_string();
|
||||
let method = req.method().to_string().green();
|
||||
let uri = req.uri().to_string().blue();
|
||||
let agent = header_map(
|
||||
req.headers().get(USER_AGENT),
|
||||
"Unknown User Agent".to_string(),
|
||||
@@ -22,8 +23,15 @@ pub async fn logger<B>(req: Request<B>, next: Next<B>) -> impl IntoResponse {
|
||||
|
||||
let res = next.run(req).await;
|
||||
let status = res.status();
|
||||
let print_status = if status.is_client_error() || status.is_server_error() {
|
||||
status.to_string().red()
|
||||
} else if status.is_success() {
|
||||
status.to_string().green()
|
||||
} else {
|
||||
status.to_string().yellow()
|
||||
};
|
||||
|
||||
info!("[{host}] {method} '{uri}': {status} / agent: {agent}");
|
||||
info!("[{host}] {method} '{uri}': {print_status} / agent: {agent}");
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ pub mod v1;
|
||||
|
||||
pub(crate) mod routes {
|
||||
pub(crate) const V1: &str = "/v1";
|
||||
pub(crate) const SWAGGER: &str = "/swagger";
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::http::router::api::{FormattedResponse, OutputParams};
|
||||
use crate::http::state::AppState;
|
||||
use axum::extract::{Query, State};
|
||||
use axum::extract::Query;
|
||||
use nym_bin_common::build_information::BinaryBuildInformationOwned;
|
||||
|
||||
/// Returns build metadata of the binary running the API
|
||||
@@ -11,6 +10,7 @@ use nym_bin_common::build_information::BinaryBuildInformationOwned;
|
||||
get,
|
||||
path = "/build-info",
|
||||
context_path = "/api/v1",
|
||||
tag = "Base",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
("application/json" = BinaryBuildInformationOwned),
|
||||
@@ -20,12 +20,11 @@ use nym_bin_common::build_information::BinaryBuildInformationOwned;
|
||||
params(OutputParams)
|
||||
)]
|
||||
pub(crate) async fn build_info(
|
||||
State(state): State<AppState>,
|
||||
build_information: BinaryBuildInformationOwned,
|
||||
Query(output): Query<OutputParams>,
|
||||
) -> BuildInfoResponse {
|
||||
let output = output.output.unwrap_or_default();
|
||||
// TODO: get rid of the clone since it's getting serialized anyway
|
||||
output.to_response(state.build_information.clone())
|
||||
output.to_response(build_information)
|
||||
}
|
||||
|
||||
pub type BuildInfoResponse = FormattedResponse<BinaryBuildInformationOwned>;
|
||||
|
||||
@@ -6,14 +6,23 @@ use axum::routing::get;
|
||||
use axum::Router;
|
||||
|
||||
pub mod root;
|
||||
pub mod types;
|
||||
|
||||
pub(crate) mod routes {
|
||||
pub(crate) const ROOT: &str = "/";
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Config {}
|
||||
|
||||
pub(crate) fn routes(_config: Config) -> Router<AppState> {
|
||||
Router::new().route(routes::ROOT, get(root::root_gateway))
|
||||
pub struct Config {
|
||||
pub details: Option<types::Gateway>,
|
||||
}
|
||||
|
||||
pub(crate) fn routes(config: Config) -> Router<AppState> {
|
||||
Router::new().route(
|
||||
routes::ROOT,
|
||||
get({
|
||||
let gateway_details = config.details;
|
||||
move |query| root::root_gateway(gateway_details, query)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,24 +1,33 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::NymNodeError;
|
||||
use crate::http::router::api::OutputParams;
|
||||
use crate::http::api::v1::gateway::types::Gateway;
|
||||
use crate::http::router::api::{FormattedResponse, OutputParams};
|
||||
use axum::extract::Query;
|
||||
use axum::http::StatusCode;
|
||||
use axum::response::IntoResponse;
|
||||
|
||||
/// Returns root gateway information
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "",
|
||||
context_path = "/api/v1/gateway",
|
||||
tag = "Gateway",
|
||||
responses(
|
||||
(status = 501, description = "the endpoint hasn't been implemented yet")
|
||||
(status = 501, description = "the endpoint hasn't been implemented yet"),
|
||||
(status = 200, content(
|
||||
("application/json" = Gateway),
|
||||
("application/yaml" = Gateway)
|
||||
))
|
||||
),
|
||||
params(OutputParams)
|
||||
)]
|
||||
pub(crate) async fn root_gateway(Query(_output): Query<OutputParams>) -> impl IntoResponse {
|
||||
(
|
||||
StatusCode::NOT_IMPLEMENTED,
|
||||
NymNodeError::Unimplemented.to_string(),
|
||||
)
|
||||
pub(crate) async fn root_gateway(
|
||||
details: Option<Gateway>,
|
||||
Query(output): Query<OutputParams>,
|
||||
) -> Result<GatewayResponse, StatusCode> {
|
||||
let details = details.ok_or(StatusCode::NOT_IMPLEMENTED)?;
|
||||
let output = output.output.unwrap_or_default();
|
||||
Ok(output.to_response(details))
|
||||
}
|
||||
|
||||
pub type GatewayResponse = FormattedResponse<Gateway>;
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use serde::Serialize;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
#[derive(Serialize, Debug, Clone, ToSchema)]
|
||||
pub struct Gateway {
|
||||
/// Base58 encoded ed25519 EdDSA public key of the gateway used for deriving shared keys with clients
|
||||
/// and for signing any messages
|
||||
pub encoded_identity_key: String,
|
||||
|
||||
/// Base58-encoded x25519 public key used for sphinx key derivation.
|
||||
pub encoded_sphinx_key: String,
|
||||
}
|
||||
@@ -2,13 +2,27 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::http::state::AppState;
|
||||
use axum::http::StatusCode;
|
||||
use axum::routing::get;
|
||||
use axum::Router;
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Config {}
|
||||
pub mod root;
|
||||
pub mod types;
|
||||
|
||||
pub(crate) fn routes(_config: Config) -> Router<AppState> {
|
||||
Router::new().route("/", get(|| async { StatusCode::NOT_IMPLEMENTED }))
|
||||
pub(crate) mod routes {
|
||||
pub(crate) const ROOT: &str = "/";
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Config {
|
||||
pub details: Option<types::Mixnode>,
|
||||
}
|
||||
|
||||
pub(crate) fn routes(config: Config) -> Router<AppState> {
|
||||
Router::new().route(
|
||||
routes::ROOT,
|
||||
get({
|
||||
let mixnode_details = config.details;
|
||||
move |query| root::root_mixnode(mixnode_details, query)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::http::api::v1::mixnode::types::Mixnode;
|
||||
use crate::http::router::api::{FormattedResponse, OutputParams};
|
||||
use axum::extract::Query;
|
||||
use axum::http::StatusCode;
|
||||
|
||||
/// Returns root mixnode information
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "",
|
||||
context_path = "/api/v1/mixnode",
|
||||
tag = "Mixnode",
|
||||
responses(
|
||||
(status = 501, description = "the endpoint hasn't been implemented yet"),
|
||||
(status = 200, content(
|
||||
("application/json" = Mixnode),
|
||||
("application/yaml" = Mixnode)
|
||||
))
|
||||
),
|
||||
params(OutputParams)
|
||||
)]
|
||||
pub(crate) async fn root_mixnode(
|
||||
details: Option<Mixnode>,
|
||||
Query(output): Query<OutputParams>,
|
||||
) -> Result<MixnodeResponse, StatusCode> {
|
||||
let details = details.ok_or(StatusCode::NOT_IMPLEMENTED)?;
|
||||
let output = output.output.unwrap_or_default();
|
||||
Ok(output.to_response(details))
|
||||
}
|
||||
|
||||
pub type MixnodeResponse = FormattedResponse<Mixnode>;
|
||||
@@ -0,0 +1,14 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use serde::Serialize;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
#[derive(Serialize, Debug, Clone, ToSchema)]
|
||||
pub struct Mixnode {
|
||||
/// Base58 encoded ed25519 EdDSA public key of the mixnode.
|
||||
pub encoded_identity_key: String,
|
||||
|
||||
/// Base58-encoded x25519 public key used for sphinx key derivation.
|
||||
pub encoded_sphinx_key: String,
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::http::api::v1::roles::NodeRoles;
|
||||
use crate::http::router::api::v1::build_info::build_info;
|
||||
use crate::http::router::api::v1::roles::roles;
|
||||
use crate::http::state::AppState;
|
||||
@@ -27,20 +28,33 @@ pub(crate) mod routes {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Config {
|
||||
pub build_information: BinaryBuildInformationOwned,
|
||||
pub roles: NodeRoles,
|
||||
pub gateway: gateway::Config,
|
||||
pub mixnide: mixnode::Config,
|
||||
pub mixnode: mixnode::Config,
|
||||
pub network_requester: network_requester::Config,
|
||||
}
|
||||
|
||||
pub(super) fn routes(config: Config) -> Router<AppState> {
|
||||
Router::new()
|
||||
.nest(routes::GATEWAY, gateway::routes(config.gateway))
|
||||
.nest(routes::MIXNODE, mixnode::routes(config.mixnide))
|
||||
.nest(routes::MIXNODE, mixnode::routes(config.mixnode))
|
||||
.nest(
|
||||
routes::NETWORK_REQUESTER,
|
||||
network_requester::routes(config.network_requester),
|
||||
)
|
||||
.route(routes::BUILD_INFO, get(build_info))
|
||||
.route(routes::ROLES, get(roles))
|
||||
.route(
|
||||
routes::BUILD_INFO,
|
||||
get({
|
||||
let build_information = config.build_information;
|
||||
move |query| build_info(build_information, query)
|
||||
}),
|
||||
)
|
||||
.route(
|
||||
routes::ROLES,
|
||||
get({
|
||||
let node_roles = config.roles;
|
||||
move |query| roles(node_roles, query)
|
||||
}),
|
||||
)
|
||||
.merge(openapi::route())
|
||||
}
|
||||
|
||||
@@ -2,13 +2,27 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::http::state::AppState;
|
||||
use axum::http::StatusCode;
|
||||
use axum::routing::get;
|
||||
use axum::Router;
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Config {}
|
||||
pub mod root;
|
||||
pub mod types;
|
||||
|
||||
pub(crate) fn routes(_config: Config) -> Router<AppState> {
|
||||
Router::new().route("/", get(|| async { StatusCode::NOT_IMPLEMENTED }))
|
||||
pub(crate) mod routes {
|
||||
pub(crate) const ROOT: &str = "/";
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Config {
|
||||
pub details: Option<types::NetworkRequester>,
|
||||
}
|
||||
|
||||
pub(crate) fn routes(config: Config) -> Router<AppState> {
|
||||
Router::new().route(
|
||||
routes::ROOT,
|
||||
get({
|
||||
let network_requester_details = config.details;
|
||||
move |query| root::root_network_requester(network_requester_details, query)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::http::api::v1::network_requester::types::NetworkRequester;
|
||||
use crate::http::router::api::{FormattedResponse, OutputParams};
|
||||
use axum::extract::Query;
|
||||
use axum::http::StatusCode;
|
||||
|
||||
/// Returns root network requester information
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "",
|
||||
context_path = "/api/v1/network-requester",
|
||||
tag = "Network Requester",
|
||||
responses(
|
||||
(status = 501, description = "the endpoint hasn't been implemented yet"),
|
||||
(status = 200, content(
|
||||
("application/json" = NetworkRequester),
|
||||
("application/yaml" = NetworkRequester)
|
||||
))
|
||||
),
|
||||
params(OutputParams)
|
||||
)]
|
||||
pub(crate) async fn root_network_requester(
|
||||
details: Option<NetworkRequester>,
|
||||
Query(output): Query<OutputParams>,
|
||||
) -> Result<NetworkRequesterResponse, StatusCode> {
|
||||
let details = details.ok_or(StatusCode::NOT_IMPLEMENTED)?;
|
||||
let output = output.output.unwrap_or_default();
|
||||
Ok(output.to_response(details))
|
||||
}
|
||||
|
||||
pub type NetworkRequesterResponse = FormattedResponse<NetworkRequester>;
|
||||
@@ -0,0 +1,14 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use serde::Serialize;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
#[derive(Serialize, Debug, Clone, ToSchema)]
|
||||
pub struct NetworkRequester {
|
||||
/// Base58 encoded ed25519 EdDSA public key of the network requester.
|
||||
pub encoded_identity_key: String,
|
||||
|
||||
/// Base58-encoded x25519 public key used for performing key exchange with remote clients.
|
||||
pub encoded_sphinx_key: String,
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::roles::NodeRoles;
|
||||
use crate::http::router::api;
|
||||
use crate::http::state::AppState;
|
||||
use axum::Router;
|
||||
@@ -8,28 +9,27 @@ use nym_bin_common::build_information::BinaryBuildInformationOwned;
|
||||
use utoipa::OpenApi;
|
||||
use utoipa_swagger_ui::SwaggerUi;
|
||||
|
||||
#[derive(OpenApi)]
|
||||
#[openapi(
|
||||
info(title = "NymNode API"),
|
||||
paths(api::v1::build_info::build_info, api::v1::gateway::root::root_gateway,),
|
||||
components(schemas(api::Output, api::OutputParams, BinaryBuildInformationOwned))
|
||||
)]
|
||||
/*
|
||||
#[derive(OpenApi)]
|
||||
#[openapi(
|
||||
info(title = "NymNode API"),
|
||||
paths(
|
||||
api::v1::build_info::build_info,
|
||||
api::v1::roles::roles,
|
||||
api::v1::gateway::root::root_gateway,
|
||||
api::v1::mixnode::root::root_mixnode,
|
||||
api::v1::network_requester::root::root_network_requester,
|
||||
),
|
||||
components(
|
||||
schemas(
|
||||
api::Output,
|
||||
api::OutputParams,
|
||||
BinaryBuildInformationOwned
|
||||
)
|
||||
)
|
||||
components(schemas(
|
||||
api::Output,
|
||||
api::OutputParams,
|
||||
BinaryBuildInformationOwned,
|
||||
NodeRoles,
|
||||
api::v1::gateway::types::Gateway,
|
||||
api::v1::mixnode::types::Mixnode,
|
||||
api::v1::network_requester::types::NetworkRequester,
|
||||
))
|
||||
)]
|
||||
*/
|
||||
|
||||
pub(crate) struct ApiDoc;
|
||||
|
||||
pub(crate) fn route() -> Router<AppState> {
|
||||
|
||||
@@ -1,23 +1,38 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::http::router::api::Output;
|
||||
use crate::http::router::api::{FormattedResponse, OutputParams};
|
||||
use axum::extract::Query;
|
||||
use axum::response::IntoResponse;
|
||||
use serde::Serialize;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
pub enum NodeRole {
|
||||
Mixnode {
|
||||
//
|
||||
},
|
||||
Gateway {
|
||||
//
|
||||
},
|
||||
NetworkRequester {
|
||||
//
|
||||
},
|
||||
#[derive(Clone, Debug, Copy, ToSchema, Serialize)]
|
||||
pub struct NodeRoles {
|
||||
pub mixnode_enabled: bool,
|
||||
pub gateway_enabled: bool,
|
||||
pub network_requester_enabled: bool,
|
||||
}
|
||||
|
||||
pub async fn roles(output: Query<Option<Output>>) -> impl IntoResponse {
|
||||
let output = output.unwrap_or_default();
|
||||
todo!()
|
||||
/// Returns roles supported by this node
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/roles",
|
||||
context_path = "/api/v1",
|
||||
tag = "Base",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
("application/json" = NodeRoles),
|
||||
("application/yaml" = NodeRoles)
|
||||
))
|
||||
),
|
||||
params(OutputParams)
|
||||
)]
|
||||
pub(crate) async fn roles(
|
||||
node_roles: NodeRoles,
|
||||
Query(output): Query<OutputParams>,
|
||||
) -> RolesResponse {
|
||||
let output = output.output.unwrap_or_default();
|
||||
output.to_response(node_roles)
|
||||
}
|
||||
|
||||
pub type RolesResponse = FormattedResponse<NodeRoles>;
|
||||
|
||||
@@ -37,7 +37,7 @@ pub struct NymNodeRouter {
|
||||
|
||||
impl NymNodeRouter {
|
||||
pub fn new(config: Config) -> NymNodeRouter {
|
||||
let state = AppState::new(config.api.v1_config.build_information.clone());
|
||||
let state = AppState::new();
|
||||
|
||||
NymNodeRouter {
|
||||
inner: Router::new()
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_bin_common::build_information::BinaryBuildInformationOwned;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -10,10 +9,12 @@ pub(crate) struct AppState {
|
||||
inner: Arc<AppStateInner>,
|
||||
}
|
||||
|
||||
// TODO: https://docs.rs/axum/latest/axum/extract/struct.State.html#substates
|
||||
|
||||
impl AppState {
|
||||
pub fn new(build_information: BinaryBuildInformationOwned) -> Self {
|
||||
pub fn new() -> Self {
|
||||
AppState {
|
||||
inner: Arc::new(AppStateInner { build_information }),
|
||||
inner: Arc::new(AppStateInner {}),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,7 +29,4 @@ impl Deref for AppState {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct AppStateInner {
|
||||
// TODO: split it based on routes?
|
||||
pub(crate) build_information: BinaryBuildInformationOwned,
|
||||
}
|
||||
pub(crate) struct AppStateInner {}
|
||||
|
||||
Reference in New Issue
Block a user