diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..dc7d3d9 --- /dev/null +++ b/.env.example @@ -0,0 +1,4 @@ +### このファイルの内容は .env ファイルで上書きできます + +# OpenAPI Schemaを取得するホスト +BACKEND_REST_HOST=http://localhost:8080 \ No newline at end of file diff --git a/.gitignore b/.gitignore index ea8c4bf..50fd5c8 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ /target +backend_api/ +.env \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 294f279..3bc2d47 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,21 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anstream" version = "0.6.18" @@ -133,6 +148,19 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "serde", + "windows-targets 0.52.6", +] + [[package]] name = "clap" version = "4.5.26" @@ -181,6 +209,7 @@ dependencies = [ "common", "confy", "dialoguer", + "openapi", "reqwest", "rpassword", "serde", @@ -241,6 +270,51 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + [[package]] name = "dialoguer" version = "0.11.0" @@ -421,13 +495,19 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap", + "indexmap 2.7.0", "slab", "tokio", "tokio-util", "tracing", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hashbrown" version = "0.15.2" @@ -440,6 +520,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "http" version = "1.2.0" @@ -552,6 +638,29 @@ dependencies = [ "tracing", ] +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "icu_collections" version = "1.5.0" @@ -670,6 +779,12 @@ dependencies = [ "syn", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "1.0.3" @@ -691,6 +806,17 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + [[package]] name = "indexmap" version = "2.7.0" @@ -698,7 +824,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.2", + "serde", ] [[package]] @@ -785,6 +912,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "miniz_oxide" version = "0.8.3" @@ -822,6 +959,21 @@ dependencies = [ "tempfile", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "object" version = "0.36.7" @@ -837,6 +989,19 @@ version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +[[package]] +name = "openapi" +version = "1.0.0" +dependencies = [ + "reqwest", + "serde", + "serde_json", + "serde_repr", + "serde_with", + "url", + "uuid", +] + [[package]] name = "openssl" version = "0.10.68" @@ -934,6 +1099,12 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "proc-macro2" version = "1.0.93" @@ -995,6 +1166,7 @@ dependencies = [ "js-sys", "log", "mime", + "mime_guess", "native-tls", "once_cell", "percent-encoding", @@ -1192,6 +1364,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_repr" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "serde_spanned" version = "0.6.8" @@ -1213,6 +1396,36 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_with" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" +dependencies = [ + "base64", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.7.0", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "server" version = "0.1.0" @@ -1376,6 +1589,37 @@ dependencies = [ "syn", ] +[[package]] +name = "time" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "tinystr" version = "0.7.6" @@ -1475,7 +1719,7 @@ version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap", + "indexmap 2.7.0", "serde", "serde_spanned", "toml_datetime", @@ -1534,6 +1778,12 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "unicase" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" + [[package]] name = "unicode-ident" version = "1.0.14" @@ -1588,6 +1838,7 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "744018581f9a3454a9e15beb8a33b017183f1e7c0cd170232a2d1453b23a51c4" dependencies = [ + "getrandom", "serde", ] @@ -1693,6 +1944,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-registry" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index f0f6023..9600bfc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,4 +4,5 @@ members = [ "common", "server", "client", + "backend_api", ] diff --git a/Makefile.toml b/Makefile.toml new file mode 100644 index 0000000..aeb3fd6 --- /dev/null +++ b/Makefile.toml @@ -0,0 +1,51 @@ +env_files = [{ path = ".env.example"}] +# Load .env file if it exists +env_scripts = [''' +#!@duckscript +if is_file .env + text = readfile .env + handle = map + map_load_properties ${handle} ${text} + set_env --handle ${handle} +end +'''] + + +[config] +default_to_workspace = false + +[tasks.openapi-fetch] +description = "Fetch latest OpenAPI schema" +command = "curl" +args = ["-o", "schema.yaml", "${BACKEND_REST_HOST}/api/schema.yaml"] + +[tasks.openapi-gen] +description = "Generate Rust client from OpenAPI schema" +command = "docker" +windows.env = { "PWD" = { script = ["cd"] } } +linux.env = { "UID" = { script = [ + "id -u", +] }, "GID" = { script = [ + "id -g", +] }, "OPTS" = "--user=${UID}:${GID}" } + +args = [ + "run", + "--rm", + "@@remove-empty(OPTS)", + "-v", + "${PWD}:/local", + "openapitools/openapi-generator-cli", + "generate", + "-i", + "/local/schema.yaml", + "-g", + "rust", + "-o", + "/local/backend_api", + "--skip-validate-spec", +] + +[tasks.openapi] +description = "Fetch and generate OpenAPI schema" +dependencies = ["openapi-fetch", "openapi-gen"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..bdab95f --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +# 前提条件 +## cargo-make +```sh +$ cargo install --force cargo-make +``` + +https://github.com/sagiegurari/cargo-make?tab=readme-ov-file#installation + + +# Build +## Generate OpenAPI Client +```sh +$ cargo make openapi-gen +``` \ No newline at end of file diff --git a/client/Cargo.toml b/client/Cargo.toml index 2fe833e..fa985e7 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -8,6 +8,7 @@ path = "src/main.rs" [dependencies] clap = { version = "4.5.26", features = ["derive"] } common = { path = "../common" } +openapi = { path = "../backend_api" } confy = "0.6.1" dialoguer = "0.11.0" reqwest = { version = "0.12.12", features = ["json"] } diff --git a/client/src/api_client.rs b/client/src/api_client.rs new file mode 100644 index 0000000..bb778f0 --- /dev/null +++ b/client/src/api_client.rs @@ -0,0 +1,7 @@ +use openapi::apis::configuration::Configuration; + +pub fn get_api_config(basepath: String) -> Configuration { + let mut conf = Configuration::new(); + conf.base_path = basepath; + conf +} diff --git a/client/src/commands/login.rs b/client/src/commands/login.rs index b076549..f21605e 100644 --- a/client/src/commands/login.rs +++ b/client/src/commands/login.rs @@ -1,8 +1,9 @@ use super::{Args, Command}; -use crate::config::{Config, ServerConfig}; -use crate::schema::api::{LoginRequest, LoginResponse}; +use crate::{ + api_client::get_api_config, + config::{Config, ServerConfig}, +}; use dialoguer::{Confirm, Input, Password}; -use reqwest::Client; use std::process::exit; use url::Url; @@ -60,7 +61,7 @@ impl Command for Login { let mut config = Config::load(); let server = ServerConfig { url, - token: Some(response_body.data.unwrap().token.token), + token: Some(response_body.token.token), }; config.servers.insert(self.server_name.clone(), server); if self.default { @@ -71,42 +72,49 @@ impl Command for Login { } } -async fn login(username: String, password: String, mut url: Url) -> LoginResponse { - let login_request = LoginRequest { username, password }; - url.set_path(&format!( - "{}/api/auth/login", - url.path().trim_end_matches('/') - )); - let response = Client::new().post(url).json(&login_request).send().await; +async fn login( + username: String, + password: String, + url: Url, +) -> openapi::models::UserWithTokenResponse { + let login_credential = openapi::models::LoginCredential { username, password }; + let conf = get_api_config(url.as_str().to_string()); + + let response = + openapi::apis::default_api::api_auth_login_post(&conf, Some(login_credential)).await; match response { - Ok(response) => { - let status = response.status(); - if !status.is_success() && status.as_u16() != 401 { - eprintln!("Request error: status {}", status.as_u16()); - eprintln!("Please check your internet connection or server URL and try again."); - exit(1); - } - let response_body = response.json::().await; - match response_body { - Ok(response_body) => { - if response_body.ok { - response_body - } else { - eprintln!("Login Failed!"); - eprintln!("Wrong username or password."); - eprintln!("Check your credentials."); + Ok(response) => *response.data, + Err(e) => match e { + openapi::apis::Error::ResponseError(response_content) => { + match response_content.entity { + Some(e) => match e { + openapi::apis::default_api::ApiAuthLoginPostError::UnknownValue(_value) => { + eprintln!("Login Failed!"); + eprintln!("Unknown Error {:?}", _value); + exit(1); + } + openapi::apis::default_api::ApiAuthLoginPostError::Status400(error) => { + eprint!("Login Failed!"); + eprintln!("Bad Request: {:?}", error); + exit(1); + } + openapi::apis::default_api::ApiAuthLoginPostError::Status401(_error) => { + eprintln!("Login Failed!"); + eprintln!("Wrong username or password."); + eprintln!("Check your credentials."); + exit(1); + } + }, + None => { + eprintln!("Invalid Response"); exit(1); } } - Err(e) => { - eprintln!("Invalid response: {}", e); - exit(1); - } } - } - Err(e) => { - eprintln!("Request error: {}", e); - exit(1); - } + e => { + eprintln!("Request error: {}", e); + exit(1); + } + }, } } diff --git a/client/src/commands/logout.rs b/client/src/commands/logout.rs index 9e676e1..000119f 100644 --- a/client/src/commands/logout.rs +++ b/client/src/commands/logout.rs @@ -1,7 +1,6 @@ use super::{Args, Command}; -use crate::schema::api::LogoutResponse; -use crate::Config; -use reqwest::{header, Client}; +use crate::{api_client::get_api_config, Config}; +use openapi::apis::default_api::api_auth_logout_post; use std::process::exit; use url::Url; @@ -29,44 +28,29 @@ impl Command for Logout { } } -async fn logout(token: String, mut url: Url) -> LogoutResponse { - url.set_path(&format!( - "{}/api/auth/logout", - url.path().trim_end_matches('/') - )); - let response = Client::new() - .post(url) - .header(header::AUTHORIZATION, format!("Bearer {}", token)) - .json(&{}) - .send() - .await; +async fn logout(token: String, url: Url) -> Option> { + let mut conf = get_api_config(url.as_str().to_string()); + conf.bearer_access_token = Some(token); + let response = api_auth_logout_post(&conf).await; match response { - Ok(response) => { - let status = response.status(); - if !status.is_success() { - eprintln!("Request error: status {}", status.as_u16()); - exit(1); - } - println!("{}", status.is_success()); - let response_body = response.json::().await; - match response_body { - Ok(response_body) => { - if response_body.ok { - response_body - } else { - eprintln!("Error: {}", response_body.message.unwrap()); + Ok(response) => response.data, + Err(e) => match e { + openapi::apis::Error::ResponseError(response_content) => { + match response_content.entity { + Some(e) => { + eprintln!("Error: {:?}", e); + exit(1); + } + None => { + eprintln!("Invalid response {}", response_content.status); exit(1); } - } - Err(ref e) => { - eprintln!("Invalid response: {}", e); - exit(1); } } - } - Err(e) => { - eprintln!("Request error: {}", e); - exit(1); - } + e => { + eprintln!("Request error: {}", e); + exit(1); + } + }, } } diff --git a/client/src/main.rs b/client/src/main.rs index 71d3a70..623ed24 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -2,9 +2,9 @@ use clap::Parser; use commands::Args; use config::Config; +mod api_client; mod commands; mod config; -mod schema; #[tokio::main] async fn main() { diff --git a/client/src/schema.rs b/client/src/schema.rs deleted file mode 100644 index e5fdf85..0000000 --- a/client/src/schema.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod api; diff --git a/client/src/schema/api.rs b/client/src/schema/api.rs deleted file mode 100644 index 34205e4..0000000 --- a/client/src/schema/api.rs +++ /dev/null @@ -1,38 +0,0 @@ -#![allow(dead_code)] -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -#[derive(Debug, Serialize)] -pub struct LoginRequest { - pub username: String, - pub password: String, -} - -#[derive(Debug, Deserialize)] -pub struct LoginResponse { - pub ok: bool, - pub data: Option, - pub message: Option, -} - -#[derive(Debug, Deserialize)] -pub struct LoginResponseData { - #[serde(rename = "userId")] - pub user_id: Uuid, - pub username: String, - pub token: LoginResponseToken, -} - -#[derive(Debug, Deserialize)] -pub struct LoginResponseToken { - pub token: String, - #[serde(rename = "expiresAt")] - pub expires_at: String, -} - -#[derive(Debug, Deserialize)] -pub struct LogoutResponse { - pub ok: bool, - pub data: Option, // Always returned null or empty - pub message: Option, -} diff --git a/schema.yaml b/schema.yaml new file mode 100644 index 0000000..b1b162e --- /dev/null +++ b/schema.yaml @@ -0,0 +1,886 @@ +openapi: 3.1.0 +info: + title: Freight API + description: Freight API + version: 1.0.0 +externalDocs: + url: / +servers: +- url: http://localhost:8080 + description: Development Server +tags: [] +paths: + /api/auth/login: + post: + tags: [] + parameters: [] + requestBody: + content: + application/json: + schema: + type: object + properties: + username: + type: string + title: String + password: + type: string + title: String + required: + - password + - username + title: LoginCredential + required: false + responses: + "200": + headers: {} + content: + application/json: + schema: + type: object + properties: + ok: + type: boolean + title: Boolean + data: + $ref: "#/components/schemas/UserWithTokenResponse" + required: + - data + - ok + title: Success + "400": + description: Bad Request + headers: {} + content: + application/json: + schema: + type: object + example: "{\"ok\":false,\"message\":\"Error Message\"}" + properties: + ok: + type: boolean + title: Boolean + message: + type: string + title: String + required: + - message + - ok + title: Error + "401": + description: Unauthorized + headers: {} + content: + application/json: + schema: + type: object + example: "{\"ok\":false,\"message\":\"Error Message\"}" + properties: + ok: + type: boolean + title: Boolean + message: + type: string + title: String + required: + - message + - ok + title: Error + deprecated: false + /api/auth/logout: + post: + tags: [] + parameters: [] + responses: + "200": + headers: {} + content: + application/json: + schema: + type: object + properties: + ok: + type: boolean + title: Boolean + data: + type: "null" + title: Unit + required: + - ok + title: Success + "401": + description: Unauthorized + headers: {} + content: + application/json: + schema: + type: object + example: "{\"ok\":false,\"message\":\"Error Message\"}" + properties: + ok: + type: boolean + title: Boolean + message: + type: string + title: String + required: + - message + - ok + title: Error + "500": + description: Internal Server Error + headers: {} + content: + application/json: + schema: + type: object + example: "{\"ok\":false,\"message\":\"Error Message\"}" + properties: + ok: + type: boolean + title: Boolean + message: + type: string + title: String + required: + - message + - ok + title: Error + deprecated: false + security: + - AppDefaultSecurityScheme: [] + /api/networks/create: + post: + tags: [] + parameters: [] + requestBody: + content: + application/json: + schema: + type: object + properties: + name: + type: string + title: String + networkAddress: + type: string + format: ipv4-cidr + example: 10.0.0.0/8 + title: NetworkAddressWithMask + containerAddress: + type: string + format: ipv4-cidr + example: 10.0.0.0/8 + title: NetworkAddressWithMask + clientAddress: + type: string + format: ipv4-cidr + example: 10.0.0.0/8 + title: NetworkAddressWithMask + required: + - clientAddress + - containerAddress + - name + - networkAddress + title: CreateNetworkRequest + required: false + responses: + "200": + headers: {} + content: + application/json: + schema: + type: object + properties: + ok: + type: boolean + title: Boolean + data: + $ref: "#/components/schemas/UserWithTokenResponse" + required: + - data + - ok + title: Success + "401": + description: Unauthorized + headers: {} + content: + application/json: + schema: + type: object + example: "{\"ok\":false,\"message\":\"Error Message\"}" + properties: + ok: + type: boolean + title: Boolean + message: + type: string + title: String + required: + - message + - ok + title: Error + "400": + description: Bad Request + headers: {} + content: + application/json: + schema: + type: object + example: "{\"ok\":false,\"message\":\"Error Message\"}" + properties: + ok: + type: boolean + title: Boolean + message: + type: string + title: String + required: + - message + - ok + title: Error + deprecated: false + security: + - AppDefaultSecurityScheme: [] + /api/networks/me: + get: + tags: [] + parameters: [] + responses: + "200": + headers: {} + content: + application/json: + schema: + type: object + properties: + ok: + type: boolean + title: Boolean + data: + type: array + items: + $ref: "#/components/schemas/Network" + title: ArrayList + required: + - data + - ok + title: Success + "401": + description: Unauthorized + headers: {} + content: + application/json: + schema: + type: object + example: "{\"ok\":false,\"message\":\"Error Message\"}" + properties: + ok: + type: boolean + title: Boolean + message: + type: string + title: String + required: + - message + - ok + title: Error + deprecated: false + security: + - AppDefaultSecurityScheme: [] + /api/networks/{owner}/{name}: + get: + tags: [] + parameters: + - name: owner + in: path + required: true + deprecated: false + explode: false + schema: + type: string + title: String + - name: name + in: path + required: true + deprecated: false + explode: false + schema: + type: string + title: String + responses: + "200": + headers: {} + content: + application/json: + schema: + type: object + properties: + ok: + type: boolean + title: Boolean + data: + $ref: "#/components/schemas/Network" + required: + - data + - ok + title: Success + "401": + description: Unauthorized + headers: {} + content: + application/json: + schema: + type: object + example: "{\"ok\":false,\"message\":\"Error Message\"}" + properties: + ok: + type: boolean + title: Boolean + message: + type: string + title: String + required: + - message + - ok + title: Error + "404": + description: Not Found + headers: {} + content: + application/json: + schema: + type: object + example: "{\"ok\":false,\"message\":\"Error Message\"}" + properties: + ok: + type: boolean + title: Boolean + message: + type: string + title: String + required: + - message + - ok + title: Error + deprecated: false + security: + - AppDefaultSecurityScheme: [] + /api/networks/{owner}/{name}/init: + post: + tags: [] + parameters: + - name: owner + in: path + required: true + deprecated: false + explode: false + schema: + type: string + title: String + - name: name + in: path + required: true + deprecated: false + explode: false + schema: + type: string + title: String + responses: + "200": + headers: {} + content: + application/json: + schema: + type: object + properties: + ok: + type: boolean + title: Boolean + data: + type: "null" + title: Unit + required: + - data + - ok + title: Success + "401": + description: Unauthorized + headers: {} + content: + application/json: + schema: + type: object + example: "{\"ok\":false,\"message\":\"Error Message\"}" + properties: + ok: + type: boolean + title: Boolean + message: + type: string + title: String + required: + - message + - ok + title: Error + "404": + description: Not Found + headers: {} + content: + application/json: + schema: + type: object + example: "{\"ok\":false,\"message\":\"Error Message\"}" + properties: + ok: + type: boolean + title: Boolean + message: + type: string + title: String + required: + - message + - ok + title: Error + deprecated: false + security: + - AppDefaultSecurityScheme: [] + /api/networks/{owner}/{name}/clean: + post: + tags: [] + parameters: + - name: owner + in: path + required: true + deprecated: false + explode: false + schema: + type: string + title: String + - name: name + in: path + required: true + deprecated: false + explode: false + schema: + type: string + title: String + responses: + "200": + headers: {} + content: + application/json: + schema: + type: object + properties: + ok: + type: boolean + title: Boolean + data: + type: "null" + title: Unit + required: + - data + - ok + title: Success + "401": + description: Unauthorized + headers: {} + content: + application/json: + schema: + type: object + example: "{\"ok\":false,\"message\":\"Error Message\"}" + properties: + ok: + type: boolean + title: Boolean + message: + type: string + title: String + required: + - message + - ok + title: Error + "404": + description: Not Found + headers: {} + content: + application/json: + schema: + type: object + example: "{\"ok\":false,\"message\":\"Error Message\"}" + properties: + ok: + type: boolean + title: Boolean + message: + type: string + title: String + required: + - message + - ok + title: Error + deprecated: false + security: + - AppDefaultSecurityScheme: [] + /api/users/me: + get: + tags: [] + parameters: [] + responses: + "200": + headers: {} + content: + application/json: + schema: + type: object + properties: + ok: + type: boolean + title: Boolean + data: + $ref: "#/components/schemas/UserResponse" + required: + - data + - ok + title: Success + "401": + description: Unauthorized + headers: {} + content: + application/json: + schema: + type: object + example: "{\"ok\":false,\"message\":\"Error Message\"}" + properties: + ok: + type: boolean + title: Boolean + message: + type: string + title: String + required: + - message + - ok + title: Error + deprecated: false + security: + - AppDefaultSecurityScheme: [] + /api/containers/create: + post: + tags: [] + parameters: [] + requestBody: + content: + application/json: + schema: + type: object + properties: + fullNetworkName: + type: string + example: naotiki/my-nw1 + title: String + required: + - fullNetworkName + title: CreateContainerRequest + required: false + responses: + "200": + headers: {} + content: + application/json: + schema: + type: object + properties: + ok: + type: boolean + title: Boolean + data: + $ref: "#/components/schemas/Container" + required: + - data + - ok + title: Success + "201": + description: Created + headers: {} + content: + application/json: + schema: + type: object + properties: + id: + type: string + format: uuid + title: Uuid + containerId: + type: string + title: DockerId + network: + $ref: "#/components/schemas/Network" + ipAddress: + type: integer + maximum: 4294967295 + minimum: 0 + title: IPv4Address + hostVEthName: + type: + - "null" + - string + title: NetworkInterfaceName + containerVEthName: + type: + - "null" + - string + title: NetworkInterfaceName + required: + - containerId + - id + - ipAddress + - network + title: Container + "401": + description: Unauthorized + headers: {} + content: + application/json: + schema: + type: object + example: "{\"ok\":false,\"message\":\"Error Message\"}" + properties: + ok: + type: boolean + title: Boolean + message: + type: string + title: String + required: + - message + - ok + title: Error + "400": + description: Bad Request + headers: {} + content: + application/json: + schema: + type: object + example: "{\"ok\":false,\"message\":\"Error Message\"}" + properties: + ok: + type: boolean + title: Boolean + message: + type: string + title: String + required: + - message + - ok + title: Error + "500": + description: Internal Server Error + headers: {} + content: + application/json: + schema: + type: object + example: "{\"ok\":false,\"message\":\"Error Message\"}" + properties: + ok: + type: boolean + title: Boolean + message: + type: string + title: String + required: + - message + - ok + title: Error + deprecated: false + security: + - AppDefaultSecurityScheme: [] +components: + schemas: + UserWithTokenResponse: + type: object + properties: + userId: + type: string + format: uuid + title: Uuid + username: + type: string + title: String + token: + $ref: "#/components/schemas/Token" + required: + - token + - userId + - username + title: UserWithTokenResponse + Token: + type: object + properties: + token: + type: string + title: String + expiresAt: + type: string + format: timestamp + title: Instant + required: + - expiresAt + - token + title: Token + Network: + type: object + properties: + id: + type: string + format: uuid + title: Uuid + numericId: + type: integer + maximum: 4294967295 + minimum: 0 + title: UInt + name: + type: string + title: String + networkAddressWithMask: + type: string + format: ipv4-cidr + example: 10.0.0.0/8 + title: NetworkAddressWithMask + containersNetworkAddressWithMask: + type: string + format: ipv4-cidr + example: 10.0.0.0/8 + title: NetworkAddressWithMask + clientsNetworkAddressWithMask: + type: string + format: ipv4-cidr + example: 10.0.0.0/8 + title: NetworkAddressWithMask + owner: + $ref: "#/components/schemas/User" + members: + type: array + items: + $ref: "#/components/schemas/NetworkMember" + title: ArrayList + dockerNetworkId: + type: + - "null" + - string + title: DockerId#6781840936060560326 + tunInterfaceName: + type: + - "null" + - string + title: NetworkInterfaceName + vrfInterfaceName: + type: + - "null" + - string + title: NetworkInterfaceName + bridgeInterfaceName: + type: + - "null" + - string + title: NetworkInterfaceName + required: + - clientsNetworkAddressWithMask + - containersNetworkAddressWithMask + - id + - members + - name + - networkAddressWithMask + - numericId + - owner + title: Network + User: + type: object + properties: + id: + type: string + format: uuid + title: Uuid + username: + type: string + title: String + required: + - id + - username + title: User + NetworkMember: + type: object + properties: + user: + $ref: "#/components/schemas/User" + permission: + $ref: "#/components/schemas/Permissions" + required: + - permission + - user + title: NetworkMember + Permissions: + type: string + enum: + - Owner + - Member + - Guest + title: Permissions + UserResponse: + type: object + properties: + id: + type: string + format: uuid + title: Uuid + username: + type: string + title: String + required: + - id + - username + title: UserResponse + Container: + type: object + properties: + id: + type: string + format: uuid + title: Uuid + containerId: + type: string + title: DockerId + network: + $ref: "#/components/schemas/Network" + ipAddress: + type: integer + maximum: 4294967295 + minimum: 0 + title: IPv4Address + hostVEthName: + type: + - "null" + - string + title: NetworkInterfaceName + containerVEthName: + type: + - "null" + - string + title: NetworkInterfaceName + required: + - containerId + - id + - ipAddress + - network + title: Container + examples: {} + securitySchemes: + AppDefaultSecurityScheme: + type: http + scheme: bearer diff --git a/server/proto b/server/proto new file mode 160000 index 0000000..b2e8120 --- /dev/null +++ b/server/proto @@ -0,0 +1 @@ +Subproject commit b2e812008b0ad6a29e9503c9f6d6d679b35c87a0