Skip to content
Draft
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
47 changes: 47 additions & 0 deletions api-description.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ tags:
description: "Download files"
- name: "Usage"
description: "Upload usage quotas"
- name: "Email template"
description: "Email template linked to an API key"
paths:
/health:
get:
Expand Down Expand Up @@ -410,6 +412,44 @@ paths:
falls out of the rolling window, partially freeing quota.
Null if the sender has no recorded uploads."

/email-template:
get:
tags:
- "Email template"
summary: "Get the email template linked to an API key"
description:
"Returns the email template pg-pkg has linked to the caller's API key.
The key is validated through the same flow the upload endpoints use:
send it in an `Authorization: Bearer PG-…` header. Unlike the upload
endpoints, a missing or invalid key is rejected here rather than
degraded to the default tier."
operationId: "getEmailTemplate"
security:
- apiKeyBearer: []
responses:
"200":
description: "The email template linked to the validated API key."
content:
application/json:
schema:
type: "object"
required:
- tenant_id
- email_template
properties:
tenant_id:
type: "string"
description: "Tenant the API key resolved to on pg-pkg."
email_template:
type: "string"
description: "The email template linked to the API key."
"401":
description: "No valid `PG-…` API key was presented."
"404":
description: "The API key is valid but has no email template configured."
"503":
description: "pg-pkg was unreachable while validating the API key."

/filedownload/{uuid}:
get:
tags:
Expand Down Expand Up @@ -445,6 +485,13 @@ paths:
description: "Uploaded file does not exist."

components:
securitySchemes:
apiKeyBearer:
type: "http"
scheme: "bearer"
description:
"PostGuard API key, sent as `Authorization: Bearer PG-…`. Validated
against pg-pkg's `/v2/api-key/validate` endpoint."
schemas:
PayloadTooLarge:
type: "object"
Expand Down
17 changes: 17 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ pub struct UploadSessionNotFoundBody {
#[derive(Debug)]
pub enum Error {
BadRequest(Option<String>),
/// 401 — the request did not present a valid API key on an endpoint
/// that requires one. Distinct from the upload flow, which degrades a
/// missing/invalid key to the default tier rather than rejecting.
Unauthorized(Option<String>),
/// 404 — the resource (e.g. the email template for a validated API
/// key) does not exist. Carries an optional human-readable message.
NotFound(Option<String>),
UnprocessableEntity(Option<String>),
InternalServerError(Option<String>),
PayloadTooLarge(PayloadTooLargeBody),
Expand All @@ -50,6 +57,16 @@ impl<'r, 'o: 'r> Responder<'r, 'o> for Error {
fn respond_to(self, request: &'r rocket::Request<'_>) -> response::Result<'o> {
match self {
Error::BadRequest(e) => response::status::BadRequest(e).respond_to(request),
Error::Unauthorized(e) => response::status::Custom::<String>(
rocket::http::Status::Unauthorized,
e.unwrap_or_else(|| "".to_owned()),
)
.respond_to(request),
Error::NotFound(e) => response::status::Custom::<String>(
rocket::http::Status::NotFound,
e.unwrap_or_else(|| "".to_owned()),
)
.respond_to(request),
// response::status::Custom apparently doesn't support Option<R>
Error::UnprocessableEntity(e) => response::status::Custom::<String>(
rocket::http::Status::UnprocessableEntity,
Expand Down
Loading