mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 00:49:42 +08:00
refactor(router): api-key routes refactoring (#600)
This commit is contained in:
@ -1,13 +1,9 @@
|
|||||||
use actix_web::{web, HttpRequest, Responder};
|
use actix_web::{web, HttpRequest, Responder};
|
||||||
use error_stack::{IntoReport, ResultExt};
|
|
||||||
use router_env::{instrument, tracing, Flow};
|
use router_env::{instrument, tracing, Flow};
|
||||||
|
|
||||||
use super::app::AppState;
|
use super::app::AppState;
|
||||||
use crate::{
|
use crate::{
|
||||||
core::{
|
core::api_keys,
|
||||||
api_keys,
|
|
||||||
errors::{self, RouterResult},
|
|
||||||
},
|
|
||||||
services::{api, authentication as auth},
|
services::{api, authentication as auth},
|
||||||
types::api as api_types,
|
types::api as api_types,
|
||||||
};
|
};
|
||||||
@ -18,7 +14,7 @@ use crate::{
|
|||||||
/// displayed only once on creation, so ensure you store it securely.
|
/// displayed only once on creation, so ensure you store it securely.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
post,
|
post,
|
||||||
path = "/api_keys",
|
path = "/api_keys/{merchant_id)",
|
||||||
request_body= CreateApiKeyRequest,
|
request_body= CreateApiKeyRequest,
|
||||||
responses(
|
responses(
|
||||||
(status = 200, description = "API Key created", body = CreateApiKeyResponse),
|
(status = 200, description = "API Key created", body = CreateApiKeyResponse),
|
||||||
@ -31,17 +27,18 @@ use crate::{
|
|||||||
pub async fn api_key_create(
|
pub async fn api_key_create(
|
||||||
state: web::Data<AppState>,
|
state: web::Data<AppState>,
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
|
path: web::Path<String>,
|
||||||
json_payload: web::Json<api_types::CreateApiKeyRequest>,
|
json_payload: web::Json<api_types::CreateApiKeyRequest>,
|
||||||
) -> impl Responder {
|
) -> impl Responder {
|
||||||
let payload = json_payload.into_inner();
|
let payload = json_payload.into_inner();
|
||||||
|
let merchant_id = path.into_inner();
|
||||||
|
|
||||||
api::server_wrap(
|
api::server_wrap(
|
||||||
state.get_ref(),
|
state.get_ref(),
|
||||||
&req,
|
&req,
|
||||||
payload,
|
payload,
|
||||||
|state, _, payload| async {
|
|state, _, payload| async {
|
||||||
let merchant_id = get_merchant_id_header(&req)?;
|
api_keys::create_api_key(&*state.store, payload, merchant_id.clone()).await
|
||||||
api_keys::create_api_key(&*state.store, payload, merchant_id).await
|
|
||||||
},
|
},
|
||||||
&auth::AdminApiAuth,
|
&auth::AdminApiAuth,
|
||||||
)
|
)
|
||||||
@ -53,7 +50,7 @@ pub async fn api_key_create(
|
|||||||
/// Retrieve information about the specified API Key.
|
/// Retrieve information about the specified API Key.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
get,
|
get,
|
||||||
path = "/api_keys/{key_id}",
|
path = "/api_keys/{merchant_id}/{key_id}",
|
||||||
params (("key_id" = String, Path, description = "The unique identifier for the API Key")),
|
params (("key_id" = String, Path, description = "The unique identifier for the API Key")),
|
||||||
responses(
|
responses(
|
||||||
(status = 200, description = "API Key retrieved", body = RetrieveApiKeyResponse),
|
(status = 200, description = "API Key retrieved", body = RetrieveApiKeyResponse),
|
||||||
@ -66,9 +63,9 @@ pub async fn api_key_create(
|
|||||||
pub async fn api_key_retrieve(
|
pub async fn api_key_retrieve(
|
||||||
state: web::Data<AppState>,
|
state: web::Data<AppState>,
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
path: web::Path<String>,
|
path: web::Path<(String, String)>,
|
||||||
) -> impl Responder {
|
) -> impl Responder {
|
||||||
let key_id = path.into_inner();
|
let (key_id, _merchant_id) = path.into_inner();
|
||||||
|
|
||||||
api::server_wrap(
|
api::server_wrap(
|
||||||
state.get_ref(),
|
state.get_ref(),
|
||||||
@ -85,7 +82,7 @@ pub async fn api_key_retrieve(
|
|||||||
/// Update information for the specified API Key.
|
/// Update information for the specified API Key.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
post,
|
post,
|
||||||
path = "/api_keys/{key_id}",
|
path = "/api_keys/{merchant_id}/{key_id}",
|
||||||
request_body = UpdateApiKeyRequest,
|
request_body = UpdateApiKeyRequest,
|
||||||
params (("key_id" = String, Path, description = "The unique identifier for the API Key")),
|
params (("key_id" = String, Path, description = "The unique identifier for the API Key")),
|
||||||
responses(
|
responses(
|
||||||
@ -99,10 +96,10 @@ pub async fn api_key_retrieve(
|
|||||||
pub async fn api_key_update(
|
pub async fn api_key_update(
|
||||||
state: web::Data<AppState>,
|
state: web::Data<AppState>,
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
path: web::Path<String>,
|
path: web::Path<(String, String)>,
|
||||||
json_payload: web::Json<api_types::UpdateApiKeyRequest>,
|
json_payload: web::Json<api_types::UpdateApiKeyRequest>,
|
||||||
) -> impl Responder {
|
) -> impl Responder {
|
||||||
let key_id = path.into_inner();
|
let (key_id, _merchant_id) = path.into_inner();
|
||||||
let payload = json_payload.into_inner();
|
let payload = json_payload.into_inner();
|
||||||
|
|
||||||
api::server_wrap(
|
api::server_wrap(
|
||||||
@ -121,7 +118,7 @@ pub async fn api_key_update(
|
|||||||
/// authenticating with our APIs.
|
/// authenticating with our APIs.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
delete,
|
delete,
|
||||||
path = "/api_keys/{key_id}",
|
path = "/api_keys/{merchant_id)/{key_id}",
|
||||||
params (("key_id" = String, Path, description = "The unique identifier for the API Key")),
|
params (("key_id" = String, Path, description = "The unique identifier for the API Key")),
|
||||||
responses(
|
responses(
|
||||||
(status = 200, description = "API Key revoked", body = RevokeApiKeyResponse),
|
(status = 200, description = "API Key revoked", body = RevokeApiKeyResponse),
|
||||||
@ -134,9 +131,9 @@ pub async fn api_key_update(
|
|||||||
pub async fn api_key_revoke(
|
pub async fn api_key_revoke(
|
||||||
state: web::Data<AppState>,
|
state: web::Data<AppState>,
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
path: web::Path<String>,
|
path: web::Path<(String, String)>,
|
||||||
) -> impl Responder {
|
) -> impl Responder {
|
||||||
let key_id = path.into_inner();
|
let (key_id, _merchant_id) = path.into_inner();
|
||||||
|
|
||||||
api::server_wrap(
|
api::server_wrap(
|
||||||
state.get_ref(),
|
state.get_ref(),
|
||||||
@ -153,7 +150,7 @@ pub async fn api_key_revoke(
|
|||||||
/// List all API Keys associated with your merchant account.
|
/// List all API Keys associated with your merchant account.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
get,
|
get,
|
||||||
path = "/api_keys/list",
|
path = "/api_keys/{merchant_id}/list",
|
||||||
params(
|
params(
|
||||||
("limit" = Option<i64>, Query, description = "The maximum number of API Keys to include in the response"),
|
("limit" = Option<i64>, Query, description = "The maximum number of API Keys to include in the response"),
|
||||||
("skip" = Option<i64>, Query, description = "The number of API Keys to skip when retrieving the list of API keys."),
|
("skip" = Option<i64>, Query, description = "The number of API Keys to skip when retrieving the list of API keys."),
|
||||||
@ -168,42 +165,22 @@ pub async fn api_key_revoke(
|
|||||||
pub async fn api_key_list(
|
pub async fn api_key_list(
|
||||||
state: web::Data<AppState>,
|
state: web::Data<AppState>,
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
|
path: web::Path<String>,
|
||||||
query: web::Query<api_types::ListApiKeyConstraints>,
|
query: web::Query<api_types::ListApiKeyConstraints>,
|
||||||
) -> impl Responder {
|
) -> impl Responder {
|
||||||
let list_api_key_constraints = query.into_inner();
|
let list_api_key_constraints = query.into_inner();
|
||||||
let limit = list_api_key_constraints.limit;
|
let limit = list_api_key_constraints.limit;
|
||||||
let offset = list_api_key_constraints.skip;
|
let offset = list_api_key_constraints.skip;
|
||||||
|
let merchant_id = path.into_inner();
|
||||||
|
|
||||||
api::server_wrap(
|
api::server_wrap(
|
||||||
state.get_ref(),
|
state.get_ref(),
|
||||||
&req,
|
&req,
|
||||||
(&req, limit, offset),
|
(limit, offset, merchant_id),
|
||||||
|state, _, (req, limit, offset)| async move {
|
|state, _, (limit, offset, merchant_id)| async move {
|
||||||
let merchant_id = get_merchant_id_header(req)?;
|
|
||||||
api_keys::list_api_keys(&*state.store, merchant_id, limit, offset).await
|
api_keys::list_api_keys(&*state.store, merchant_id, limit, offset).await
|
||||||
},
|
},
|
||||||
&auth::AdminApiAuth,
|
&auth::AdminApiAuth,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_merchant_id_header(req: &HttpRequest) -> RouterResult<String> {
|
|
||||||
use crate::headers::X_MERCHANT_ID;
|
|
||||||
|
|
||||||
req.headers()
|
|
||||||
.get(X_MERCHANT_ID)
|
|
||||||
.ok_or_else(|| errors::ApiErrorResponse::InvalidRequestData {
|
|
||||||
message: format!("Missing header: `{X_MERCHANT_ID}`"),
|
|
||||||
})
|
|
||||||
.into_report()?
|
|
||||||
.to_str()
|
|
||||||
.into_report()
|
|
||||||
.change_context(errors::ApiErrorResponse::InvalidDataValue {
|
|
||||||
field_name: X_MERCHANT_ID,
|
|
||||||
})
|
|
||||||
.attach_printable(
|
|
||||||
"Failed to convert header value to string, \
|
|
||||||
possibly contains non-printable or non-ASCII characters",
|
|
||||||
)
|
|
||||||
.map(|s| s.to_owned())
|
|
||||||
}
|
|
||||||
|
|||||||
@ -340,7 +340,7 @@ pub struct ApiKeys;
|
|||||||
#[cfg(feature = "olap")]
|
#[cfg(feature = "olap")]
|
||||||
impl ApiKeys {
|
impl ApiKeys {
|
||||||
pub fn server(state: AppState) -> Scope {
|
pub fn server(state: AppState) -> Scope {
|
||||||
web::scope("/api_keys")
|
web::scope("/api_keys/{merchant_id}")
|
||||||
.app_data(web::Data::new(state))
|
.app_data(web::Data::new(state))
|
||||||
.service(web::resource("").route(web::post().to(api_key_create)))
|
.service(web::resource("").route(web::post().to(api_key_create)))
|
||||||
.service(web::resource("/list").route(web::get().to(api_key_list)))
|
.service(web::resource("/list").route(web::get().to(api_key_list)))
|
||||||
|
|||||||
@ -5,7 +5,7 @@ use error_stack::{report, IntoReport, ResultExt};
|
|||||||
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
|
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
core::errors::{self, RouterResult, StorageErrorExt},
|
core::errors::{self, RouterResult},
|
||||||
db::StorageInterface,
|
db::StorageInterface,
|
||||||
routes::{app::AppStateInfo, AppState},
|
routes::{app::AppStateInfo, AppState},
|
||||||
services::api,
|
services::api,
|
||||||
@ -44,8 +44,13 @@ where
|
|||||||
.store()
|
.store()
|
||||||
.find_merchant_account_by_api_key(api_key)
|
.find_merchant_account_by_api_key(api_key)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::ApiErrorResponse::Unauthorized)
|
.map_err(|e| {
|
||||||
.attach_printable("Merchant not authenticated")
|
if e.current_context().is_db_not_found() {
|
||||||
|
e.change_context(errors::ApiErrorResponse::Unauthorized)
|
||||||
|
} else {
|
||||||
|
e.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,7 +92,13 @@ impl AuthenticateAndFetch<storage::MerchantAccount, AppState> for MerchantIdAuth
|
|||||||
.store
|
.store
|
||||||
.find_merchant_account_by_merchant_id(self.0.as_ref())
|
.find_merchant_account_by_merchant_id(self.0.as_ref())
|
||||||
.await
|
.await
|
||||||
.map_err(|error| error.to_not_found_response(errors::ApiErrorResponse::Unauthorized))
|
.map_err(|e| {
|
||||||
|
if e.current_context().is_db_not_found() {
|
||||||
|
e.change_context(errors::ApiErrorResponse::Unauthorized)
|
||||||
|
} else {
|
||||||
|
e.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,8 +118,13 @@ impl AuthenticateAndFetch<storage::MerchantAccount, AppState> for PublishableKey
|
|||||||
.store
|
.store
|
||||||
.find_merchant_account_by_publishable_key(publishable_key)
|
.find_merchant_account_by_publishable_key(publishable_key)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::ApiErrorResponse::Unauthorized)
|
.map_err(|e| {
|
||||||
.attach_printable("Merchant not authenticated")
|
if e.current_context().is_db_not_found() {
|
||||||
|
e.change_context(errors::ApiErrorResponse::Unauthorized)
|
||||||
|
} else {
|
||||||
|
e.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user