Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ glob = "0.3.1"
governor = "0.6"
heck = "0.5"
hex = "0.4"
http = "1.3.1"
http-body = "1.0.0"
http-body-util = "0.1.1"
hyper-tls = "0.5.0"
Expand Down
5 changes: 5 additions & 0 deletions out/errors/api.bad_request.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/common/api-builder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ axum.workspace = true
axum-extra.workspace = true
gas.workspace = true
chrono.workspace = true
http.workspace = true
hyper = { workspace = true, features = ["full"] }
lazy_static.workspace = true
opentelemetry.workspace = true
Expand Down
12 changes: 12 additions & 0 deletions packages/common/api-builder/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use rivet_error::*;
use serde::Serialize;

#[derive(RivetError)]
#[error("api", "not_found", "The requested resource was not found")]
Expand All @@ -19,3 +20,14 @@ pub struct ApiForbidden;
#[derive(RivetError)]
#[error("api", "internal_error", "An internal server error occurred")]
pub struct ApiInternalError;

#[derive(RivetError, Serialize)]
#[error(
"api",
"bad_request",
"Request is invalid",
"Request is invalid: {reason}"
)]
pub struct ApiBadRequest {
pub reason: String,
}
109 changes: 109 additions & 0 deletions packages/common/api-builder/src/extract.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
use anyhow::anyhow;
use axum::{
extract::{
Request,
rejection::{ExtensionRejection, JsonRejection},
{FromRequest, FromRequestParts},
},
response::IntoResponse,
};
use axum_extra::extract::QueryRejection;
use http::request::Parts;
use serde::Serialize;

use crate::{error_response::ApiError, errors::ApiBadRequest};

pub struct ExtractorError(ApiError);

impl IntoResponse for ExtractorError {
fn into_response(self) -> axum::response::Response {
let mut res = self.0.into_response();

res.extensions_mut().insert(FailedExtraction);

res
}
}

#[derive(Clone, Copy)]
pub struct FailedExtraction;

pub struct Json<T>(pub T);

impl<S, T> FromRequest<S> for Json<T>
where
axum::extract::Json<T>: FromRequest<S, Rejection = JsonRejection>,
S: Send + Sync,
{
type Rejection = ExtractorError;

async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection> {
axum::extract::Json::<T>::from_request(req, state)
.await
.map(|json| Json(json.0))
.map_err(|err| {
ExtractorError(
ApiBadRequest {
reason: err.body_text(),
}
.build()
.into(),
)
})
}
}

impl<T: Serialize> IntoResponse for Json<T> {
fn into_response(self) -> axum::response::Response {
let Self(value) = self;
axum::extract::Json(value).into_response()
}
}

pub struct Query<T>(pub T);

impl<S, T> FromRequestParts<S> for Query<T>
where
axum_extra::extract::Query<T>: FromRequestParts<S, Rejection = QueryRejection>,
S: Send + Sync,
{
type Rejection = ExtractorError;

async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
let res = axum_extra::extract::Query::<T>::from_request_parts(parts, state)
.await
.map(|query| Query(query.0))
.map_err(|err| {
ExtractorError(
ApiBadRequest {
reason: err.body_text(),
}
.build()
.into(),
)
});

res
}
}

pub struct Extension<T>(pub T);

impl<S, T> FromRequestParts<S> for Extension<T>
where
axum::extract::Extension<T>: FromRequestParts<S, Rejection = ExtensionRejection>,
S: Send + Sync,
{
type Rejection = ExtractorError;

async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
axum::extract::Extension::<T>::from_request_parts(parts, state)
.await
.map(|ext| Extension(ext.0))
.map_err(|err| {
ExtractorError(
anyhow!("developer error: extension error: {}", err.body_text()).into(),
)
})
}
}
1 change: 1 addition & 0 deletions packages/common/api-builder/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod context;
pub mod error_response;
pub mod errors;
pub mod extract;
pub mod global_context;
pub mod metrics;
pub mod middleware;
Expand Down
11 changes: 7 additions & 4 deletions packages/common/api-builder/src/wrappers.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
use anyhow::Result;
use axum::{
body::Bytes,
extract::{Extension, Path},
response::{IntoResponse, Json},
extract::Path,
response::IntoResponse,
routing::{
delete as axum_delete, get as axum_get, patch as axum_patch, post as axum_post,
put as axum_put,
},
};
use axum_extra::extract::Query;
use serde::{Serialize, de::DeserializeOwned};
use std::future::Future;

use crate::{context::ApiCtx, error_response::ApiError};
use crate::{
context::ApiCtx,
error_response::ApiError,
extract::{Extension, Json, Query},
};

