diff options
| author | rtkay123 <dev@kanjala.com> | 2026-04-04 10:51:18 +0200 |
|---|---|---|
| committer | rtkay123 <dev@kanjala.com> | 2026-04-04 10:51:18 +0200 |
| commit | 19c25138f88acf19c9a959a58de4f58e54026ebc (patch) | |
| tree | bd854f20c539770a92fb451503b4c6d132c110a6 /crates/api-core | |
| parent | 41d90f42c37df06dabfd717d19f3dc72b5ba2d11 (diff) | |
| download | sellershut-19c25138f88acf19c9a959a58de4f58e54026ebc.tar.bz2 sellershut-19c25138f88acf19c9a959a58de4f58e54026ebc.zip | |
feat: connect to db
Diffstat (limited to 'crates/api-core')
| -rw-r--r-- | crates/api-core/Cargo.toml | 24 | ||||
| -rw-r--r-- | crates/api-core/src/auth/mod.rs | 9 | ||||
| -rw-r--r-- | crates/api-core/src/auth/provider.rs | 14 | ||||
| -rw-r--r-- | crates/api-core/src/health/apidoc.rs | 12 | ||||
| -rw-r--r-- | crates/api-core/src/health/mod.rs | 27 | ||||
| -rw-r--r-- | crates/api-core/src/lib.rs | 7 | ||||
| -rw-r--r-- | crates/api-core/src/models/mod.rs | 2 | ||||
| -rw-r--r-- | crates/api-core/src/models/user.rs | 1 | ||||
| -rw-r--r-- | crates/api-core/src/version.rs | 96 |
9 files changed, 192 insertions, 0 deletions
diff --git a/crates/api-core/Cargo.toml b/crates/api-core/Cargo.toml new file mode 100644 index 0000000..ae9f8f7 --- /dev/null +++ b/crates/api-core/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "api-core" +version = "0.0.0" +edition = "2024" +license.workspace = true +readme.workspace = true +documentation.workspace = true +homepage.workspace = true + +[dependencies] +axum = { workspace = true, optional = true } +serde.workspace = true +utoipa = { workspace = true, optional = true } + +[features] +auth = [] +auth-discord = ["auth"] +axum = ["dep:axum"] +users = [] +utoipa = ["dep:utoipa", "serde/derive", "axum"] + +[dev-dependencies] +tokio = { workspace = true, features = ["macros"] } +tower = { workspace = true, features = ["util"] } diff --git a/crates/api-core/src/auth/mod.rs b/crates/api-core/src/auth/mod.rs new file mode 100644 index 0000000..1045122 --- /dev/null +++ b/crates/api-core/src/auth/mod.rs @@ -0,0 +1,9 @@ +pub mod provider; + +pub struct AuthClientConfig { + pub client_id: String, + pub client_secret: String, + pub redirect_uri: String, + pub token_uri: String, + pub auth_url: String, +} diff --git a/crates/api-core/src/auth/provider.rs b/crates/api-core/src/auth/provider.rs new file mode 100644 index 0000000..803472f --- /dev/null +++ b/crates/api-core/src/auth/provider.rs @@ -0,0 +1,14 @@ +#[non_exhaustive] +/// The oauth provider +#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] +#[cfg_attr( + feature = "utoipa", + derive(utoipa::ToSchema, serde::Deserialize, serde::Serialize), + schema(example = "v0"), + serde(rename_all = "camelCase") +)] +pub enum OauthProvider { + /// Discord + #[cfg(feature = "auth-discord")] + Discord, +} diff --git a/crates/api-core/src/health/apidoc.rs b/crates/api-core/src/health/apidoc.rs new file mode 100644 index 0000000..45b8754 --- /dev/null +++ b/crates/api-core/src/health/apidoc.rs @@ -0,0 +1,12 @@ +use utoipa::OpenApi; + +use crate::Version; + +#[derive(OpenApi)] +#[openapi( + tags( + (name = "sellershut", description = "API health check"), + ), + components(schemas(Version)) +)] +pub struct ApiDocBase; diff --git a/crates/api-core/src/health/mod.rs b/crates/api-core/src/health/mod.rs new file mode 100644 index 0000000..a84dc85 --- /dev/null +++ b/crates/api-core/src/health/mod.rs @@ -0,0 +1,27 @@ +#[cfg(feature = "utoipa")] +mod apidoc; + +#[cfg(feature = "utoipa")] +pub use apidoc::*; + +#[derive(Default)] +pub struct BaseService; + +impl HealthDriver for BaseService {} + +pub trait HealthDriver: Send + Sync { + fn health(&self, app: &str, version: &str) -> String { + format!("{app} v{version} is live") + } +} + +#[cfg(test)] +mod tests { + use crate::health::{BaseService, HealthDriver}; + + #[test] + fn health() { + let app = BaseService.health(env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); + assert!(app.contains("is live")); + } +} diff --git a/crates/api-core/src/lib.rs b/crates/api-core/src/lib.rs new file mode 100644 index 0000000..8c22b49 --- /dev/null +++ b/crates/api-core/src/lib.rs @@ -0,0 +1,7 @@ +pub mod health; +pub mod models; +mod version; +pub use version::*; + +#[cfg(feature = "auth")] +pub mod auth; diff --git a/crates/api-core/src/models/mod.rs b/crates/api-core/src/models/mod.rs new file mode 100644 index 0000000..0f2db76 --- /dev/null +++ b/crates/api-core/src/models/mod.rs @@ -0,0 +1,2 @@ +#[cfg(feature = "users")] +pub mod user; diff --git a/crates/api-core/src/models/user.rs b/crates/api-core/src/models/user.rs new file mode 100644 index 0000000..e6ad9f0 --- /dev/null +++ b/crates/api-core/src/models/user.rs @@ -0,0 +1 @@ +pub struct User {} diff --git a/crates/api-core/src/version.rs b/crates/api-core/src/version.rs new file mode 100644 index 0000000..5f84f3e --- /dev/null +++ b/crates/api-core/src/version.rs @@ -0,0 +1,96 @@ +#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] +#[cfg_attr( + feature = "utoipa", + derive(utoipa::ToSchema, serde::Deserialize, serde::Serialize), + schema(example = "v0"), + serde(rename_all = "camelCase") +)] +pub enum Version { + V0, +} + +#[cfg(feature = "axum")] +mod request { + use super::*; + use axum::RequestPartsExt; + use axum::extract::{FromRequestParts, Path}; + use axum::http::StatusCode; + use axum::http::request::Parts; + use axum::response::{IntoResponse, Response}; + use std::collections::HashMap; + + impl<S> FromRequestParts<S> for Version + where + S: Send + Sync, + { + type Rejection = Response; + + async fn from_request_parts( + parts: &mut Parts, + _state: &S, + ) -> Result<Self, Self::Rejection> { + let params: Path<HashMap<String, String>> = + parts.extract().await.map_err(IntoResponse::into_response)?; + + let version = params + .get("apiVersion") + .ok_or_else(|| (StatusCode::NOT_FOUND, "version param missing").into_response())?; + + match version.as_str() { + "v0" => Ok(Version::V0), + _ => Err((StatusCode::NOT_FOUND, "unknown version").into_response()), + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use axum::{ + Router, + body::Body, + http::{Request, StatusCode}, + routing::get, + }; + use tower::ServiceExt; + + async fn handler(version: Version) -> &'static str { + match version { + Version::V0 => "ok", + } + } + + async fn check(endpoint: &str, expected: StatusCode) { + let app = app(); + let response = app + .oneshot( + Request::builder() + .uri(endpoint) + .body(Body::empty()) + .unwrap(), + ) + .await + .unwrap(); + assert_eq!(expected, response.status()); + } + + fn app() -> Router { + Router::new().route("/{apiVersion}/test", get(handler)) + } + + #[tokio::test] + async fn valid_version_v0() { + check("/v0/test", StatusCode::OK).await + } + + #[tokio::test] + async fn unknown_version() { + check("/v1/test", StatusCode::NOT_FOUND).await + } + + #[tokio::test] + async fn missing_version_param() { + check("/test", StatusCode::NOT_FOUND).await + } +} |
