AsyncApiSpex.Channel (async_api_spex v0.2.0)

Copy Markdown View Source

A channel: a topic, exchange and routing key, subject, or any other address a message is sent to or received from.

address is nil when the address is computed at runtime and cannot be described statically; in that case parameters must be empty. messages maps a channel-local key to a message, which may be a %AsyncApiSpex.Message{}, a %AsyncApiSpex.Reference{}, or a module that exports __async_api_message__/0 (moved into components.messages by AsyncApiSpex.resolve/1).

Declaring a channel on the module that uses it

use AsyncApiSpex.Channel decorates the module that publishes to (or consumes from) a channel. It declares the channel, the broker it lives on, and the operation, so use AsyncApiSpex.Spec can assemble a document from the modules your application already has:

defmodule Shop.Kafka.OrderProducer do
  use AsyncApiSpex.Channel,
    address: "shop.orders",
    server: [id: "kafka", host: "kafka:9092", protocol: "kafka"],
    messages: [Shop.Events.OrderCreated, Shop.Events.OrderShipped],
    bindings: %{"kafka" => %{"partitions" => 12}}

  def publish(event), do: # ... produce to "shop.orders"
end

Options:

  • :address (required) — a string literal, or the literal nil when the address is computed at runtime.
  • :id — the channel id in the document; a string literal matching ~r/\A[A-Za-z0-9_-]+\z/. Defaults to :address with every other character replaced by _ ("shop.orders" becomes "shop_orders"). Required when :address is nil.
  • :server (required) — a keyword list literal with :host and :protocol and optionally :id (default: the protocol), :protocol_version, :pathname, :title, :summary, :description, :tags, :bindings. Values are evaluated when the document is built, so System.get_env/2 and Application.get_env/2 work.
  • :messages (required) — a non-empty list of modules, each using either AsyncApiSpex.Message or AsyncApiSpex.Schema. A schema module becomes a message in components.messages, named after the schema, with :content_type.
  • :action — :send (default) when this module publishes, :receive when it consumes.
  • :content_type — the content type of messages derived from schema modules. Defaults to "application/json".
  • :title, :summary, :description, :parameters, :tags, :bindings, :extensions — the same fields of the channel struct.
  • :operation — a keyword list literal of :title, :summary, :description, :tags, :bindings, :extensions for the operation.

Unknown options and invalid literals raise ArgumentError at compile time.

The module gets channel/0, returning the t/0, and __async_api_channel__/0, returning a map with the channel :id, the :server as {id, server}, the :channel, the :operation as {id, operation} (its id is "<action>-<channel id>"), and :messages, the components.messages entries derived from schema modules. Message keys on the channel are the message names with every character outside A-Za-z0-9_- replaced by _.

channel/0 alone is not a complete document fragment: a message derived from a schema module is a reference to #/components/messages/<name>, and that message is only in __async_api_channel__/0's :messages. Use AsyncApiSpex.Spec, which assembles all of it; if you build a %AsyncApiSpex.Document{} from channel/0 yourself, add :messages to components.messages, the server, and the operation too, or AsyncApiSpex.validate/1 reports the unresolved reference.

Summary

Functions

Declares the channel, its server, and its operation on the calling module.

Types

t()

@type t() :: %AsyncApiSpex.Channel{
  address: String.t() | nil,
  bindings: map() | nil,
  description: String.t() | nil,
  extensions: map(),
  messages: %{
    optional(String.t()) =>
      AsyncApiSpex.Message.t() | AsyncApiSpex.Reference.t() | module()
  },
  parameters: %{optional(String.t()) => AsyncApiSpex.Parameter.t()},
  servers: [AsyncApiSpex.Reference.t()] | nil,
  summary: String.t() | nil,
  tags: [AsyncApiSpex.Tag.t()] | nil,
  title: String.t() | nil
}

Functions

__using__(opts)

(macro)

Declares the channel, its server, and its operation on the calling module.

See the module documentation for the options.