/// Macro to generate wrapper functions for HTTP methods
macro_rules! create_method_wrapper {
Expand Down
2 changes: 1 addition & 1 deletion packages/common/config/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ pub struct Root {
impl Default for Root {
fn default() -> Self {
Root {
auth: None,
auth: Some(Auth::default()),
guard: None,
api_public: None,
api_peer: None,
Expand Down
8 changes: 5 additions & 3 deletions packages/core/api-public/src/actors/create.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use anyhow::Result;
use axum::{
extract::{Extension, Query},
http::HeaderMap,
response::{IntoResponse, Json, Response},
response::{IntoResponse, Response},
};
use rivet_api_builder::{
ApiError,
extract::{Extension, Json, Query},
};
use rivet_api_builder::ApiError;
use rivet_api_types::actors::create::{CreateRequest, CreateResponse};
use rivet_api_util::request_remote_datacenter;
use serde::{Deserialize, Serialize};
Expand Down
9 changes: 6 additions & 3 deletions packages/core/api-public/src/actors/delete.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use anyhow::Result;
use axum::{
extract::{Extension, Path, Query},
extract::Path,
http::HeaderMap,
response::{IntoResponse, Json, Response},
response::{IntoResponse, Response},
};
use rivet_api_builder::{
ApiError,
extract::{Extension, Json, Query},
};
use rivet_api_builder::ApiError;
use rivet_api_util::request_remote_datacenter_raw;
use rivet_util::Id;
use serde::{Deserialize, Serialize};
Expand Down
8 changes: 5 additions & 3 deletions packages/core/api-public/src/actors/get_or_create.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use anyhow::Result;
use axum::{
extract::{Extension, Query},
http::HeaderMap,
response::{IntoResponse, Json, Response},
response::{IntoResponse, Response},
};
use rivet_api_builder::{
ApiError,
extract::{Extension, Json, Query},
};
use rivet_api_builder::ApiError;
use rivet_types::actors::CrashPolicy;
use rivet_util::Id;
use serde::{Deserialize, Serialize};
Expand Down
8 changes: 5 additions & 3 deletions packages/core/api-public/src/actors/list.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use anyhow::{Context, Result};
use axum::{
extract::{Extension, Query},
http::HeaderMap,
response::{IntoResponse, Json, Response},
response::{IntoResponse, Response},
};
use rivet_api_builder::{
ApiError,
extract::{Extension, Json, Query},
};
use rivet_api_builder::ApiError;
use rivet_api_types::pagination::Pagination;
use rivet_api_util::fanout_to_datacenters;
use serde::{Deserialize, Serialize};
Expand Down
8 changes: 5 additions & 3 deletions packages/core/api-public/src/actors/list_names.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use anyhow::Result;
use axum::{
extract::{Extension, Query},
http::HeaderMap,
response::{IntoResponse, Json, Response},
response::{IntoResponse, Response},
};
use rivet_api_builder::{
ApiError,
extract::{Extension, Json, Query},
};
use rivet_api_builder::ApiError;
use rivet_api_types::{actors::list_names::*, pagination::Pagination};
use rivet_api_util::fanout_to_datacenters;
use rivet_types::actors::ActorName;
Expand Down
7 changes: 2 additions & 5 deletions packages/core/api-public/src/datacenters.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
use anyhow::Result;
use axum::{
extract::Extension,
response::{IntoResponse, Json, Response},
};
use rivet_api_builder::ApiError;
use axum::response::{IntoResponse, Json, Response};
use rivet_api_builder::{ApiError, extract::Extension};
use rivet_api_types::{datacenters::list::*, pagination::Pagination};
use rivet_types::datacenters::Datacenter;

Expand Down
8 changes: 5 additions & 3 deletions packages/core/api-public/src/namespaces.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use anyhow::Result;
use axum::{
extract::{Extension, Query},
http::HeaderMap,
response::{IntoResponse, Json, Response},
response::{IntoResponse, Response},
};
use rivet_api_builder::{
ApiError,
extract::{Extension, Json, Query},
};
use rivet_api_builder::ApiError;
use rivet_api_peer::namespaces::*;
use rivet_api_types::namespaces::list::*;
use rivet_api_util::request_remote_datacenter;
Expand Down
9 changes: 7 additions & 2 deletions packages/core/api-public/src/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use axum::{
response::{Redirect, Response},
};
use reqwest::header::{AUTHORIZATION, HeaderMap};
use rivet_api_builder::create_router;
use rivet_api_builder::{create_router, extract::FailedExtraction};
use utoipa::OpenApi;

use crate::{actors, ctx, datacenters, namespaces, runner_configs, runners, ui};
Expand Down Expand Up @@ -116,7 +116,12 @@ async fn auth_middleware(
let res = next.run(req).await;

// Verify auth was handled
if !ctx.is_auth_handled() {
if res.extensions().get::<FailedExtraction>().is_none()
&& path != "/"
&& path != "/ui"
&& !path.starts_with("/ui/")
&& !ctx.is_auth_handled()
{
return Err(format!(
"developer error: must explicitly handle auth in all endpoints (path: {path})"
));
Expand Down
9 changes: 6 additions & 3 deletions packages/core/api-public/src/runner_configs.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use anyhow::Result;
use axum::{
extract::{Extension, Path, Query},
extract::Path,
http::HeaderMap,
response::{IntoResponse, Json, Response},
response::{IntoResponse, Response},
};
use rivet_api_builder::{
ApiError,
extract::{Extension, Json, Query},
};
use rivet_api_builder::ApiError;

use rivet_api_peer::runner_configs::*;
use rivet_api_util::request_remote_datacenter;
Expand Down
8 changes: 5 additions & 3 deletions packages/core/api-public/src/runners.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use anyhow::Result;
use axum::{
extract::{Extension, Query},
http::HeaderMap,
response::{IntoResponse, Json, Response},
response::{IntoResponse, Response},
};
use rivet_api_builder::{
ApiError,
extract::{Extension, Json, Query},
};
use rivet_api_builder::ApiError;
use rivet_api_types::{pagination::Pagination, runners::list::*};
use rivet_api_util::fanout_to_datacenters;
use serde::{Deserialize, Serialize};
Expand Down
Loading