AshOaskit.SchemaBuilder.RelationshipSchemas (AshOasKit v0.2.1)

View Source

Relationship schema building for JSON:API responses.

This module handles the generation of OpenAPI schemas for Ash resource relationships. JSON:API relationships include resource linkage (id/type) and optional links for navigation.

Overview

In JSON:API, relationships are represented with:

  • data - Resource identifier(s) containing id and type
  • links - Optional self and related URLs for navigation

Cardinality Handling

The schema structure differs based on relationship cardinality:

Relationship TypeCardinalitySchema
belongs_to:oneSingle identifier (nullable)
has_one:oneSingle identifier (nullable)
has_many:manyArray of identifiers
many_to_many:manyArray of identifiers

Nullable Handling by Version

For to-one relationships, null values are handled differently by version:

  • OpenAPI 3.0: Uses "nullable": true on the identifier schema
  • OpenAPI 3.1: Uses oneOf with the identifier and {"type": "null"}

Cycle Detection

When building relationship schemas, the module checks if the destination resource has been seen. If not, it triggers schema generation for that resource to ensure all referenced schemas exist in the spec.

Usage

# Build a relationship schema
{schema, builder} = RelationshipSchemas.build_relationship_schema(builder, rel)

# Add all relationships for a resource
builder = RelationshipSchemas.add_relationships_schema(builder, resource, "Post")

Summary

Functions

Adds the relationships schema for a resource if it has any.

Gets the JSON:API type for a resource.

Gets public relationships for a resource.

Checks if a resource has any public relationships.

Determines if a relationship is to-many or to-one.

Functions

add_relationships_schema(builder, resource, schema_name, opts)

@spec add_relationships_schema(map(), module(), String.t(), keyword()) :: map()

Adds the relationships schema for a resource if it has any.

Creates a schema containing all public relationships with their data (resource linkage) and links properties.

Parameters

  • builder - The SchemaBuilder accumulator
  • resource - The Ash resource module
  • schema_name - Base name for the schema
  • add_schema_fn - Function to add schemas to builder

Returns

Updated builder with relationships schema added (if resource has relationships).

build_relationship_schema(builder, relationship, seen_fn, add_resource_schemas_fn)

@spec build_relationship_schema(map(), map(), function(), function()) ::
  {map(), map()}

Builds a relationship schema with data and links.

Creates a JSON:API compliant relationship object schema that includes the resource linkage (data) and navigation links.

Parameters

  • builder - The SchemaBuilder accumulator
  • relationship - The relationship struct from Ash.Resource.Info

Returns

A tuple of {relationship_schema, updated_builder}.

Example Output

For a to-many relationship:

{
  %{
    "type" => "object",
    "properties" => %{
      "data" => %{
        "type" => "array",
        "items" => %{
          "type" => "object",
          "properties" => %{
            "id" => %{"type" => "string"},
            "type" => %{"type" => "string", "enum" => ["posts"]}
          },
          "required" => ["id", "type"]
        }
      },
      "links" => %{...}
    }
  },
  builder
}

get_json_api_type(resource)

@spec get_json_api_type(module()) :: String.t()

Gets the JSON:API type for a resource.

Uses the configured type from AshJsonApi if available, otherwise derives from the module name.

Parameters

  • resource - The Ash resource module

Returns

The JSON:API type string.

Examples

iex> RelationshipSchemas.get_json_api_type(MyApp.BlogPost)
# From AshJsonApi config or derived from module name
"blog_posts"

get_public_relationships(resource)

@spec get_public_relationships(module()) :: [map()]

Gets public relationships for a resource.

Only relationships marked public? true are included.

Parameters

  • resource - The Ash resource module

Returns

List of public relationship structs.

has_relationships?(resource)

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

Checks if a resource has any public relationships.

Parameters

  • resource - The Ash resource module

Returns

true if the resource has relationships, false otherwise.

relationship_cardinality(arg1)

@spec relationship_cardinality(map()) :: :one | :many

Determines if a relationship is to-many or to-one.

Checks the cardinality field first (Ash 3.x), falling back to relationship type for compatibility.

Parameters

  • rel - The relationship struct

Returns

:one or :many.

Examples

iex> RelationshipSchemas.relationship_cardinality(%{cardinality: :many})
:many

iex> RelationshipSchemas.relationship_cardinality(%{type: :belongs_to})
:one