AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Validation

skill-jkaninda-okapi-skills-validation · by jkaninda

A Claude skill from jkaninda/okapi-skills.

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

Install

$ agentstack add skill-jkaninda-okapi-skills-validation

✓ 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.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-jkaninda-okapi-skills-validation)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Validation? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Okapi Validation

Validation is declarative: struct tags drive both runtime enforcement and OpenAPI schema generation. Validation runs automatically inside c.Bind and inside the typed handler wrappers (okapi.Handle, okapi.H, okapi.HandleIO, okapi.HandleO).

For where values come from (JSON body, query, path, header, cookie, form), see the request_binding/ skill.

Constraint Tags

| Tag | Applies to | Description | |-----|------------|-------------| | required:"true" | any | Field must be present and non-zero | | default:"v" | any | Assigned when the field is missing/empty | | min:"5" | number | ≥ 5 | | max:"100" | number | ≤ 100 | | exclusiveMin:"0" | number | > 0 | | exclusiveMax:"100" | number | Slices: enum, const, format, pattern, contains, and notContains apply to each element of a []string. Failures are reported per index — element [2]: .... > > Empty values: those same tags skip empty strings. Combine with required:"true" to also enforce presence.

Conditional Required Tags

Requiredness that depends on sibling fields in the same struct. Referenced fields use their Go field name, not the JSON name.

| Tag | Description | |-----|-------------| | requiredIf:"Type card" | Required when sibling Type equals card | | requiredWith:"Pass" | Required when any listed sibling (comma-separated) is non-empty | | requiredWithout:"Email" | Required when any listed sibling (comma-separated) is empty |

type Payment struct {
    Type    string `json:"type"`
    Card    string `json:"card"    requiredIf:"Type card"`
    Pass    string `json:"pass"`
    Confirm string `json:"confirm" requiredWith:"Pass"`
    Email   string `json:"email"`
    Phone   string `json:"phone"   requiredWithout:"Email"`
}

Documentation-Only Tags

These shape the OpenAPI schema; they are not enforced at runtime.

| Tag | Description | |-----|-------------| | description:"..." | Property description | | doc:"..." | Alternative description tag | | example:"v" | Example value | | deprecated:"true" | Mark the property deprecated | | hidden:"true" | Omit the field from the generated schema | | readOnly:"true" | Returned by the server, not sent by clients | | writeOnly:"true" | Sent by clients, not returned | | nullable:"true" | Nullable property (pointer fields are nullable automatically) |

Formats

All formats apply to string fields and to each element of a []string.

Date & time

| Format | Description | |--------|-------------| | date | YYYY-MM-DD | | date-time | RFC3339 timestamp | | time | RFC3339 full-time (15:04:05Z) | | duration | Go duration (1h30m, 300ms) |

Network, web & identifiers

| Format | Description | |--------|-------------| | email | Valid email address | | hostname | Valid hostname | | ipv4 / ipv6 | IP addresses | | mac | MAC address | | cidr | CIDR notation (192.168.1.0/24) | | uri / uri-reference | Any URI / relative reference allowed | | url | Absolute http/https URL | | uuid / ulid | UUID / ULID | | e164 / phone | E.164 phone number (+14155552671) | | credit-card | Luhn-valid card number | | semver | Semantic version (1.2.3-alpha.1) | | json-pointer | RFC 6901 JSON Pointer | | byte / base64 | Base64-encoded value | | base64url | URL-safe Base64 (padded or unpadded) | | jwt | JSON Web Token (three base64url segments) | | port | TCP/UDP port (165535) |

String content

| Format | Description | |--------|-------------| | alpha | Letters only | | alphanumeric | Letters and digits | | numeric | Numeric string (123, -12.5) | | ascii | ASCII only | | lowercase / uppercase | Case constraint | | slug | URL slug (my-post-123) | | hexcolor | #RGB or #RRGGBB | | json | Syntactically valid JSON string |

Geo & time zones

