Something went wrong. Try again.
A lexicon-driven AppView for ATProto.
Something went wrong. Try again.
2.3 kB · 84 lines
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485use axum::Json;use axum::extract::{Query, State};use axum::response::{IntoResponse, Response};use serde::Deserialize;
use super::row_to_view;use crate::AppState;use crate::auth::XrpcClaims;use crate::db::adapt_sql;use crate::error::AppError;use crate::rate_limit::CheckResult;
#[derive(Debug, Deserialize)]pub struct GetApiClientParams { pub id: String,}
pub async fn get_api_client( State(state): State<AppState>, xrpc_claims: XrpcClaims, Query(params): Query<GetApiClientParams>,) -> Result<Response, AppError> { let claims = xrpc_claims .identity .ok_or_else(|| AppError::Auth("getApiClient requires DPoP authentication".into()))?;
let check = if let Some(client_key) = claims.client_key() { let cost = state .rate_limiter .default_cost_for_type(client_key, "query"); Some(state.rate_limiter.check(client_key, cost)) } else { None };
if let Some(CheckResult::Limited { retry_after, limit, reset, }) = check { return Err(AppError::RateLimited { retry_after, limit, reset, }); }
let did = claims.did();
let sql = adapt_sql( "SELECT id, client_key, name, client_id_url, client_uri, redirect_uris, scopes, client_type, allowed_origins, is_active, created_at \ FROM api_clients \ WHERE id = $1 AND owner_did = $2", state.db_backend, );
let row = sqlx::query(&sql) .bind(¶ms.id) .bind(did) .fetch_optional(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to get client: {e}")))? .ok_or_else(|| AppError::NotFound("API client not found".into()))?;
let client = row_to_view(&row).map_err(|e| AppError::Internal(format!("failed to read client: {e}")))?;
let mut response = Json(serde_json::json!({ "client": client })).into_response();
if let Some(CheckResult::Allowed { remaining, limit, reset, }) = check { let h = response.headers_mut(); h.insert("RateLimit-Limit", limit.into()); h.insert("RateLimit-Remaining", remaining.into()); h.insert("RateLimit-Reset", reset.into()); }
Ok(response)}