AgentStack
SKILL verified MIT Self-run

Http Actix Axum

skill-pedromneto97-custom-skills-http-actix-axum · by pedromneto97

>

No reviews yet
0 installs
10 views
0.0% view→install

Install

$ agentstack add skill-pedromneto97-custom-skills-http-actix-axum

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Http Actix Axum? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

HTTP Best Practices — actix-web / axum

1. Resource Naming

| Rule | Good | Bad | |------|------|-----| | Plural nouns | /orders, /users | /order, /getOrders | | Lowercase + hyphens | /order-items | /orderItems, /Order_Items | | Hierarchical nesting | /orders/{id}/items | /order-items?orderId={id} | | No verbs in path | POST /orders | POST /createOrder | | Filter / sort in query | /orders?status=pending&sort=created_at | /pending-orders |

Max nesting depth: 2 levels (/resource/{id}/sub-resource). Avoid deeper hierarchies.


2. API Versioning

Prefix at the router level. Handlers are version-agnostic.

actix-web

// inbound/src/http/router.rs
pub fn configure(cfg: &mut web::ServiceConfig) {
    cfg.service(
        web::scope("/api/v1")
            .service(web::scope("/orders")
                .route("",      web::get().to(list))
                .route("",      web::post().to(create))
                .route("/{id}", web::get().to(get_one))
                .route("/{id}", web::put().to(update))
                .route("/{id}", web::delete().to(delete)),
            ),
    );
}

axum

// inbound/src/http/router.rs
pub fn build_router() -> Router {
    Router::new()
        .nest("/api/v1", Router::new()
            .nest("/orders", Router::new()
                .route("/",    get(list).post(create))
                .route("/:id", get(get_one).put(update).delete(delete)),
            ),
        )
}

3. HTTP Status Codes

| Operation | Method | Success | Error cases | |-----------|--------|---------|-------------| | Fetch one | GET | 200 | 404 if not found | | Fetch list | GET | 200 | Empty list → 200 [], never 404 | | Create | POST | 201 + Location header | 400, 422 | | Full replace | PUT | 200 | 404, 422 | | Partial update | PATCH | 200 | 404, 422 | | Delete | DELETE | 204 No Content | 404 | | Async action | POST | 202 Accepted | — | | Bad input | — | 400 Bad Request | — | | Unauthenticated | — | 401 Unauthorized | — | | Forbidden | — | 403 Forbidden | — | | Conflict (duplicate) | — | 409 Conflict | — | | Business rule violated | — | 422 Unprocessable Entity | — | | Server fault | — | 500 Internal Server Error | Never leak stack traces |

// 201 + Location (actix-web)
HttpResponse::Created()
    .insert_header(("Location", format!("/api/v1/orders/{}", order.id)))
    .json(OrderResponse::from(order))

// 201 + Location (axum)
(StatusCode::CREATED, [("Location", format!("/api/v1/orders/{}", order.id))], Json(body))

4. Error Responses — Problem Details (RFC 9457)

→ Read [references/problem-details.md](./references/problem-details.md) for the full struct, ResponseError / IntoResponse impl, From, and validation error mapping.

Quick rules:

  • Content-Type: application/problem+json
  • type is a URI; use "about:blank" when no dedicated error page exists
  • Never expose stack traces, internal IDs, or DB details in detail
  • Convert framework extractor errors (JSON/query/path) into sanitized Problem Details

5. Security Headers (OWASP)

→ Read [references/security-headers.md](./references/security-headers.md) for middleware implementation (actix-web Transform + axum tower-http layer).

Mandatory headers on every response:

| Header | Value | |--------|-------| | X-Content-Type-Options | nosniff | | X-Frame-Options | DENY | | Referrer-Policy | strict-origin-when-cross-origin | | Content-Security-Policy | default-src 'self' (tune per app) | | Permissions-Policy | geolocation=(), microphone=(), camera=() | | Strict-Transport-Security | max-age=31536000; includeSubDomains (HTTPS only) |

Remove Server and X-Powered-By response headers.


6. CORS

→ Read [references/cors.md](./references/cors.md) for full configuration.

Decision guide:

| Scenario | Strategy | |----------|----------| | Public API, no cookies | allow_any_origin() | | Cookie-auth / credentialed | Explicit origin allowlist + allow_credentials(true) |

> Never combine allow_any_origin() with allow_credentials(true) — browsers reject it.

For cookie/session auth, combine CORS policy with cookie security (Secure, HttpOnly, SameSite) and an explicit origin allowlist.


7. Response Compression

→ Read [references/compression.md](./references/compression.md) for middleware setup.

  • Priority order: Brotli → gzip → deflate (auto-negotiated from Accept-Encoding)
  • Skip already-compressed content: images (jpeg/png/gif/webp), video, application/zip, application/pdf
  • Skip small responses: for ApiError`.

→ Read [references/problem-details.md](./references/problem-details.md) for the From impl and the domain-validation bridge pattern.

actix-web

#[derive(Deserialize, Validate)]
#[serde(rename_all = "camelCase")]
pub struct CreateOrderRequest {
    #[validate(length(min = 1, max = 100))]
    pub customer_name: String,
    #[validate(email)]
    pub email: String,
}

pub async fn create_order(
    state: web::Data>,
    body: web::Json,
) -> Result {
    body.validate()?; // ValidationErrors → ApiError via From impl → 400 Problem Detail
    let order = orders::create_order(&state.repo, body.into_inner().into()).await?;
    Ok(HttpResponse::Created()
        .insert_header(("Location", format!("/api/v1/orders/{}", order.id)))
        .json(OrderResponse::from(order)))
}

9. Custom Extractors

Use typed request extractors (FromRequest in actix-web, FromRequestParts in axum) for cross-cutting concerns like auth claims, tenant context, and request-scoped metadata.

→ Read [references/extractors.md](./references/extractors.md).


10. OpenAPI / Swagger

Keep handlers transport-focused and annotate route contracts where possible. Expose docs routes conditionally (often only in non-production/debug builds).

→ Read [references/openapi.md](./references/openapi.md).

Domain-validation bridge (when domain owns the rules):

use validator::ValidationError;
use domain::use_cases::validate_customer_name; // pure domain fn → Vec

fn customer_name_valid(val: &str) -> Result {
    match validate_customer_name(val) {
        Ok(_) => Ok(()),
        Err(errors) => {
            let mut e = ValidationError::new("customer_name")
                .with_message("Invalid customer name".into());
            e.add_param("errors".into(), &errors);
            Err(e)
        }
    }
}

#[derive(Deserialize, Validate)]
pub struct CreateOrderRequest {
    #[validate(custom(function = "customer_name_valid"))]
    pub customer_name: String,
}

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.