| Format | Description | |--------|-------------| | latitude | Decimal latitude, -9090 | | longitude | Decimal longitude, -180180 | | timezone | IANA time zone (America/New_York) |

Custom pattern
Phone string `json:"phone" format:"regex" pattern:"^\\+?[1-9]\\d{1,14}$"`

Example

type CreateUserRequest struct {
    Email    string            `json:"email" required:"true" format:"email" example:"user@example.com"`
    Password string            `json:"password" minLength:"8" writeOnly:"true" description:"User password"`
    Age      int               `json:"age" exclusiveMin:"0" max:"120" default:"18"`
    Website  string            `json:"website" format:"url"`
    Kind     string            `json:"kind" const:"user"`
    Roles    []string          `json:"roles" minItems:"1" uniqueItems:"true" enum:"admin,editor,viewer"`
    Metadata map[string]string `json:"metadata" minProperties:"1" maxProperties:"10"`
    ID       string            `json:"id" format:"uuid" readOnly:"true"`
    Internal string            `json:"-" hidden:"true"`
}

Five Ways to Validate

1. c.Bind() — bind and validate inside the handler

o.Post("/users", func(c *okapi.Context) error {
    var req CreateUserRequest
    if err := c.Bind(&req); err != nil {
        return c.ErrorBadRequest(err)
    }
    return c.JSON(http.StatusOK, req)
})

2. okapi.Handle() — typed input, manual response

o.Post("/books", okapi.Handle(func(c *okapi.Context, book *Book) error {
    book.ID = nextID()
    return c.Created(book)
}),
    okapi.DocRequestBody(&Book{}),
    okapi.DocResponse(&Book{}),
)

3. okapi.H() — shorthand for Handle

o.Get("/books/{id:int}", okapi.H(func(c *okapi.Context, in *BookDetailInput) error {
    b := find(in.ID)
    if b == nil {
        return c.AbortNotFound("Book not found")
    }
    return c.OK(b)
})).WithInput(&BookDetailInput{})

4. okapi.HandleIO() — typed input and typed output

type BookEditInput struct {
    ID   int  `json:"id" path:"id" required:"true"`
    Body Book `json:"body"`
}
type BookOutput struct {
    Status int
    Body   Book
}

o.Put("/books/{id:int}", okapi.HandleIO(func(c *okapi.Context, in *BookEditInput) (*BookOutput, error) {
    b := update(in.ID, in.Body)
    if b == nil {
        return nil, c.AbortNotFound("Book not found")
    }
    return &BookOutput{Body: *b}, nil
})).WithIO(&BookEditInput{}, &BookOutput{})

5. okapi.HandleO() — typed output only

type BooksResponse struct {
    Body []Book `json:"books"`
}

o.Get("/books", okapi.HandleO(func(c *okapi.Context) (*BooksResponse, error) {
    return &BooksResponse{Body: books}, nil
})).WithOutput(&BooksResponse{})

The output struct follows the body-style convention (Status, Body, header/cookie-tagged fields). The response format comes from the client's Accept header, defaulting to JSON.

Schema Helpers

| Helper | Purpose | |--------|---------| | okapi.DocRequestBody(&T{}) | Document the request body schema | | okapi.DocResponse(&T{}) / okapi.DocResponse(201, &T{}) | Document a response schema | | route.WithInput(&T{}) | Input schema (pairs with okapi.H / Handle) | | route.WithOutput(&T{}) | Output schema (pairs with HandleO) | | route.WithIO(&In{}, &Out{}) | Both (pairs with HandleIO) |

Returning Validation Errors

return c.AbortValidationErrors([]okapi.ValidationError{
    {Field: "email", Message: "must be a valid email", Value: req.Email},
    {Field: "age",   Message: "must be >= 18"},
}, "validation failed")

AbortValidationErrors always uses the ValidationErrorResponse shape (an ErrorResponse plus an errors array), regardless of the configured error handler. Use AbortValidationErrorsWithProblemDetail for the RFC 7807 form.

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.