Skip to content

Example project

outry-example-gin is a small shop API written with Gin: login, users, orders and asynchronous payments. Its api/ folder describes every route in .outry files and uses every feature of the format, so it doubles as a tour.

  1. Install the CLI (other platforms) and clone the project:

    Terminal window
    curl -fsSL https://raw.githubusercontent.com/1rowvy/outry/master/install.sh | sh
    git clone https://github.com/1rowvy/outry-example-gin && cd outry-example-gin
  2. Start the service — it keeps everything in memory, the admin password is admin:

    Terminal window
    go run . &
  3. Give Outry the password. admin_password is declared as a secret in api/env.toml, so it comes from the keychain or a OUTRY_* variable, never from a file:

    Terminal window
    export OUTRY_ADMIN_PASSWORD=admin # or: outry secret set admin_password
  4. Run every request and flow:

    Terminal window
    outry run api
    ✓ api/flows/checkout.outry Checkout flow
    ↳ CreateUser 201 0ms
    ↳ Login cached
    ↳ CreateOrder 201 0ms
    ↳ PayOrder 202 0ms
    ↳ WaitUntilPaid 200 1ms
    ✓ paid.body.total == 45.5
    ✓ paid.body.user_id == user.body.id
    → saved last_order
    …
    22 passed, 0 failed

    DeleteUser has confirm: true, so Outry asks before sending it; --yes answers for you.

Every generated request knows its handler (handler: s.CreateUser). Rename a field of the request struct in internal/model/model.go:

type CreateUser struct {
Name string `json:"name" binding:"required"` // full name
FullName string `json:"full_name" binding:"required"` // full name

outry check reads the Go source — nothing has to compile or run:

api/v1/users/post.outry:17:8: error: required field `full_name` (string) is missing from body ← internal/api/users.go:13
api/v1/users/post.outry:17:10: error: body field `name` is not in model.CreateUser ← internal/api/users.go:13
14 files, 2 environments, 12 Go routes: 2 errors, 0 warnings; 2 fixable with `outry import go --fix`

outry import go . --fix rewrites the body. In a pull request the project’s workflow (outry check --format github) puts the same errors on the changed lines. Add a route, and outry import go . creates its request with the body, query, headers and a response check filled in.

Feature File
Environments, shared variables, a secret, middleware → headers api/env.toml
Checks of status, fields, headers, timing; a JSON Schema api/health.outry
Parameters with defaults, cache: 50m between runs, a negative test api/auth/login/post.outry
form body, the cookie jar, cookies.session api/auth/session.outry
Calls: Login().body.token, CreateUser().body.id, sent once per run api/v1/users/get-by-id.outry
Calls with arguments, only: [dev], confirm: true api/v1/users/delete-by-id.outry
multipart file upload api/v1/users/avatar/post.outry
File-level let, uuid(), arithmetic, all / map, save api/v1/orders/post.outry
null query parameters left out api/v1/orders/get.outry
poll until the payment is confirmed api/v1/orders/pay/post.outry
Flows; an idempotent retry with fresh api/flows/checkout.outry
Shapes from Go structs, made stricter by hand api/shapes.outry
outry check and outry run in GitHub Actions .github/workflows/api.yml

The collection started as outry init and outry import go .; the requests then got checks, parameters and calls, and some files were moved — outry import still recognizes them by handler:.