56 results available
Sign in
Skills directory

api

encoredev

·

Last changed
Hardened

This skill has been hardened by Chainguard

Last changed

This version passed the hardening gate. Hardening applied 8 targeted changes and preserved all other text. Classified findings before hardening: 0. Classified findings closed: 0. Classified findings remaining: 0. Unclassified scanner findings remaining: 0. Review findings closed: 7. Review findings remaining: 1.


Open before hardening

None

Open after hardening

None


Expand
File
Group
Subtype
Severity
Status

No findings available

0 findings


SKILL.md

Encore API Endpoints

Instructions

When creating API endpoints with Encore.ts, follow these patterns:

1. Import the API module

import { api } from "encore.dev/api";

2. Define typed request/response interfaces

Always define explicit TypeScript interfaces for request and response types:

interface CreateUserRequest {
  email: string;
  name: string;
}

interface CreateUserResponse {
  id: string;
  email: string;
  name: string;
}

3. Create the endpoint

export const createUser = api(
  { method: "POST", path: "/users", expose: true },
  async (req: CreateUserRequest): Promise<CreateUserResponse> => {
    // Implementation
  }
);

API Options

OptionTypeDescription

method

string

HTTP method: GET, POST, PUT, PATCH, DELETE

path

string

URL path, supports :param and *wildcard

expose

boolean

If true, accessible from outside (default: false)

auth

boolean

If true, requires authentication

sensitive

boolean

If true, redacts request/response payloads from traces

Request/Response Patterns

Encore supports four endpoint configurations:

// Both request and response
export const createUser = api(
  { method: "POST", path: "/users", expose: true },
  async (req: CreateRequest): Promise<CreateResponse> => { ... }
);

// Response only (no request body)
export const listUsers = api(
  { method: "GET", path: "/users", expose: true },
  async (): Promise<ListResponse> => { ... }
);

// Request only (no response body)
export const deleteUser = api(
  { method: "DELETE", path: "/users/:id", expose: true },
  async (req: DeleteRequest): Promise<void> => { ... }
);

// Neither request nor response
export const ping = api(
  { method: "GET", path: "/ping", expose: true },
  async (): Promise<void> => { ... }
);

Custom HTTP Status Codes

Include an HttpStatus field in your response to return custom status codes:

import { api, HttpStatus } from "encore.dev/api";

interface CreateResponse {
  id: string;
  status: HttpStatus;
}

export const create = api(
  { method: "POST", path: "/items", expose: true },
  async (req: CreateRequest): Promise<CreateResponse> => {
    const item = await createItem(req);
    return { id: item.id, status: HttpStatus.Created };  // Returns 201
  }
);

Parameter Types

Path Parameters

// Path: "/users/:id"
interface GetUserRequest {
  id: string;  // Automatically mapped from :id
}

Before acting on an ID from the path or query, check that the authenticated caller is allowed to access that resource. For example, compare the caller user ID with the resource owner. If they do not match, throw an APIError with the PermissionDenied code or use APIError.notFound.

Query Parameters

import { Query } from "encore.dev/api";

interface ListUsersRequest {
  limit?: Query<number>;
  offset?: Query<number>;
}

Headers

import { Header } from "encore.dev/api";

interface WebhookRequest {
  signature: Header<"X-Webhook-Signature">;
  payload: string;
}

This example only shows how to bind a header value. A signature header read in a typed endpoint is not proof of authenticity. For real webhooks, check the signature against the raw request body using api.raw, as described in the encore-webhook skill.

Cookies

import { Cookie } from "encore.dev/api";

interface SessionRequest {
  session?: Cookie<"session">;
  settings?: Cookie<"user-settings">;
}

Cookie values are untrusted client input. Validate any session or identity on the server, preferably in an Encore auth handler, and treat the raw cookie as unverified in endpoint logic. Endpoints that receive session cookies should also set the sensitive option to true so their payloads are redacted from traces.

Request Validation

Encore validates requests at runtime using TypeScript types. Add constraints for stricter validation:

import { api } from "encore.dev/api";
import { Min, Max, MinLen, MaxLen, IsEmail, IsURL } from "encore.dev/validate";

interface CreateUserRequest {
  email: string & IsEmail;                    // Must be valid email
  username: string & MinLen<3> & MaxLen<20>;  // 3-20 characters
  age: number & Min<13> & Max<120>;           // Between 13 and 120
  website?: string & IsURL;                   // Optional, must be URL if provided
}

Combining Validation Rules

Use & for AND logic (must pass all rules) and | for OR logic (must pass at least one):

import { IsEmail, IsURL, MinLen, MaxLen } from "encore.dev/validate";

