### Example: `get` with a generic action Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/routing.md Demonstrates using the `get` route helper with a custom generic action that returns a struct conforming to JSON:API resource object format. ```APIDOC ### Example: `get` with a generic action ```elixir get :my_custom_get ``` ```elixir action :my_custom_get, :struct do constraints instance_of: __MODULE__ argument :id, :uuid, allow_nil?: false run fn input, _ -> Ash.get(__MODULE__, input.arguments.id) end end ``` The response is serialized as a standard JSON:API resource object with `type`, `id`, `attributes`, and `relationships`. ``` -------------------------------- ### Install AshJsonApi with Igniter Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/tutorials/getting-started-with-ash-json-api.md Use this command to install the AshJsonApi package if you are using Igniter. ```sh mix igniter.install ash_json_api ``` -------------------------------- ### Generic Action for `get` Helper Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/routing.md Example of using a generic action with the `get` route helper. The action must return a `:struct` with `instance_of: __MODULE__`. ```elixir get :my_custom_get ``` ```elixir action :my_custom_get, :struct do constraints instance_of: __MODULE__ argument :id, :uuid, allow_nil?: false run fn input, _ -> Ash.get(__MODULE__, input.arguments.id) end end ``` -------------------------------- ### Example: `delete` with a generic action Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/routing.md Provides an example of using the `delete` route helper with a generic action, similar to `patch`, requiring path parameters as action arguments. ```APIDOC ### Example: `delete` with a generic action ```elixir delete :fake_delete do route "/delete_fake/:id" end ``` ```elixir action :fake_delete, :struct do constraints instance_of: __MODULE__ argument :id, :uuid run fn input, _ -> Ash.get(__MODULE__, input.arguments.id) end end ``` ``` -------------------------------- ### Example API Interactions with Composite Keys Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/composite-primary-keys.md Demonstrates creating, retrieving, updating, and deleting resources with composite primary keys using the defined URL format and delimiter. The retrieval, update, and delete examples show the composite key encoded in the URL. ```http # Creating a bio POST /bios { "data": { "type": "bio", "attributes": { "author_id": "550e8400-e29b-41d4-a716-446655440000", "category": "sports", "content": "Author bio for sports category" } } } # Retrieving the bio using composite key GET /bios/550e8400-e29b-41d4-a716-446655440000|sports # Updating the bio PATCH /bios/550e8400-e29b-41d4-a716-446655440000|sports { "data": { "type": "bio", "attributes": { "content": "Updated bio content" } } } # Deleting the bio DELETE /bios/550e8400-e29b-41d4-a716-446655440000|sports ``` -------------------------------- ### Get All Tickets via JSON API Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/tutorials/getting-started-with-ash-json-api.md Example of retrieving a list of all tickets using a GET request to the JSON API endpoint. ```bash curl 'localhost:4000/api/json/helpdesk/tickets' ``` -------------------------------- ### Defining Routes on a Resource Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/routing.md Example of how to define API routes directly on a resource using `json_api do routes do ... end end` block. ```APIDOC ## Defining Routes on a Resource ```elixir defmodule MyApp.Support.Ticket do use Ash.Resource, extensions: [AshJsonApi.Resource] json_api do type "ticket" routes do base "/tickets" get :read index :read post :create patch :update delete :destroy end end end ``` `base` sets the path prefix for all routes defined on the resource. ``` -------------------------------- ### Define a GET route for a resource Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/dsls/DSL-AshJsonApi.Domain.md Use the `get` DSL to define a route that retrieves a single record. Specify the resource and the action to be called. ```elixir get resource, action ``` -------------------------------- ### Example: `index` with a generic action Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/routing.md Shows how to use the `index` route helper with a generic action designed to return an array of structs, suitable for JSON:API collection responses. ```APIDOC ### Example: `index` with a generic action ```elixir index :search ``` ```elixir action :search, {:array, :struct} do constraints items: [instance_of: __MODULE__] argument :query, :string, allow_nil?: false run fn input, _ -> # custom search logic {:ok, results} end end ``` ``` -------------------------------- ### Defining Routes on a Domain Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/routing.md Example of how to define API routes within a domain using `json_api do routes do ... end end` block. ```APIDOC ## Defining Routes on a Domain ```elixir defmodule MyApp.Support do use Ash.Domain, extensions: [AshJsonApi.Domain] json_api do routes do base_route "/tickets", MyApp.Support.Ticket do get :read index :read post :create patch :update delete :destroy end end end end ``` `base_route` scopes all nested routes under the given path prefix for the specified resource. ``` -------------------------------- ### Example: Context-Specific Error Handling Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/errors.md An example of an error handler that applies different error formatting logic based on the resource involved in the request. It accesses the resource from the context. ```elixir defmodule MyApp.JsonApiErrorHandler do def handle_error(error, %{resource: resource}) do case resource do MyApp.PaymentResource -> %{error | detail: MyApp.Payments.format_error(error)} _ -> error end end end ``` -------------------------------- ### Define GET index route in AshJsonApi Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/dsls/DSL-AshJsonApi.Domain.md Use this to define a GET route for retrieving a list of records. It requires a resource and an action. ```elixir index resource \ nil, action ``` ```elixir index :read ``` -------------------------------- ### Example: `patch` with a generic action Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/routing.md Illustrates using the `patch` route helper with a generic action, requiring path parameters to be present as action arguments for record identification. ```APIDOC ### Example: `patch` with a generic action ```elixir patch :fake_update do route "/fake_update/:id" end ``` ```elixir action :fake_update, :struct do constraints instance_of: __MODULE__ argument :id, :uuid, allow_nil?: false run fn %{arguments: %{id: id}}, _ -> record = Ash.get!(__MODULE__, id) {:ok, %{record | name: record.name <> "_updated"}} end end ``` ``` -------------------------------- ### Create Location with Related Leads Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/relationships.md Example JSON payload for creating a location resource, including nested data for associated 'leads' that will be automatically created. ```json { "data": { "type": "location", "attributes": { "name": "Test Location", "location": { "lat": 32323, "long": 23232, "address": "test street 123" }, "images": ["url1", "url2", "url3"] }, "relationships": { "leads": { "data": [ { "type": "lead", "meta": { "type": "Roof", "description": "roofing has 3 holes to fix", "priority": "high" } }, { "type": "lead", "meta": { "type": "garden", "description": "Garden looks like it could be polished", "priority": "medium" } } ] } } } } ``` -------------------------------- ### Create a Ticket via JSON API Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/tutorials/getting-started-with-ash-json-api.md Example of creating a new ticket using a POST request to the JSON API endpoint. Ensure correct Content-Type and Accept headers are used. ```bash curl -X POST 'localhost:4000/api/json/helpdesk/tickets' \ --header 'Accept: application/vnd.api+json' \ --header 'Content-Type: application/vnd.api+json' \ --data-raw '{ "data": { "type": "ticket", "attributes": { "subject": "This ticket was created through the JSON API" } } }' ``` -------------------------------- ### Resource Configuration for Paginated Includes Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/paginated-relationships.md Configure a resource to support paginated relationships. This example defines the `Post` resource, specifies `comments` as a paginated include, and sets up JSON:API routes. ```elixir defmodule MyApp.Post do use Ash.Resource, extensions: [AshJsonApi.Resource] json_api do type "post" includes [:comments, :author] paginated_includes [:comments] routes do base "/posts" get :read index :read end end actions do defaults [:read] end relationships do has_many :comments, MyApp.Comment belongs_to :author, MyApp.Author end end ``` -------------------------------- ### Example: Translate Error Messages Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/errors.md An example of an error handler that translates error messages based on the error code using a `MyApp.Gettext` module. ```elixir defmodule MyApp.JsonApiErrorHandler do def handle_error(error, _context) do %{error | detail: MyApp.Gettext.translate_error(error.code, error.detail)} end end ``` -------------------------------- ### json_api.routes.get Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/dsls/DSL-AshJsonApi.Domain.md Defines a GET route for retrieving a single record. It accepts the resource and the action to be performed. ```APIDOC ## json_api.routes.get ### Description A GET route to retrieve a single record ### Method GET ### Endpoint `/resource/:id` (example, actual endpoint depends on configuration) ### Arguments #### Path Parameters - **resource** (module) - Required - The resource that the route's action is defined on - **action** (atom) - Required - The action to call when this route is hit ### Examples ```elixir get :read ``` ```elixir get :read, path_param_is_composite_key: :id ``` ``` -------------------------------- ### Generic Action for `delete` Helper Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/routing.md Example of using a generic action with the `delete` route helper. The action must return a `:struct` and all path parameters must have corresponding arguments. ```elixir delete :fake_delete do route "/delete_fake/:id" end ``` ```elixir action :fake_delete, :struct do constraints instance_of: __MODULE__ argument :id, :uuid run fn input, _ -> Ash.get(__MODULE__, input.arguments.id) end end ``` -------------------------------- ### Add AshJsonApi Dependency to mix.exs Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/tutorials/getting-started-with-ash-json-api.md Add the AshJsonApi dependency to your project's mix.exs file for manual installation. ```elixir defp deps do [ # .. other dependencies {:ash_json_api, "~> 1.0"}, ] end ``` -------------------------------- ### Route Configuration Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/dsls/DSL-AshJsonApi.Resource.md Defines the API routes for a resource, including base paths and specific actions like GET, POST, and relationship management. ```APIDOC ## json_api.routes ### Description Configure the routes that will be exposed via the JSON:API ### Nested DSLs * [get](#json_api-routes-get) * [index](#json_api-routes-index) * [post](#json_api-routes-post) * [patch](#json_api-routes-patch) * [delete](#json_api-routes-delete) * [related](#json_api-routes-related) * [relationship](#json_api-routes-relationship) * [post_to_relationship](#json_api-routes-post_to_relationship) * [patch_relationship](#json_api-routes-patch_relationship) * [delete_from_relationship](#json_api-routes-delete_from_relationship) * [route](#json_api-routes-route) ### Examples ```elixir routes do base "/posts" get :read get :me, route: "/me" index :read post :confirm_name, route: "/confirm_name" patch :update related :comments, :read relationship :comments, :read post_to_relationship :comments patch_relationship :comments delete_from_relationship :comments end ``` ### Options | Name | Type | Default | Docs | |------|------|---------|------| | [`base`](#json_api-routes-base){: #json_api-routes-base } | `String.t` | | A base route for the resource, e.g `"/users"` | ## json_api.routes.get ### Description A GET route to retrieve a single record ### Examples ```elixir get :read ``` ```elixir get :read, path_param_is_composite_key: :id ``` ### Arguments | Name | Type | Default | Docs | |------|------|---------|------| | [`action`](#json_api-routes-get-action){: #json_api-routes-get-action .spark-required} | `atom` | | The action to call when this route is hit | ``` -------------------------------- ### Generic Action for `index` Helper Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/routing.md Example of using a generic action with the `index` route helper. The action must return `{:array, :struct}` with `items: [instance_of: __MODULE__]`. ```elixir index :search ``` ```elixir action :search, {:array, :struct} do constraints items: [instance_of: __MODULE__] argument :query, :string, allow_nil?: false run fn input, _ -> # custom search logic {:ok, results} end end ``` -------------------------------- ### Define Base Routes for Posts and Comments Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/dsls/DSL-AshJsonApi.Domain.md Use `base_route` to define a route prefix and associate actions like `index` and `get` with it. This sets up the basic routing structure for resources. ```elixir base_route "/posts" do index :read get :read end base_route "/comments" do index :read end ``` -------------------------------- ### Generic Action for `patch` Helper Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/routing.md Example of using a generic action with the `patch` route helper. The action must return a `:struct` and all path parameters must have corresponding arguments. ```elixir patch :fake_update do route "/fake_update/:id" end ``` ```elixir action :fake_update, :struct do constraints instance_of: __MODULE__ argument :id, :uuid, allow_nil?: false run fn %{arguments: %{id: id}}, _ -> record = Ash.get!(__MODULE__, id) {:ok, %{record | name: record.name <> "_updated"}} end end ``` -------------------------------- ### Standard CRUD Route: Index Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/routing.md Defines a GET route for listing records. Issues a GET request to `/` by default and supports filtering, sorting, pagination, and includes. `paginate?` option defaults to `true`. ```elixir index :read ``` -------------------------------- ### Set Actor Manually with PlugHelpers Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/authorize-with-json-api.md When authorization is enabled, you need to provide an actor. This example shows how to fetch a user from a token and set them as the actor in the connection using `Ash.PlugHelpers.set_actor/2`. ```elixir defmodule MyAppWeb.Router do pipeline :api do # ... plug :get_actor_from_token end def get_actor_from_token(conn, _opts) do with ["" <> token] <- get_req_header(conn, "authorization"), {:ok, user, _claims} <- MyApp.Guardian.resource_from_token(token) do conn |> Ash.PlugHelpers.set_actor(user) else _ -> conn end end end ``` -------------------------------- ### Basic Pagination Query Parameter Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/paginated-relationships.md Use the `included_page` query parameter with a `limit` to paginate included relationships. This example requests the first 10 comments for a post. ```http GET /posts/1?include=comments&included_page[comments][limit]=10 ``` -------------------------------- ### json_api.routes.index Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/dsls/DSL-AshJsonApi.Domain.md Defines a GET route to retrieve a list of records for a given resource and action. ```APIDOC ## json_api.routes.index ### Description A GET route to retrieve a list of records. ### Method GET ### Endpoint /:id ### Parameters #### Query Parameters - **resource** (module) - Required - The resource that the route's action is defined on - **action** (atom) - Required - The action to call when this route is hit ### Request Example ```elixir index :read ``` ### Response #### Success Response (200) - **data** (list) - A list of records. #### Response Example ```json { "data": [ { "type": "posts", "id": "1", "attributes": { "title": "My First Post", "body": "This is the content of my first post." } } ] } ``` ``` -------------------------------- ### Define an index route for reading records Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/dsls/DSL-AshJsonApi.Domain.md Use the `index` function to define a GET route for retrieving a list of records. It requires the resource module and the action to be called. ```elixir index resource, action ``` ```elixir index :read ``` -------------------------------- ### API Request to Include Paginated Comments Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/paginated-relationships.md Make an API request to fetch a post and its paginated comments. This example requests comments with a limit of 5 and requests the total count. ```bash curl "http://localhost:4000/posts/1?include=comments&included_page[comments][limit]=5&included_page[comments][count]=true" ``` -------------------------------- ### Forward Requests to AshJsonApi Router Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/tutorials/getting-started-with-ash-json-api.md In your Phoenix router, forward requests to your AshJsonApi router to make your resources accessible. This example forwards requests under the /api/json/helpdesk path. ```elixir scope "/api/json" do pipe_through(:api) forward "/helpdesk", HelpdeskWeb.JsonApiRouter end ``` -------------------------------- ### Define Routes on Domain Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/tutorials/getting-started-with-ash-json-api.md Define API routes for a resource directly within the domain using the `routes` block. This example defines routes for 'ticket' resources. ```elixir defmodule Helpdesk.Support do use Ash.Domain, extensions: [AshJsonApi.Domain] json_api do routes do # in the domain `base_route` acts like a scope base_route "/tickets", Helpdesk.Support.Ticket do get :read index :read post :open end end end end ``` -------------------------------- ### Configure Default Limits for Paginated Relationships Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/paginated-relationships.md Set a default limit for paginated relationships at the action level to improve performance for commonly included resources. This example sets a default limit of 20 for the `read` action. ```elixir read :read do primary? true pagination offset?: true, default_limit: 20 end ``` -------------------------------- ### Creating a Resource with Relationships Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/relationships.md Demonstrates how to create a primary resource (e.g., Location) and automatically create associated related resources (e.g., Leads) as part of the same operation. ```APIDOC ## Create Location with Leads ### Description Creates a new location resource and automatically creates associated lead resources. ### Method POST ### Endpoint /locations ### Request Body - **data** (object) - Required - The resource data. - **type** (string) - Required - The resource type, e.g., "location". - **attributes** (object) - Required - The attributes of the location. - **name** (string) - Required - The name of the location. - **location** (object) - Required - Geographic and address details. - **lat** (number) - Required - Latitude. - **long** (number) - Required - Longitude. - **address** (string) - Required - Street address. - **images** (array of strings) - Optional - URLs for location images. - **relationships** (object) - Optional - Relationships to other resources. - **leads** (object) - Optional - The leads associated with the location. - **data** (array of objects) - Required - An array of lead objects. - **type** (string) - Required - The type of the lead, e.g., "lead". - **meta** (object) - Optional - Metadata for the lead. - **type** (string) - Optional - The type of lead (e.g., "Roof"). - **description** (string) - Optional - A description of the lead. - **priority** (string) - Optional - The priority of the lead (e.g., "high"). ### Request Example ```json { "data": { "type": "location", "attributes": { "name": "Test Location", "location": { "lat": 32323, "long": 23232, "address": "test street 123" }, "images": ["url1", "url2", "url3"] }, "relationships": { "leads": { "data": [ { "type": "lead", "meta": { "type": "Roof", "description": "roofing has 3 holes to fix", "priority": "high" } }, { "type": "lead", "meta": { "type": "garden", "description": "Garden looks like it could be polished", "priority": "medium" } } ] } } } } ``` ### Response #### Success Response (200) - **data** (object) - The created location resource, potentially including related data if requested via include parameter. Note: Related data is not returned by default. Use the `include` query parameter as per the JSON:API specification. ``` -------------------------------- ### Get a Specific Ticket via JSON API Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/tutorials/getting-started-with-ash-json-api.md Example of retrieving a single ticket by its UUID using a GET request to the JSON API endpoint. Replace `` with the actual ticket identifier. ```bash # Add the uuid of a Ticket you created earlier curl 'localhost:4000/api/json/helpdesk/tickets/' ``` -------------------------------- ### GET - Fetch a Single Record Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/routing.md Defines a GET route to fetch a single record by its primary key. Issues a GET request to `/:id` by default. ```APIDOC ## `get` — fetch a single record ```elixir get :read ``` Issues a GET request to `/:id` (by default). Looks up a single record by primary key and returns a JSON:API resource object. ``` -------------------------------- ### Standard CRUD Route: Get Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/routing.md Defines a GET route for fetching a single record by primary key. Issues a GET request to `/:id` by default. ```elixir get :read ``` -------------------------------- ### GET - List Records Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/routing.md Defines a GET route to list multiple records. Issues a GET request to `/` by default and supports filtering, sorting, pagination, and includes. ```APIDOC ## `index` — list records ```elixir index :read ``` Issues a GET request to `/` (by default). Returns a JSON:API array of resource objects. Supports filtering, sorting, pagination, and includes. Options: - `paginate?` (default `true`) — whether to apply pagination ``` -------------------------------- ### When to use `route` vs standard helpers Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/routing.md Guidance on choosing between the flexible `route` helper and the convention-driven standard route helpers based on response type and formatting needs. ```APIDOC ### When to use `route` vs standard helpers Use the **standard helpers** when your generic action returns resource instances and you want JSON:API response formatting with `type`, `id`, `attributes`, and `relationships`. Use **`route`** when: - Your action returns a non-resource value (string, map, integer, etc.) - Your action returns nothing (side-effect only) - You want full control over the HTTP method and path - You don't need JSON:API resource object formatting in the response ``` -------------------------------- ### Configure OpenAPI Plug Options Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/open-api.md When using `redoc_ui_plug`, specify `to` and `init_opts` for the `forward` calls to configure the OpenAPI UIs. ```elixir forward "/api/swaggerui", to: OpenApiSpex.Plug.SwaggerUI, init_opts: [ path: "/api/open_api", default_model_expand_depth: 4 ] forward "/api/redoc", to: Redoc.Plug.RedocUI, init_opts: [ spec_url: "/api/open_api" ] forward "/api", YourApp.YourApiRouter ``` -------------------------------- ### GET Route Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/dsls/DSL-AshJsonApi.Domain.md Defines a GET route to retrieve a single record. It can optionally specify a resource and an action to be called. ```APIDOC ## GET /:id ### Description A GET route to retrieve a single record. ### Method GET ### Endpoint /:id ### Parameters #### Query Parameters - **resource** (module) - Optional - The resource that the route's action is defined on. - **action** (atom) - Required - The action to call when this route is hit. ### Options #### Query Parameters - **route** (String.t) - Optional - Defaults to "/:id". The path of the route. - **default_fields** (list(atom)) - Optional - A list of fields to be shown in the attributes of the called route. - **primary?** (boolean) - Optional - Defaults to `false`. Whether or not this is the route that should be linked to by default when rendering links to this type of route. - **metadata** ((any, any, any -> any)) - Optional - A function to generate arbitrary top-level metadata for the JSON:API response. - **modify_conn** ((any, any, any, any -> any)) - Optional - A function to modify the conn before responding. Used for things like setting headers based on the response. Takes `conn, subject, result, request`. - **action_names_in_schema** (keyword) - Optional - A mapping of action names to how they should appear in the OpenAPI schema. - **name** (String.t) - Optional - A globally unique name for this route, to be used when generating docs and open api specifications. - **description** (String.t) - Optional - A human-friendly description of this specific route to use in generated documentation and OpenAPI. If provided, this overrides the action description. - **derive_sort?** (boolean) - Optional - Defaults to `true`. Whether or not to derive a sort parameter based on the sortable fields of the resource. - **derive_filter?** (boolean) - Optional - Defaults to `true`. Whether or not to derive a filter parameter based on the sortable fields of the resource. - **path_param_is_composite_key** (atom) - Optional - The path parameter that should be parsed as a composite primary key. When specified (e.g., :id), the parameter will be split using the resource's primary key delimiter and mapped to individual primary key fields. This is required for resources with composite primary keys to work correctly with GET, PATCH, and DELETE operations. ``` -------------------------------- ### Configure Post Route for Creating Related Resources Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/relationships.md Set up a post route on a 'location' resource to allow the creation of 'lead' resources via the 'leads' relationship argument. ```elixir json_api do routes do base_route "/location", Marketplace.Location do post :create, relationship_arguments: [:leads] end base_route "/lead", Marketplace.Lead do post :create end end end ``` -------------------------------- ### Define a GET Route for a Single Record Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/dsls/DSL-AshJsonApi.Resource.md Creates a GET endpoint to retrieve a single record. Specify the action to be called when the route is matched. ```elixir get :read ``` -------------------------------- ### Add open_api_spex and redoc_ui_plug Dependencies Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/open-api.md Include both `:open_api_spex` and `:redoc_ui_plug` dependencies for full OpenAPI UI support. ```elixir {:open_api_spex, "~> 3.16"}, {:redoc_ui_plug, "~> 0.2.1"}, ``` -------------------------------- ### Route Overview Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/routing.md A table summarizing the available route helpers, their corresponding HTTP methods, default paths, primary action types, and accepted options. ```APIDOC ## Route Overview | Route Helper | HTTP Method | Default Path | Primary Action Type | Also Accepts | |---|---|---|---|---| | `get` | GET | `/:id` | `:read` | `:action` | | `index` | GET | `/` | `:read` | `:action` | | `post` | POST | `/` | `:create` | `:action`, `:read` | | `patch` | PATCH | `/:id` | `:update` | `:action` | | `delete` | DELETE | `/:id` | `:destroy` | `:action` | | `related` | GET | `/:id/` | `:read` | — | | `relationship` | GET | `/:id/relationships/` | `:read` | — | | `post_to_relationship` | POST | `/:id/relationships/` | `:update` | — | | `patch_relationship` | PATCH | `/:id/relationships/` | `:update` | — | | `delete_from_relationship` | DELETE | `/:id/relationships/` | `:update` | — | | `route` | *any* | *required* | `:action` | — | ``` -------------------------------- ### Define a GET Route Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/dsls/DSL-AshJsonApi.Domain.md Defines a GET route for a single record. The `action` argument specifies the function to call. Optionally, `resource` can be provided if it's not inferred. ```elixir get resource \ nil, action ``` -------------------------------- ### Example: Add Custom Metadata to Errors Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/errors.md An example of an error handler that adds custom metadata, such as the API version, to the error response. It accesses the domain from the context. ```elixir defmodule MyApp.JsonApiErrorHandler do def handle_error(error, %{domain: domain}) do %{error | meta: Map.put(error.meta || %{}, :api_version, "v2")} end end ``` -------------------------------- ### Configure Sign-in Route with Token Metadata Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/authenticate-with-json-api.md Configure a POST route for the `:sign_in_with_password` action to include the generated authentication token in the response metadata. This is useful for providing the token to the client for future requests. ```elixir defmodule ..User do json_api do routes do post :sign_in_with_password do route "/sign_in" metadata fn _subject, user, _request -> %{token: user.__metadata__.token} end end end end end ``` -------------------------------- ### Define a GET Route with Composite Key Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/dsls/DSL-AshJsonApi.Resource.md Creates a GET endpoint for retrieving a single record using a composite key. Specify the action and the path parameter for the composite key. ```elixir get :read, path_param_is_composite_key: :id ``` -------------------------------- ### Configure OpenAPI Tag and Grouping Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/dsls/DSL-AshJsonApi.Domain.md Configure OpenAPI documentation by setting tags and grouping resources by API or resource. ```elixir json_api do ... open_api do tag "Users" group_by :api end end ``` -------------------------------- ### Define Create Action for Lead Resource Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/relationships.md Define the 'create' action for the 'lead' resource, specifying the accepted attributes for new lead creation. ```elixir actions do create :create do primary?(true) accept([:type, :description, :priority, :location_id]) end end ``` -------------------------------- ### json_api.routes.base_route.index Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/dsls/DSL-AshJsonApi.Domain.md Defines a GET route to retrieve a list of records for a given resource and action. ```APIDOC ## json_api.routes.base_route.index ### Description A GET route to retrieve a list of records. ### Method GET ### Endpoint / ### Arguments - **resource** (module) - The resource that the route's action is defined on - **action** (atom) - Required - The action to call when this route is hit ### Options - **paginate?** (boolean) - Optional - Defaults to `true`. Whether to enable pagination. - **route** (String.t) - Optional - Defaults to "/". The path of the route. - **default_fields** (list(atom)) - Optional - A list of fields to be shown in the attributes of the called route. - **primary?** (boolean) - Optional - Defaults to `false`. Whether or not this is the route that should be linked to by default. - **metadata** ((any, any, any -> any)) - Optional - A function to generate arbitrary top-level metadata for the JSON:API response. - **modify_conn** ((any, any, any, any -> any)) - Optional - A function to modify the conn before responding. - **action_names_in_schema** (keyword) - Optional - A mapping of action names to how they should appear in the OpenAPI schema. - **name** (String.t) - Optional - A globally unique name for this route. - **description** (String.t) - Optional - A human-friendly description of this specific route. - **derive_sort?** (boolean) - Optional - Defaults to `true`. Whether to derive a sort parameter. - **derive_filter?** (boolean) - Optional - Defaults to `true`. Whether to derive a filter parameter. - **path_param_is_composite_key** (atom) - Optional - The path parameter that should be parsed as a composite primary key. ``` -------------------------------- ### json_api.routes.base_route.related Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/dsls/DSL-AshJsonApi.Domain.md Defines a GET route to read related resources of a relationship. It takes the resource, relationship, and action as arguments. ```APIDOC ## json_api.routes.base_route.related ### Description A GET route to read the related resources of a relationship. ### Method GET ### Endpoint /related/:relationship_id ### Parameters #### Path Parameters - **resource** (module) - Optional - The resource that the route's action is defined on - **relationship** (atom) - Required - The relationship to read related resources from - **action** (atom) - Required - The action to call when this route is hit ### Request Example ```elixir related :comments, :read ``` ### Response #### Success Response (200) - **data** (list) - A list of related resources. #### Response Example ```json { "data": [ { "type": "comments", "id": "1", "attributes": { "body": "This is a comment." } } ] } ``` ``` -------------------------------- ### Define POST Route for Resource Creation Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/dsls/DSL-AshJsonApi.Domain.md Use this to define a POST route that creates a record for a given resource. It requires the resource module and the action to call. ```elixir post resource, action ``` -------------------------------- ### Define POST create route in AshJsonApi Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/dsls/DSL-AshJsonApi.Domain.md Use this to define a POST route for creating a record. It requires a resource and an action. ```elixir post resource \ nil, action ``` ```elixir post :create ``` -------------------------------- ### Returning Authentication Tokens in Headers Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/modify-conn.md Implement a pattern to return authentication tokens in the `authorization` header after a successful sign-in action. ```elixir defmodule MyApp.User do use Ash.Resource, domain: MyApp.Domain, extensions: [AshJsonApi.Resource] json_api do routes do base "/users" post :sign_in do route "/sign_in/:id" modify_conn(fn conn, _subject, result, _request -> case result do %{__metadata__: %{token: token}} when not is_nil(token) -> Plug.Conn.put_resp_header(conn, "authorization", "Bearer #{token}") _ -> conn end end) end end end end ``` -------------------------------- ### Generate Self Link for Individual Entities Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/links.md Designate a `get` route as `primary?: true` to generate a `self` link for each individual entity. ```elixir get :read, primary?: true ``` -------------------------------- ### Related Resource Route Definition Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/dsls/DSL-AshJsonApi.Domain.md Defines a GET route for fetching related resources of a relationship. The `:action` argument specifies how to load the relationship itself. ```elixir related resource \ nil, relationship, action ``` -------------------------------- ### json_api.routes.related Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/dsls/DSL-AshJsonApi.Domain.md Defines a GET route to retrieve related resources for a given relationship. It allows specifying the action to fetch the source record and the relationship to query. ```APIDOC ## json_api.routes.related ### Description A GET route to read the related resources of a relationship. The `:action` argument is the read action used to fetch the source record. The action used to load the relationship itself is configured on the relationship (e.g. `has_many :comments, Comment, read_action: :foo`). ### Method GET ### Endpoint `/related/:relationship` (example, actual endpoint depends on configuration) ### Parameters #### Path Parameters - **resource** (module) - Required - The resource that the route's action is defined on - **relationship** (atom) - Required - The relationship to query - **action** (atom) - Required - The action to call when this route is hit ### Request Example ```elixir related :comments, :read ``` ### Response #### Success Response (200) - **data** (list) - A list of related resources. - **links** (object) - Links related to the response. #### Response Example ```json { "data": [ { "type": "comments", "id": "1", "attributes": { "body": "This is a comment." } } ], "links": { "self": "/comments?filter[post_id]=1" } } ``` ``` -------------------------------- ### Path and Query Parameters Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/routing.md Arguments can be supplied via path parameters, query parameters, or the request body, depending on the HTTP method and route configuration. ```APIDOC ### Path parameters and query parameters Arguments can be supplied via path parameters, query parameters, or the request body. **Path parameters** — embed `:arg_name` segments in the route: ```elixir route :get, "/say_hello/:name", :say_hello # GET /say_hello/fred → name = "fred" ``` **Query parameters** — use the `query_params` option: ```elixir route :get, "/say_hello", :say_hello, query_params: [:name] # GET /say_hello?name=fred → name = "fred" ``` For GET requests using `route`, all action arguments are automatically accepted as query parameters even without specifying `query_params`. **Request body** — for POST/PATCH/DELETE, remaining arguments are read from the JSON body under `data`: ```elixir route :post, "/greet/:name", :greet # POST /greet/fred with body {"data": {"greeting": "Hi"}} # → name = "fred", greeting = "Hi" ``` > ### Conflicting parameters {: .warning} > > If the same argument appears in both the path and query string, the request returns a `400` error with an `invalid_query` error code. ``` -------------------------------- ### Custom Path for Standard Routes Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/routing.md Overrides the default path for standard CRUD routes. Example shows custom paths for `patch` and `delete` actions. ```elixir patch :update_email do route "/update_email/:id" end delete :archive do route "/archive/:id" end ``` -------------------------------- ### Serve OpenAPI Spec from File in Production Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/open-api.md Use the `open_api_file` option to serve a static OpenAPI spec file in production, improving performance. The file path is conditionally set based on the environment. ```elixir open_api_file = if Mix.env() == :prod do "priv/static/open_api.json" else nil end use AshJsonApi.Router, domains: [...], open_api: "/open_api", modify_open_api: {__MODULE__, :modify_open_api, []}, open_api_file: open_api_file ``` -------------------------------- ### Combine Field and Argument Name Transformations Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/field-names.md Use `field_names` and `argument_names` together for consistent naming conventions across the API. This example applies camelCase to both. ```elixir json_api do type "user" field_names :camelize argument_names :camelize end ``` -------------------------------- ### Offset Pagination Query Parameters Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/paginated-relationships.md Employ `limit` and `offset` within the `included_page` parameter for offset-based pagination. This retrieves 10 comments starting from the 21st. ```http GET /posts/1?include=comments&included_page[comments][limit]=10&included_page[comments][offset]=20 ``` -------------------------------- ### Configure AshJsonApi Router for OpenAPI Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/open-api.md Add the `open_api` option to your `use AshJsonApi.Router` call to specify the OpenAPI endpoint path. ```elixir use AshJsonApi.Router, domains: [...], open_api: "/open_api" ``` -------------------------------- ### Keyset Pagination Query Parameter Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/paginated-relationships.md Utilize `limit` and `after` (or `before`) within `included_page` for keyset (cursor-based) pagination. Replace `` with the actual cursor value. ```http GET /posts/1?include=comments&included_page[comments][limit]=10&included_page[comments][after]= ``` -------------------------------- ### Returning simple values Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/routing.md Actions can return raw values directly, which are then serialized as the response body. For example, returning a string results in a plain text response. ```APIDOC ## Returning simple values Actions can return raw values directly, which are then serialized as the response body. For example, returning a string results in a plain text response. ```elixir action :say_hello, :string do argument :name, :string, allow_nil?: false run fn input, _ -> {:ok, "Hello, #{input.arguments.name}!"} end end ``` The response body is the raw value: `"Hello, fred!"` ``` -------------------------------- ### Add open_api_spex Dependency Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/open-api.md Include the `:open_api_spex` dependency in your `mix.exs` file to enable OpenAPI support. ```elixir {:open_api_spex, "~> 3.16"}, ``` -------------------------------- ### Define Action Returning Nothing Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/routing.md Use this for actions that perform a side effect and do not need to return a value. The response will be `{"success": true}`. ```elixir action :trigger_job do run fn _input, _ -> :ok end end ``` -------------------------------- ### Define Action Returning Simple String Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/routing.md Use this to define an action that returns a simple string value. The response body will be the raw string. ```elixir action :say_hello, :string do argument :name, :string, allow_nil?: false run fn input, _ -> {:ok, "Hello, #{input.arguments.name}!"} end end ``` -------------------------------- ### Index Action for JSON:API Route Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/dsls/DSL-AshJsonApi.Resource.md Defines a GET route for retrieving a list of records using the 'index' action. This is a common pattern for fetching collections of resources. ```elixir index :read ``` -------------------------------- ### Define a JSON:API Route Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/dsls/DSL-AshJsonApi.Resource.md Use the `route/3` macro to define a new route for a resource. Specify the HTTP method, the route path, and the action to be executed. ```elixir route :get, "say_hi/:name", :say_hello ``` -------------------------------- ### Configure Domain with Error Handler Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/topics/errors.md Configure the `error_handler` option in your Ash domain to intercept and transform `AshJsonApi.Error` structs before they are sent to the client. This example sets up a handler for `MyApp.JsonApiErrorHandler`. ```elixir defmodule MyApp.Domain do use Ash.Domain, extensions: [AshJsonApi.Domain] json_api do error_handler {MyApp.JsonApiErrorHandler, :handle_error, []} end end ``` -------------------------------- ### Extend Resource with AshJsonApi using Igniter Source: https://github.com/ash-project/ash_json_api/blob/main/documentation/tutorials/getting-started-with-ash-json-api.md Use this mix command to apply the AshJsonApi extension to an existing Ash resource. ```sh mix ash.patch.extend Your.Resource.Name json_api ```