Skip to content
huma-endpoint logo

Huma Endpoint Creation

huma-endpoint

Guide for creating Huma API endpoints following this project's conventions including routing, input/output structs, error handling, and OpenAPI documentation.

SKILL.md

Full skill instructions

Huma Endpoint Creation

Use this skill when creating new API endpoints for this Huma REST API application.

For comprehensive coding guidelines, see AGENTS.md in the repository root.

Router Setup

Create route handlers in internal/​http/​v1/ and register them in routes.go:

// internal/​http/​v1/​routes/​routes.go
func Register(api huma.API) {
    hello.Register(api)
    items.Register(api)
    // Add new routes here
}

Note: The health endpoint is a plain HTTP handler registered at the root level in main.go, not via Huma.

Output Struct Pattern

Use plain structs with a Body field for the response payload:

import "github.com/​janisto/​huma-playground/​internal/​platform/​timeutil"

// ResourceData models the response payload.
type ResourceData struct {
    ID        string      `json:"id"        doc:"Unique identifier"   example:"res-001"`
    Name      string      `json:"name"      doc:"Display name"        example:"My Resource"`
    CreatedAt timeutil.Time `json:"createdAt" doc:"Creation timestamp"  example:"2024-01-15T10:30:00.000Z"`
}

// ResourceOutput is the response wrapper.
type ResourceOutput struct {
    Body ResourceData
}

Input Struct Pattern

Always prefix input types with the resource name for consistency:

// Path parameters
type ResourceGetInput struct {
    ID string `path:"id" doc:"Resource identifier" example:"res-001"`
}

// Query parameters
type ResourceListInput struct {
    Status string `query:"status" doc:"Filter by status" example:"active" enum:"active,inactive"`
    Limit  int    `query:"limit"  doc:"Maximum items"    example:"10"     minimum:"1" maximum:"100"`
}

// Request body
type ResourceCreateInput struct {
    Body struct {
        Name string `json:"name" doc:"Resource name" example:"New Resource" minLength:"1" maxLength:"100"`
    }
}

GET Endpoint

Simple retrieval endpoints use huma.Get:

func registerResource(api huma.API) {
    huma.Get(api, "/​resources/​{id}", func(ctx context.Context, input *ResourceGetInput) (*ResourceOutput, error) {
        resource, err := getResource(input.ID)
        if err != nil {
            return nil, huma.Error404NotFound("resource not found")
        }
        return &ResourceOutput{Body: resource}, nil
    })
}

POST Endpoint with 201 Created

Use huma.Register for operations requiring custom configuration:

type CreateResourceOutput struct {
    Location string `header:"Location" doc:"URL of created resource"`
    Body     ResourceData
}

huma.Register(api, huma.Operation{
    OperationID:   "create-resource",
    Method:        http.MethodPost,
    Path:          "/​resources",
    Summary:       "Create a new resource",
    Description:   "Creates a new resource and returns its data.",
    DefaultStatus: http.StatusCreated,
    Tags:          []string{"Resources"},
}, func(ctx context.Context, input *ResourceCreateInput) (*CreateResourceOutput, error) {
    resource := createResource(input.Body.Name)
    return &CreateResourceOutput{
        Location: fmt.Sprintf("/​resources/%s", resource.ID),
        Body:     resource,
    }, nil
})

PUT/​PATCH Endpoint

type UpdateResourceInput struct {
    ID   string `path:"id"`
    Body struct {
        Name string `json:"name" doc:"Updated name" minLength:"1" maxLength:"100"`
    }
}

huma.Register(api, huma.Operation{
    OperationID: "update-resource",
    Method:      http.MethodPut,
    Path:        "/​resources/​{id}",
    Summary:     "Update a resource",
    Tags:        []string{"Resources"},
}, func(ctx context.Context, input *UpdateResourceInput) (*ResourceOutput, error) {
    resource, err := updateResource(input.ID, input.Body.Name)
    if err != nil {
        return nil, huma.Error404NotFound("resource not found")
    }
    return &ResourceOutput{Body: resource}, nil
})

DELETE Endpoint

Return 204 No Content for successful deletions:

huma.Register(api, huma.Operation{
    OperationID:   "delete-resource",
    Method:        http.MethodDelete,
    Path:          "/​resources/​{id}",
    Summary:       "Delete a resource",
    DefaultStatus: http.StatusNoContent,
    Tags:          []string{"Resources"},
}, func(ctx context.Context, input *ResourceInput) (*struct{}, error) {
    if err := deleteResource(input.ID); err != nil {
        return nil, huma.Error404NotFound("resource not found")
    }
    return nil, nil
})

Error Handling

Use Huma's built-in error helpers for RFC 9457 Problem Details:

// Common error responses
huma.Error400BadRequest("invalid request")
huma.Error403Forbidden("access denied")
huma.Error404NotFound("resource not found")
huma.Error422UnprocessableEntity("validation failed", fieldErrors...)
huma.Error500InternalServerError("internal error")

// Custom status codes
huma.NewError(http.StatusTeapot, "custom message")
huma.NewError(http.StatusConflict, "resource already exists")

Logging

Use context-aware logging helpers:

import (
    "go.uber.org/​zap"
    applog "github.com/​janisto/​huma-playground/​internal/​platform/​logging"
)

func handler(ctx context.Context, input *Input) (*Output, error) {
    applog.LogInfo(ctx, "processing request", zap.String("id", input.ID))

    if err != nil {
        applog.LogError(ctx, "operation failed", err, zap.String("id", input.ID))
        return nil, huma.Error500InternalServerError("operation failed")
    }

    return &Output{Body: result}, nil
}

Field Documentation

Every field MUST have:

  • doc: tag for OpenAPI description
  • example: tag for OpenAPI examples

Validation tags:

  • minLength, maxLength for strings
  • minimum, maximum for numbers
  • enum: for allowed values
  • pattern: for regex validation

Status Code Reference

MethodSuccess StatusUse Case
GET200 OKRetrieve resource(s)
POST201 CreatedCreate resource (include Location header)
PUT200 OKReplace resource
PATCH200 OKPartial update
DELETE204 No ContentRemove resource

Error Status Codes

StatusUse Case
400Malformed syntax, invalid cursor
401Missing authentication
403Authenticated but not authorized
404Resource not found
409Conflict (duplicate resource)
422Validation failures
500Unexpected server error

More skills from majiayu000

xiaohongshu logo
majiayu000/claude-arsenal

xiaohongshu

xiaohongshu

286 148
View
agent-task-conductor logo
majiayu000/claude-skill-registry

agent-task-conductor

Conduct multi-agent task orchestration and workflow coordination.

663 1
View
conductor-setup logo
majiayu000/claude-skill-registry

conductor-setup

Initialize project with Conductor artifacts (product definition,

663 1
View
animation-designer logo
majiayu000/claude-skill-registry

animation-designer

Expert in web animations, transitions, and motion design using Framer Motion and CSS

663 1
View
diagramming logo
majiayu000/claude-skill-registry

diagramming

Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...

663 1
View
h3-pg logo
majiayu000/claude-skill-registry-data

h3-pg

PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.

23 1
View
conductor-development logo
majiayu000/claude-skill-registry

conductor-development

Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...

663 1
View
conductor-status logo
majiayu000/claude-skill-registry

conductor-status

Display project status, active tracks, and next actions

663 1
View
dockerization logo
majiayu000/claude-skill-registry

dockerization

Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.

663 1
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View