Packages

OpenAPI 3.0 and 3.1 spec generator for Ash Framework resources. Supports dual-version output for migration scenarios.

Current section

Files

Jump to
ash_oaskit lib ash_oaskit core config.ex
Raw

lib/ash_oaskit/core/config.ex

defmodule AshOaskit.Config do
@moduledoc """
Retrieves and normalizes configuration from AshJsonApi DSL.
This module provides a unified interface for accessing configuration options
defined in Ash domains and resources through the AshJsonApi DSL.
## Domain-Level Configuration
Domain-level configuration is retrieved via `AshJsonApi.Domain.Info`:
- `tag/1` - Custom OpenAPI tag for the domain
- `group_by/1` - How operations should be grouped (e.g., by resource)
- `prefix/1` - Route prefix for all resources in the domain
## Resource-Level Configuration
Resource-level configuration is retrieved via `AshJsonApi.Resource.Info`:
- `type/1` - JSON:API type name (defaults to underscored resource name)
- `derive_filter?/1` - Whether to auto-generate filter schemas
- `derive_sort?/1` - Whether to auto-generate sort schemas
- `default_fields/1` - Default fields to include in responses
- `includes/1` - Available relationship includes
## Usage
# Get the JSON:API type for a resource
type = Config.resource_type(MyApp.Post)
# => "post"
# Check if filtering should be derived
if Config.derive_filter?(MyApp.Post) do
# Generate filter schema
end
# Get route prefix for a domain
prefix = Config.route_prefix(MyApp.Blog)
# => "/api/v1"
## Error Handling
Functions in this module follow the "let it crash" philosophy. If called
with an invalid module (not an Ash resource or domain), they will raise
an error. This is intentional - configuration errors should fail loudly
rather than silently returning defaults.
"""
@doc """
Gets the JSON:API type name for a resource.
The type is used in JSON:API responses as the `type` field and in
route generation. If not explicitly configured, defaults to the
underscored resource module name.
## Parameters
- `resource` - The Ash resource module
## Returns
The JSON:API type as a string.
## Examples
iex> Config.resource_type(MyApp.BlogPost)
"blog_post"
iex> Config.resource_type(MyApp.User)
"user"
"""
@spec resource_type(module()) :: String.t()
def resource_type(resource) do
case AshJsonApi.Resource.Info.type(resource) do
nil -> default_type(resource)
type -> type
end
end
@doc """
Checks whether filter schemas should be auto-derived for a resource.
When enabled, the OpenAPI generator will create detailed filter
parameter schemas based on the resource's attributes.
## Parameters
- `resource` - The Ash resource module
## Returns
Boolean indicating if filter derivation is enabled.
## Examples
iex> Config.derive_filter?(MyApp.Post)
true
"""
@spec derive_filter?(module()) :: boolean()
def derive_filter?(resource) do
AshJsonApi.Resource.Info.derive_filter?(resource)
end
@doc """
Checks whether sort schemas should be auto-derived for a resource.
When enabled, the OpenAPI generator will create sort parameter
schemas listing all sortable fields.
## Parameters
- `resource` - The Ash resource module
## Returns
Boolean indicating if sort derivation is enabled.
## Examples
iex> Config.derive_sort?(MyApp.Post)
true
"""
@spec derive_sort?(module()) :: boolean()
def derive_sort?(resource) do
AshJsonApi.Resource.Info.derive_sort?(resource)
end
@doc """
Gets the default fields to include in responses for a resource.
If configured, responses will only include the specified fields
unless the client requests additional fields via sparse fieldsets.
## Parameters
- `resource` - The Ash resource module
## Returns
List of field names (as atoms) or `nil` for all fields.
## Examples
iex> Config.default_fields(MyApp.Post)
[:id, :title, :body]
iex> Config.default_fields(MyApp.Comment)
nil
"""
@spec default_fields(module()) :: [atom()] | nil
def default_fields(resource) do
AshJsonApi.Resource.Info.default_fields(resource)
end
@doc """
Gets the available relationship includes for a resource.
Defines which relationships can be included via the `include`
query parameter. Returns `nil` if not configured.
## Parameters
- `resource` - The Ash resource module
## Returns
List of includable relationship paths, or `nil` if not configured.
## Examples
iex> Config.includes(MyApp.Post)
[:author, :comments, "comments.author"]
"""
@spec includes(module()) :: [atom() | String.t()] | nil
def includes(resource) do
AshJsonApi.Resource.Info.includes(resource)
end
@doc """
Gets the primary key field name(s) for a resource.
## Parameters
- `resource` - The Ash resource module
## Returns
List of primary key field names (as atoms).
## Examples
iex> Config.primary_key(MyApp.Post)
[:id]
"""
@spec primary_key(module()) :: [atom()]
def primary_key(resource) do
Ash.Resource.Info.primary_key(resource)
end
@doc """
Gets the OpenAPI tag for a domain.
Tags are used to group operations in OpenAPI documentation tools
like Swagger UI.
## Parameters
- `domain` - The Ash domain module
## Returns
The tag name as a string, or `nil` if not configured.
## Examples
iex> Config.domain_tag(MyApp.Blog)
"Blog"
"""
@spec domain_tag(module()) :: String.t() | nil
def domain_tag(domain) do
AshJsonApi.Domain.Info.tag(domain)
end
@doc """
Gets the route prefix for a domain.
The prefix is prepended to all resource routes in the domain.
## Parameters
- `domain` - The Ash domain module
## Returns
The route prefix as a string (empty string if not configured).
## Examples
iex> Config.route_prefix(MyApp.Blog)
"/api/v1"
iex> Config.route_prefix(MyApp.Admin)
"/admin"
"""
@spec route_prefix(module()) :: String.t()
def route_prefix(domain) do
AshJsonApi.Domain.Info.prefix(domain) || ""
end
@doc """
Gets the operation grouping strategy for a domain.
Determines how operations are grouped in the OpenAPI spec.
## Parameters
- `domain` - The Ash domain module
## Returns
The grouping strategy atom (e.g., `:resource`, `:domain`), or `nil`.
## Examples
iex> Config.group_by(MyApp.Blog)
:resource
"""
@spec group_by(module()) :: atom() | nil
def group_by(domain) do
AshJsonApi.Domain.Info.group_by(domain)
end
@doc """
Gets all resources in a domain.
## Parameters
- `domain` - The Ash domain module
## Returns
List of resource modules.
## Examples
iex> Config.domain_resources(MyApp.Blog)
[MyApp.Post, MyApp.Comment, MyApp.Author]
"""
@spec domain_resources(module()) :: [module()]
def domain_resources(domain) do
Ash.Domain.Info.resources(domain)
end
@doc """
Gets the JSON:API routes for a domain.
## Parameters
- `domain` - The Ash domain module
## Returns
List of route structs.
## Examples
Config.domain_routes(MyApp.Blog)
# => [%{type: :index, ...}, %{type: :get, ...}, ...]
"""
@spec domain_routes(module()) :: [map()]
def domain_routes(domain) do
AshOaskit.RouteGathering.domain_routes(domain)
end
@doc """
Gets the actions for a resource.
## Parameters
- `resource` - The Ash resource module
## Returns
List of action structs.
"""
@spec resource_actions(module()) :: [map()]
def resource_actions(resource) do
Ash.Resource.Info.actions(resource)
end
@doc """
Gets a specific action for a resource by name.
## Parameters
- `resource` - The Ash resource module
- `action_name` - The action name (atom)
## Returns
The action struct or `nil` if not found.
"""
@spec resource_action(module(), atom()) :: map() | nil
def resource_action(resource, action_name) do
Ash.Resource.Info.action(resource, action_name)
end
@doc """
Gets the public attributes for a resource.
Returns only attributes marked `public? true`, which are the ones
that belong in OpenAPI schemas.
## Parameters
- `resource` - The Ash resource module
## Returns
List of attribute structs.
"""
@spec public_attributes(module()) :: [map()]
def public_attributes(resource) do
Ash.Resource.Info.public_attributes(resource)
end
@doc """
Gets the relationships for a resource.
## Parameters
- `resource` - The Ash resource module
## Returns
List of relationship structs.
"""
@spec relationships(module()) :: [map()]
def relationships(resource) do
Ash.Resource.Info.relationships(resource)
end
@doc """
Gets a specific relationship for a resource by name.
## Parameters
- `resource` - The Ash resource module
- `name` - The relationship name (atom)
## Returns
The relationship struct or `nil` if not found.
"""
@spec relationship(module(), atom()) :: map() | nil
def relationship(resource, name) do
Ash.Resource.Info.relationship(resource, name)
end
defp default_type(resource) do
resource
|> Module.split()
|> List.last()
|> Macro.underscore()
end
end