interface ContactRequest {
  // Must be valid email OR valid URL
  contact: string & (IsEmail | IsURL);
  // Must be 5-100 chars AND be a valid URL
  website: string & MinLen<5> & MaxLen<100> & IsURL;
}

Available Validators

ValidatorApplies ToExample

Min<N>

number

age: number & Min<18>

Max<N>

number

count: number & Max<100>

MinLen<N>

string, array

name: string & MinLen<1>

MaxLen<N>

string, array

tags: string[] & MaxLen<10>

IsEmail

string

email: string & IsEmail

IsURL

string

link: string & IsURL

StartsWith<S>

string

id: string & StartsWith<"usr_">

EndsWith<S>

string

file: string & EndsWith<".json">

MatchesRegexp<R>

string

code: string & MatchesRegexp<"^[A-Z]{3}$">

Validation Error Response

Invalid requests return 400 with details. The shape below is illustrative only and the exact format may vary by Encore version, so treat the details structure as informational rather than a fixed contract:

{
  "code": "invalid_argument",
  "message": "validation failed",
  "details": { "field": "email", "error": "must be a valid email" }
}

Error Handling

Use APIError for proper HTTP error responses:

import { APIError, ErrCode } from "encore.dev/api";

// Throw with error code
throw new APIError(ErrCode.NotFound, "user not found");

// Or use shorthand
throw APIError.notFound("user not found");
throw APIError.invalidArgument("email is required");
throw APIError.unauthenticated("invalid token");

Common Error Codes

CodeHTTP StatusUsage

NotFound

404

Resource doesn't exist

InvalidArgument

400

Bad input

Unauthenticated

401

Missing/invalid auth

PermissionDenied

403

Not allowed

AlreadyExists

409

Duplicate resource

Static Assets

Serve static files (HTML, CSS, JS, images) with api.static:

import { api } from "encore.dev/api";

// Serve files from ./assets under /static/*
export const assets = api.static(
  { expose: true, path: "/static/*path", dir: "./assets" }
);

// Serve at root (use !path for fallback routing)
export const frontend = api.static(
  { expose: true, path: "/!path", dir: "./dist" }
);

// Custom 404 page
export const app = api.static(
  { expose: true, path: "/!path", dir: "./public", notFound: "./404.html" }
);

Path Syntax

  • *path - Standard wildcard: matches all paths under the prefix (e.g., /static/*path)
  • !path - Fallback routing: serves static files at domain root without conflicting with other API endpoints. Use this for SPAs where unmatched routes should serve index.html

Every file in the served directory becomes public. Point it only at a dedicated build output or asset directory, never the project or service root, and make sure it holds no environment files, source maps, keys or other secrets.

Guidelines

  • Always use import not require
  • Define explicit interfaces for type safety
  • Use expose: true only for public endpoints
  • Endpoints that create, change, delete or return data for a specific user should also set the auth option to true. This requires a configured auth handler. Leave it off only for endpoints that are meant to be public, such as sign up. The examples above leave it off for brevity.
  • Internal service to service endpoints should keep the default of not exposed
  • Throw APIError instead of returning error objects
  • For inbound webhooks (Stripe, GitHub, etc.) use api.raw — see the encore-webhook skill
  • Path parameters are automatically extracted from the path pattern
  • Check that the caller is authorized for the resource named by a path or query ID before using it
  • Use validation constraints (Min, MaxLen, etc.) for user input
  • Set the sensitive option to true on endpoints whose payloads include credentials, tokens, session data or personal data such as emails

Install

Install with chainctl
chainctl skill install public/encoredev/api:latest
Get started with chainctl
View source

Harden your own skills

Bring Chainguard's hardening pipeline to your first-party skills — custom rulesets, automated remediation, full audit trail.

Provenance

Upstream sourcehttps://github.com/encoredev/skills
Upstream commitcb69bb1f246274419aed69c84ee5815955c4c499
OCI reference

skills.cgr.dev/public/github.com/encoredev/encore/api:latest

License

Apache-2.0

Files

HARDENING.md

LICENSE

SKILL.md


The trusted source for open source

Talk to an expert
PrivacyTerms

Product

Chainguard ContainersChainguard LibrariesChainguard VMsChainguard OS PackagesChainguard ActionsChainguard Agent SkillsIntegrationsPricing
© 2026 Chainguard, Inc. All Rights Reserved.
Chainguard® and the Chainguard logo are registered trademarks of Chainguard, Inc. in the United States and/or other countries.
The other respective trademarks mentioned on this page are owned by the respective companies and use of them does not imply any affiliation or endorsement.