AshOaskit.IncludedResources (AshOasKit v0.2.0)

View Source

Generates schemas for the included array in JSON:API responses.

This module provides functions to build the included member schema for compound documents. The included array contains resource objects that are related to the primary data but were not specifically requested.

Included Resources Structure

The included member is a flat array containing resource objects:

{
  "data": {...},
  "included": [
    {"type": "users", "id": "1", "attributes": {...}},
    {"type": "comments", "id": "1", "attributes": {...}},
    {"type": "comments", "id": "2", "attributes": {...}}
  ]
}

Schema Generation

When multiple resource types can appear in included, we use oneOf:

included:
  type: array
  items:
    oneOf:
      - $ref: '#/components/schemas/UserResource'
      - $ref: '#/components/schemas/CommentResource'

Include Relationships

The includable resources are determined by:

  1. Direct relationships on the primary resource
  2. Nested relationships (e.g., comments.author)
  3. Configured includes in AshJsonApi DSL

Usage

# Build included array schema for a resource
AshOaskit.IncludedResources.build_included_schema(Post)

# Build with explicit includable types
AshOaskit.IncludedResources.build_included_schema_for_types(["User", "Comment"])

# Get all includable resources for a resource
AshOaskit.IncludedResources.get_includable_resources(Post)

Summary

Functions

Adds the included schema to a response schema.

Builds an empty included array schema.

Builds component schemas for the included array.

Builds the included array schema for a resource.

Builds the included array schema for explicit resource types.

Builds an included schema with discriminator for better tooling support.

Gives the configured includes for a resource from AshJsonApi DSL.

Gets all includable resource types for a resource.

Gets resource types from explicit include paths.

Checks if a resource has any includable relationships.

Functions

add_included_to_response(response_schema, opts \\ [])

@spec add_included_to_response(
  map(),
  keyword()
) :: map()

Adds the included schema to a response schema.

Options

  • :resource - The primary resource to determine includable types.
  • :types - Explicit list of includable type names.
  • :version - OpenAPI version.

Examples

iex> response = %{type: :object, properties: %{data: %{}}}
...>
...> AshOaskit.IncludedResources.add_included_to_response(response,
...>   types: ["User", "Comment"]
...> )
%{
  type: :object,
  properties: %{
    data: %{},
    included: %{...}
  }
}

build_empty_included_schema()

@spec build_empty_included_schema() :: map()

Builds an empty included array schema.

Used when there are no includable relationships.

Examples

iex> AshOaskit.IncludedResources.build_empty_included_schema()
%{
  type: :array,
  items: %{},
  maxItems: 0
}

build_included_component_schemas(resource_types, opts \\ [])

@spec build_included_component_schemas(
  [String.t()],
  keyword()
) :: map()

Builds component schemas for the included array.

Returns schemas that can be added to components/schemas.

Options

  • :version - OpenAPI version.
  • :name_prefix - Prefix for schema names.

Examples

iex> AshOaskit.IncludedResources.build_included_component_schemas(["User", "Comment"])
%{
  "IncludedResources" => %{...}
}

build_included_schema(resource, opts \\ [])

@spec build_included_schema(
  module(),
  keyword()
) :: map()

Builds the included array schema for a resource.

Analyzes the resource's relationships to determine what types can appear in the included array.

Options

  • :version - OpenAPI version ("3.1" or "3.0"). Defaults to "3.1".
  • :max_depth - Maximum relationship depth to include. Defaults to 2.
  • :schema_prefix - Prefix for schema references. Defaults to "".

Examples

iex> AshOaskit.IncludedResources.build_included_schema(Post)
%{
  type: :array,
  items: %{
    oneOf: [
      %{"$ref" => "#/components/schemas/UserResource"},
      %{"$ref" => "#/components/schemas/CommentResource"}
    ]
  }
}

build_included_schema_for_types(resource_types, opts \\ [])

@spec build_included_schema_for_types(
  [String.t()],
  keyword()
) :: map()

Builds the included array schema for explicit resource types.

Options

  • :version - OpenAPI version ("3.1" or "3.0"). Defaults to "3.1".
  • :schema_prefix - Prefix for schema references. Defaults to "".
  • :schema_suffix - Suffix for schema references. Defaults to "Resource".

Examples

iex> AshOaskit.IncludedResources.build_included_schema_for_types(["User", "Comment"])
%{
  type: :array,
  items: %{
    oneOf: [
      %{"$ref" => "#/components/schemas/UserResource"},
      %{"$ref" => "#/components/schemas/CommentResource"}
    ]
  }
}

build_included_schema_with_discriminator(type_mappings, opts \\ [])

@spec build_included_schema_with_discriminator(
  [{String.t(), String.t()}],
  keyword()
) :: map()

Builds an included schema with discriminator for better tooling support.

The discriminator helps OpenAPI tools understand which schema to use based on the type field.

Options

  • :version - OpenAPI version ("3.1" or "3.0"). Defaults to "3.1".
  • :schema_prefix - Prefix for schema references. Defaults to "".
  • :schema_suffix - Suffix for schema references. Defaults to "Resource".

Examples

iex> types = [{"users", "User"}, {"comments", "Comment"}]
...> AshOaskit.IncludedResources.build_included_schema_with_discriminator(types)
%{
  type: :array,
  items: %{
    oneOf: [...],
    discriminator: %{
      propertyName: "type",
      mapping: %{
        "users" => "#/components/schemas/UserResource",
        "comments" => "#/components/schemas/CommentResource"
      }
    }
  }
}

configured_includes(resource)

@spec configured_includes(module()) :: [String.t()] | nil

Gives the configured includes for a resource from AshJsonApi DSL.

Examples

iex> AshOaskit.IncludedResources.configured_includes(Post)
["author", "comments", "comments.author"]

get_includable_resources(resource, opts \\ [])

@spec get_includable_resources(
  module(),
  keyword()
) :: [String.t()]

Gets all includable resource types for a resource.

Traverses relationships to find all resource types that could potentially appear in the included array.

Options

  • :max_depth - Maximum relationship depth. Defaults to 2.
  • :include_paths - Explicit include paths to follow. If nil, follows all relationships.

Examples

iex> AshOaskit.IncludedResources.get_includable_resources(Post)
["User", "Comment", "Tag"]

get_resources_from_paths(resource, paths)

@spec get_resources_from_paths(module(), [String.t()]) :: [String.t()]

Gets resource types from explicit include paths.

Examples

iex> AshOaskit.IncludedResources.get_resources_from_paths(Post, [
...>   "author",
...>   "comments",
...>   "comments.author"
...> ])
["User", "Comment"]

has_includable_resources?(resource)

@spec has_includable_resources?(module()) :: boolean()

Checks if a resource has any includable relationships.

Examples

iex> AshOaskit.IncludedResources.has_includable_resources?(Post)
true