Skip to main content

guides/cheatsheet.cheatmd

# Cheatsheet

## Spec modules
{: .col-2}

### Define

```elixir
defmodule MyAppWeb.ApiSpec do
  use AshOaskit,
    domains: [MyApp.Blog],
    title: "My API",
    api_version: "1.0.0"
end
```

### Customize

```elixir
defmodule MyAppWeb.ApiSpec do
  use AshOaskit, domains: [MyApp.Blog]

  @impl AshOaskit.Spec
  def modify_spec(spec) do
    put_in(spec, ["components", "securitySchemes"], %{
      "bearerAuth" => %{"type" => "http", "scheme" => "bearer"}
    })
  end
end
```

### Serve (Phoenix or Plug.Router)

```elixir
use AshOaskit.Router,
  spec: MyAppWeb.ApiSpec,
  open_api: "/openapi",
  redoc: "/redoc"
```

### Serve both OpenAPI versions

```elixir
use AshOaskit.Router,
  spec: [
    {"3.1", MyAppWeb.ApiSpecV31},
    {"3.0", MyAppWeb.ApiSpecV30}
  ],
  open_api: "/openapi"
```

### Dev: regenerate on reload

```elixir
# config/dev.exs
config :ash_oaskit, cache_specs: false
```

### Validate in tests

```elixir
assert {:ok, _} = AshOaskit.validate(MyAppWeb.ApiSpec.spec())
Oaskit.build_spec!(MyAppWeb.ApiSpec)
```

## One-off generation
{: .col-2}

### In code

```elixir
spec = AshOaskit.spec(domains: [MyApp.Blog])
spec = AshOaskit.spec_30(domains: [MyApp.Blog])
spec = AshOaskit.spec_31(domains: [MyApp.Blog])
```

### With full options

```elixir
AshOaskit.spec(
  domains: [MyApp.Blog],
  version: "3.1",
  title: "My API",
  api_version: "2.0.0",
  description: "Blog API",
  servers: ["https://api.example.com"]
)
```

### Validate a spec map

```elixir
{:ok, validated} = AshOaskit.validate(spec)
validated = AshOaskit.validate!(spec)
```

## Mix tasks
{: .col-2}

### Export a spec module (preferred)

```sh
mix openapi.dump MyAppWeb.ApiSpec \
  --pretty -o priv/static/openapi.json
```

### Generate without a spec module

```sh
mix ash_oaskit.generate \
  --domains MyApp.Blog,MyApp.Accounts \
  --version 3.1 \
  --output openapi.json
```

### Install

```sh
mix igniter.install ash_oaskit
```

## Making things appear in the spec
{: .col-2}

### Fields must be public

```elixir
attribute :title, :string do
  public? true
end
```

Only `public? true` attributes, calculations, aggregates, and
relationships appear in generated specs — matching what AshJsonApi
serializes.

### Request bodies follow the action

```elixir
create :create do
  accept [:title, :body]
end
# -> PostCreateInput documents exactly title + body
```

### Descriptions propagate

```elixir
create :create do
  description "Creates a blog post"
end
# -> operation description
```