### Defining Routes on the Resource Source: https://hexdocs.pm/ash_json_api/getting-started-with-ash-json-api.md Example of defining routes on an Ash resource using AshJsonApi. ```elixir defmodule Helpdesk.Support.Ticket do use Ash.Resource, extensions: [AshJsonApi.Resource] # ... json_api do type "ticket" routes do # on the resource, the `base` applies to all routes base "/tickets" get :read index :read post :open # ... end end end ``` -------------------------------- ### Example Route Source: https://hexdocs.pm/ash_json_api/dsl-ashjsonapi-resource.md An example demonstrating how to define a GET route for a 'say_hello' action with a dynamic 'name' parameter. ```elixir route :get, "say_hi/:name", :say_hello ``` -------------------------------- ### Example Routes Configuration Source: https://hexdocs.pm/ash_json_api/dsl-ashjsonapi-resource.md This example demonstrates how to configure routes for a resource using the `routes` DSL, including base path, GET, POST, PATCH, and relationship routes. ```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 ``` -------------------------------- ### Install AshJsonApi using Igniter Source: https://hexdocs.pm/ash_json_api/getting-started-with-ash-json-api.md Command to install the ash_json_api package using the igniter mix task. ```sh mix igniter.install ash_json_api ``` -------------------------------- ### Example: `get` with a generic action Source: https://hexdocs.pm/ash_json_api/routing.md Illustrates using the `get` helper with a generic action that returns a struct. ```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 ``` -------------------------------- ### GET Route Examples Source: https://hexdocs.pm/ash_json_api/dsl-ashjsonapi-domain.md Examples of how to use the get function within a base_route. ```elixir get :read ``` ```elixir get :read, path_param_is_composite_key: :id ``` -------------------------------- ### Getting Available Routes Source: https://hexdocs.pm/ash_json_api/getting-started-with-ash-json-api.md How to retrieve and display all available routes for a given Ash resource. ```elixir Helpdesk.Support.Ticket |> AshJsonApi.Resource.Info.routes(Helpdesk.Support) ``` -------------------------------- ### Create a Ticket Source: https://hexdocs.pm/ash_json_api/getting-started-with-ash-json-api.md Example cURL command to create a new ticket via the JSON API. ```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" } } }' ``` -------------------------------- ### Example Source: https://hexdocs.pm/ash_json_api/AshJsonApi.OpenApi.md Example of how to define an OpenAPI specification using AshJsonApi.OpenApi. ```elixir defmodule MyApp.OpenApi do alias OpenApiSpex.{OpenApi, Info, Server, Components} def spec do %OpenApi{ info: %Info{ title: "MyApp JSON API", version: "1.1" }, servers: [ Server.from_endpoint(MyAppWeb.Endpoint) ], paths: AshJsonApi.OpenApi.paths(MyApp.Api), tags: AshJsonApi.OpenApi.tags(MyApp.Api), components: %Components{ responses: AshJsonApi.OpenApi.responses(), schemas: AshJsonApi.OpenApi.schemas(MyApp.Api) } } end end ``` -------------------------------- ### GET Route with Composite Key Example Source: https://hexdocs.pm/ash_json_api/dsl-ashjsonapi-resource.md Example of a GET route configuration that specifies a composite primary key parameter. ```elixir get :read, path_param_is_composite_key: :id ``` -------------------------------- ### Install AshJsonApi Source: https://hexdocs.pm/ash_json_api/Mix.Tasks.AshJsonApi.Install.md Installs AshJsonApi. Should be run with `mix igniter.install ash_json_api` ```bash mix ash_json_api.install ``` -------------------------------- ### Define routes on the domain Source: https://hexdocs.pm/ash_json_api/getting-started-with-ash-json-api.md Elixir code demonstrating how to define JSON:API routes on an Ash domain. ```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 ``` -------------------------------- ### Create AshJsonApi Router Source: https://hexdocs.pm/ash_json_api/getting-started-with-ash-json-api.md Elixir code for creating a router module to serve AshJsonApi domains. ```elixir defmodule HelpdeskWeb.JsonApiRouter do use AshJsonApi.Router, # The api modules you want to serve domains: [Helpdesk.Support], # optionally an open_api route open_api: "/open_api" end ``` -------------------------------- ### Get All Tickets Source: https://hexdocs.pm/ash_json_api/getting-started-with-ash-json-api.md Example cURL command to retrieve all tickets from the JSON API. ```bash curl 'localhost:4000/api/json/helpdesk/tickets' ``` -------------------------------- ### Example Implementation Source: https://hexdocs.pm/ash_json_api/AshJsonApi.ToJsonApiError.md Example of implementing the `ToJsonApiError` protocol for a custom Ash exception. ```elixir defmodule NotAvailable do use Ash.Error.Exception use Splode.Error, fields: [], class: :invalid defimpl AshJsonApi.ToJsonApiError do def to_json_api_error(error) do %AshJsonApi.Error{ id: Ash.UUID.generate(), status_code: 409, code: "not_available", title: "not_available", detail: "Not available" } end end end ``` -------------------------------- ### Example of primary_key configuration Source: https://hexdocs.pm/ash_json_api/dsl-ashjsonapi-resource.md This example demonstrates how to configure the primary_key for a JSON API route, specifying the keys to be used and the delimiter. ```elixir primary_key do keys [:first_name, :last_name] delimiter "~" end ``` -------------------------------- ### Example HTTP Message Source: https://hexdocs.pm/ash_json_api/AshJsonApi.Plug.Parser.md An example of an HTTP POST request using `multipart/x.ash+form-data`. ```http POST /action Host: example.com Content-Length: 2740 Content-Type: multipart/x.ash+form-data; boundary=abcde12345 --abcde12345 Content-Disposition: form-data; name="data" Content-Type: application/vnd.api+json {"users": "users_csv", "meatdata": "metadata_json"} --abcde12345 Content-Disposition: form-data; name="users_csv"; filename="users.csv" Content-Type: text/csv [file content goes here] --abcde12345 Content-Disposition: form-data; name="metadata_json"; filename="metadata.json" Content-Type: application/json [file content goes there] --abcde12345-- ``` -------------------------------- ### Add AshJsonApi.Domain extension to domain Source: https://hexdocs.pm/ash_json_api/getting-started-with-ash-json-api.md Elixir code snippet showing how to add the AshJsonApi.Domain extension to an Ash domain. ```elixir defmodule Helpdesk.Support do use Ash.Domain, extensions: [AshJsonApi.Domain] ... end ``` -------------------------------- ### Extend Resource with AshJsonApi using Igniter Source: https://hexdocs.pm/ash_json_api/getting-started-with-ash-json-api.md Command to extend an existing resource with AshJsonApi using the ash.patch.extend mix task. ```sh mix ash.patch.extend Your.Resource.Name json_api ``` -------------------------------- ### Delete Action Example Source: https://hexdocs.pm/ash_json_api/dsl-ashjsonapi-resource.md Example of defining a DELETE route to destroy a record. ```elixir delete :destroy ``` ```elixir delete :destroy, path_param_is_composite_key: :id ``` -------------------------------- ### Plug Parsers Configuration Source: https://hexdocs.pm/ash_json_api/AshJsonApi.Plug.Parser.md Example configuration for `Plug.Parsers` to include `AshJsonApi.Plug.Parser`. ```elixir plug Plug.Parsers, parsers: [:urlencoded, :multipart, :json, AshJsonApi.Plug.Parser], pass: ["*/*"], json_decoder: Jason ``` -------------------------------- ### Add AshJsonApi.Plug.Parser to endpoint Source: https://hexdocs.pm/ash_json_api/getting-started-with-ash-json-api.md Elixir code snippet for adding AshJsonApi.Plug.Parser to the Plug.Parsers configuration in the endpoint. ```elixir plug Plug.Parsers, parsers: [:urlencoded, :multipart, :json, AshJsonApi.Plug.Parser], # <- add it to this list. pass: ["*/*"], json_decoder: Jason ``` -------------------------------- ### refute_has_matching_include Example Source: https://hexdocs.pm/ash_json_api/AshJsonApi.Test.md Example demonstrating how to refute that any included record matches a given function. ```elixir Domain |> get("/posts/#{post.id}/?include=author", status: 200) |> refute_has_matching_include(fn %{"type" => "author", "id" => ^author_id} -> true _ -> false end) ``` -------------------------------- ### Patch Route Example 2 Source: https://hexdocs.pm/ash_json_api/dsl-ashjsonapi-domain.md An example of using the patch route with the `path_param_is_composite_key` option. ```elixir patch :update, path_param_is_composite_key: :id ``` -------------------------------- ### Base Route Examples Source: https://hexdocs.pm/ash_json_api/dsl-ashjsonapi-domain.md Demonstrates defining base routes for posts and comments. ```elixir base_route "/posts" do index :read get :read end base_route "/comments" do index :read end ``` -------------------------------- ### Force recompile mime dependency Source: https://hexdocs.pm/ash_json_api/getting-started-with-ash-json-api.md Command to force recompile the mime dependency if a runtime configuration error occurs. ```sh mix deps.compile mime --force ``` -------------------------------- ### Add ash_json_api dependency to mix.exs Source: https://hexdocs.pm/ash_json_api/getting-started-with-ash-json-api.md Elixir code snippet showing how to add the ash_json_api dependency to the mix.exs file. ```elixir defp deps do [ # .. other dependencies {:ash_json_api, "~> 1.0"}, ] end ``` -------------------------------- ### Configure mime types for JSON:API Source: https://hexdocs.pm/ash_json_api/getting-started-with-ash-json-api.md Elixir configuration for the mime application to accept the application/vnd.api+json content type. ```elixir config :mime, extensions: %{"json" => "application/vnd.api+json"}, types: %{"application/vnd.api+json" => ["json"]} ``` -------------------------------- ### assert_has_matching_include Example Source: https://hexdocs.pm/ash_json_api/AshJsonApi.Test.md Example demonstrating how to assert that at least one included record matches a given function. ```elixir Domain |> get("/posts/#{post.id}/?include=author", status: 200) |> assert_has_matching_include(fn %{"type" => "author", "id" => ^author_id} -> true _ -> false end) ``` -------------------------------- ### Patch Route Example Source: https://hexdocs.pm/ash_json_api/dsl-ashjsonapi-resource.md Example of defining a PATCH route for updating a record. ```elixir patch :update ``` ```elixir patch :update, path_param_is_composite_key: :id ``` -------------------------------- ### Add AshJsonApi.Resource extension and type to resource Source: https://hexdocs.pm/ash_json_api/getting-started-with-ash-json-api.md Elixir code snippet showing how to add the AshJsonApi.Resource extension and define the JSON:API type for an Ash resource. ```elixir defmodule Helpdesk.Support.Ticket do use Ash.Resource, extensions: [AshJsonApi.Resource] # ... json_api do type "ticket" end end ``` -------------------------------- ### Example: `delete` with a generic action Source: https://hexdocs.pm/ash_json_api/routing.md Illustrates using the `delete` helper with a generic action and defining its route. ```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: Context-Specific Handling Source: https://hexdocs.pm/ash_json_api/errors.md Example of an error handler that provides context-specific error handling based on the resource. ```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 ``` -------------------------------- ### Returning nothing Source: https://hexdocs.pm/ash_json_api/routing.md An example of an action that returns nothing, resulting in a success response. ```elixir action :trigger_job do run fn _input, _ -> :ok end end ``` -------------------------------- ### Query parameters Source: https://hexdocs.pm/ash_json_api/routing.md Example of using query parameters with the `query_params` option. ```elixir route :get, "/say_hello", :say_hello, query_params: [:name] # GET /say_hello?name=fred → name = "fred" ``` -------------------------------- ### argument_names with keyword list Source: https://hexdocs.pm/ash_json_api/dsl-ashjsonapi-resource.md Example of renaming arguments using a nested keyword list. ```elixir argument_names [ create: [my_arg: :myArg], update: [my_arg: :myArg] ] ``` -------------------------------- ### Returning simple values Source: https://hexdocs.pm/ash_json_api/routing.md An example of an action that returns a simple string value. ```elixir action :say_hello, :string do argument :name, :string, allow_nil?: false run fn input, _ -> {:ok, "Hello, #{input.arguments.name}!"} end end ``` -------------------------------- ### Path parameters Source: https://hexdocs.pm/ash_json_api/routing.md Example of using path parameters in a route. ```elixir route :get, "/say_hello/:name", :say_hello # GET /say_hello/fred → name = "fred" ``` -------------------------------- ### Renaming Calculation Arguments with `:camelize` Source: https://hexdocs.pm/ash_json_api/dsl-ashjsonapi-resource.md Example demonstrating how to use `:camelize` to rename calculation arguments. ```elixir calculation_argument_names :camelize # publish_at → publishAt calculation_argument_names :dasherize # publish_at → publish-at ``` -------------------------------- ### Example Combining Multiple Features Source: https://hexdocs.pm/ash_json_api/paginated-relationships.md Example URL demonstrating the combination of paginated relationships with sparse fieldsets, filtering, and sorting. ```http GET /posts/1? include=comments& included_page[comments][limit]=10& filter_included[comments][status]=published& sort_included[comments]=-created_at& fields[comment]=body,author_name ``` -------------------------------- ### field_names with keyword list Source: https://hexdocs.pm/ash_json_api/dsl-ashjsonapi-resource.md Example of renaming fields using a keyword list. ```elixir field_names [ first_name: :firstName, last_name: :lastName ] ``` -------------------------------- ### Example: Adding Custom Metadata Source: https://hexdocs.pm/ash_json_api/errors.md Example of an error handler that adds custom metadata to errors. ```elixir defmodule MyApp.JsonApiErrorHandler do def handle_error(error, %{domain: domain}) do %{error | meta: Map.put(error.meta || %{}, :api_version, "v2")} end end ``` -------------------------------- ### argument_names with a function Source: https://hexdocs.pm/ash_json_api/dsl-ashjsonapi-resource.md Example of renaming arguments using a custom function. ```elixir argument_names fn _action, name -> camelized = name |> to_string() |> Macro.camelize() {first, rest} = String.split_at(camelized, 1) String.downcase(first) <> rest end ``` -------------------------------- ### argument_names :dasherize Source: https://hexdocs.pm/ash_json_api/dsl-ashjsonapi-resource.md Example of renaming arguments using the :dasherize atom. ```elixir argument_names :dasherize # publish_at → publish-at ``` -------------------------------- ### argument_names :camelize Source: https://hexdocs.pm/ash_json_api/dsl-ashjsonapi-resource.md Example of renaming arguments using the :camelize atom. ```elixir argument_names :camelize # publish_at → publishAt ``` -------------------------------- ### Phoenix Router Integration Source: https://hexdocs.pm/ash_json_api/AshJsonApi.Router.md Example of how to forward requests to the AshJsonApi router within a Phoenix router. ```elixir forward "/api", YourRouter ``` -------------------------------- ### Get a Specific Ticket Source: https://hexdocs.pm/ash_json_api/getting-started-with-ash-json-api.md Example cURL command to retrieve a specific ticket by its UUID from the JSON API. ```bash # Add the uuid of a Ticket you created earlier curl 'localhost:4000/api/json/helpdesk/tickets/' ``` -------------------------------- ### Request body parameters Source: https://hexdocs.pm/ash_json_api/routing.md Example of reading arguments from the JSON request body for POST/PATCH/DELETE requests. ```elixir route :post, "/greet/:name", :greet # POST /greet/fred with body {"data": {"greeting": "Hi"}} # → name = "fred", greeting = "Hi" ``` -------------------------------- ### Example: `index` with a generic action Source: https://hexdocs.pm/ash_json_api/routing.md Shows how to use the `index` helper with a generic action that returns an array of structs. ```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 ``` -------------------------------- ### Paginated Relationships Usage Source: https://hexdocs.pm/ash_json_api/changelog.md Example of how to use the `included_page` query parameter to paginate relationships in a GET request. ```http GET /posts/1?include=comments&included_page[comments][limit]=10&included_page[comments][offset]=5 ``` -------------------------------- ### Example: `patch` with a generic action Source: https://hexdocs.pm/ash_json_api/routing.md Demonstrates using the `patch` helper with a generic action, including defining the route. ```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 ``` -------------------------------- ### Forward requests to AshJsonApi Router from Phoenix router Source: https://hexdocs.pm/ash_json_api/getting-started-with-ash-json-api.md Elixir code for forwarding requests from a Phoenix router to the AshJsonApi router. ```elixir scope "/api/json" do pipe_through(:api) forward "/helpdesk", HelpdeskWeb.JsonApiRouter end ``` -------------------------------- ### Configure Plug UI endpoints with init_opts Source: https://hexdocs.pm/ash_json_api/open-api.md An alternative way to configure `SwaggerUI` and `RedocUI` using `init_opts`. ```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 Signature Source: https://hexdocs.pm/ash_json_api/dsl-ashjsonapi-domain.md The signature for a GET route. ```elixir get resource \ nil, action ``` -------------------------------- ### Customizing Request Handling Source: https://hexdocs.pm/ash_json_api/AshJsonApi.Router.md Example of using the `before_dispatch` option to customize request handling, such as setting monitoring information. ```elixir use AshJsonApi.Router, ..., before_dispatch: {__MODULE__, :before_dispatch, []} def before_dispatch(conn, route_info) do ... end ``` -------------------------------- ### Example Alias Configuration Source: https://hexdocs.pm/ash_json_api/Mix.Tasks.AshJsonApi.Routes.md Shows how to configure Mix aliases to run `phx.routes` and `ash_json_api.routes` consecutively. ```elixir aliases: ["phx.routes": ["do", "phx.routes,", "ash_json_api.routes"]] ``` -------------------------------- ### assert_has_error Example Source: https://hexdocs.pm/ash_json_api/AshJsonApi.Test.md Example demonstrating how to assert that an error is present in the response. ```elixir Domain |> delete("/posts/1", status: 404) |> assert_has_error(%{ "code" => "not_found", "detail" => "No post record found with `id: 1`", "title" => "Entity Not Found" }) ``` -------------------------------- ### OpenAPI Configuration Source: https://hexdocs.pm/ash_json_api/dsl-ashjsonapi-domain.md OpenAPI configurations. ```elixir json_api do ... open_api do tag "Users" group_by :api end end ``` -------------------------------- ### exception Source: https://hexdocs.pm/ash_json_api/AshJsonApi.Error.UnsupportedMediaType.md Create an Elixir.AshJsonApi.Error.UnsupportedMediaType without raising it. ```elixir @spec exception(opts :: Keyword.t()) :: %AshJsonApi.Error.UnsupportedMediaType{ __exception__: true, bread_crumbs: term(), class: term(), path: term(), splode: term(), stacktrace: term(), vars: term() } ``` -------------------------------- ### Add :redoc_ui_plug dependency Source: https://hexdocs.pm/ash_json_api/open-api.md When using `RedocUI`, ensure both `:open_api_spex` and `:redoc_ui_plug` dependencies are included. ```elixir {:open_api_spex, "~> 3.16"}, {:redoc_ui_plug, "~> 0.2.1"} ``` -------------------------------- ### Example: Translating Error Messages Source: https://hexdocs.pm/ash_json_api/errors.md Example of an error handler that translates error messages. ```elixir defmodule MyApp.JsonApiErrorHandler do def handle_error(error, _context) do %{error | detail: MyApp.Gettext.translate_error(error.code, error.detail)} end end ``` -------------------------------- ### Get Route Source: https://hexdocs.pm/ash_json_api/routing.md Issues a GET request to `/:id` (by default) to fetch a single record. ```elixir get :read ``` -------------------------------- ### Primary Get Route Source: https://hexdocs.pm/ash_json_api/links.md Designating a 'get' route as primary to generate a self link for an individual entity. ```elixir get :read, primary?: true ``` -------------------------------- ### Renaming Calculation Arguments with a Keyword List Source: https://hexdocs.pm/ash_json_api/dsl-ashjsonapi-resource.md Example showing how to rename calculation arguments using a keyword list for specific mappings. ```elixir calculation_argument_names [ full_name: [separator: :sep] ] ``` -------------------------------- ### Generic actions with `route` Source: https://hexdocs.pm/ash_json_api/routing.md Examples of defining generic actions using the `route` helper for different HTTP methods. ```elixir route :get, "/say_hello/:name", :say_hello route :post, "/trigger_job", :trigger_job route :delete, "/cancel_job/:id", :cancel_job ``` -------------------------------- ### json_api.routes.index Source: https://hexdocs.pm/ash_json_api/dsl-ashjsonapi-domain.md A GET route to retrieve a list of records ```elixir index resource, action ``` -------------------------------- ### exception Source: https://hexdocs.pm/ash_json_api/AshJsonApi.Error.UnacceptableMediaType.md Create an `Elixir.AshJsonApi.Error.UnacceptableMediaType` without raising it. ```elixir @spec exception(opts :: Keyword.t()) :: %AshJsonApi.Error.UnacceptableMediaType{ __exception__: true, bread_crumbs: term(), class: term(), path: term(), splode: term(), stacktrace: term(), vars: term() } ``` -------------------------------- ### json_api.routes.base_route.index Source: https://hexdocs.pm/ash_json_api/dsl-ashjsonapi-domain.md A GET route to retrieve a list of records ```elixir index resource \ nil, action ``` ```elixir index :read ``` -------------------------------- ### Setting the Actor Manually Source: https://hexdocs.pm/ash_json_api/authorize-with-json-api.md Example of a plug that fetches the current user and uses Ash.PlugHelpers.set_actor/2 to set the actor in the conn. ```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 ``` -------------------------------- ### field_names with a function Source: https://hexdocs.pm/ash_json_api/dsl-ashjsonapi-resource.md Example of renaming fields using a custom function. ```elixir field_names fn name -> camelized = name |> to_string() |> Macro.camelize() {first, rest} = String.split_at(camelized, 1) String.downcase(first) <> rest end ``` -------------------------------- ### field_names :dasherize Source: https://hexdocs.pm/ash_json_api/dsl-ashjsonapi-resource.md Example of renaming fields using the :dasherize atom. ```elixir field_names :dasherize # first_name → first-name ``` -------------------------------- ### Add :open_api_spex dependency Source: https://hexdocs.pm/ash_json_api/open-api.md To set up Open API endpoints, first include the `:open_api_spex` dependency in your project. ```elixir {:open_api_spex, "~> 3.16"} ```