OpenApiSpex - OpenAPI / Swagger 3.0 for Plug APIs

Leverage Open Api 3.0 (Swagger) to document, test, validate and explore your Plug and Phoenix APIs.

  • Generate and serve a JSON Open API (swagger) document from your code
  • Use the spec to cast request params to well defined schema structs
  • Validate params against schemas, eliminate bad requests before they hit your controllers
  • Validate responses against schemas in tests, ensuring your docs are accurate and reliable
  • Explore the API interactively with with SwaggerUI


Integrating with phoenix controllers:

  @spec open_api_operation(atom) :: Operation.t
  def open_api_operation(action), do: apply(__MODULE__, :"#{action}_operation", [])

  @spec show_operation() :: Operation.t
  def show_operation() do
      tags: ["users"],
      summary: "Show user",
      description: "Show a user by ID",
      operationId: "",
      parameters: [
        Operation.parameter(:id, :path, :integer, "User ID", example: 123)
      responses: %{
        200 => Operation.response("User", "application/json", UserResponse)
  def show(conn, %{"id" => id}) do
    {:ok, user} = MyApp.Users.find_by_id(id)
    json(conn, 200, user)

Cast and validate params:

  plug OpenApiSpex.Plug.Cast
  plug OpenApiSpex.Plug.Validate

  def open_api_operation(action) do
    apply(__MODULE__, :"#{action}_operation", [])

  def create_operation do
    import Operation
      tags: ["users"],
      summary: "Create user",
      description: "Create a user",
      operationId: "UserController.create",
      parameters: [],
      requestBody: request_body("The user attributes", "application/json", UserRequest),
      responses: %{
        201 => response("User", "application/json", UserResponse)

  def create(conn, request = %UserRequest{user: %User{name: name, email: email, birthday: birthday = %Date{}}}) do

Version 2.3.0 released.
Now supports validating enum string types.



Is there way to keep specs in a separate files?

@lessless can you elaborate on what you’re looking for?

OpenApiSpex doesn’t support reading external JSON/YAML files, but there is some flexibility in organizing the Elixir code.

Plug application example clarified it. I thought about extracting specs in separate .ex files and importing them later on, but having a module per http action is even better.

1 Like

Version 3.2.0 released.

Lots of internal improvements and some new features thanks to the wonderful contributors, particularly @moxley and the team at Ghost Group / Weedmaps. :heart:


  • Jason library support for JSON serialization
  • Improved memory usage
  • Improved error messages and validations
  • Integrate SwaggerUI with Plug.CSRFProtection

See the changelog for more details.


Version 3.4.0 released.

This version is required when using Phoenix 1.4.7+ and the OpenApiSpex.Paths.from_router/1 function.


  • Open API extensions can be added to the OpenApi document and the Info structs
  • Server.from_endpoint now uses the Phoenix API instead of the endpoint config to determine the URL
  • Compatibility with Phoenix 1.4.7 Router modules

amazing lib! thanks @mbuhot!
I loved the idea that the controller tests are guaranteeing the API protocol, so when our mobile/web devs (or us) access the swaggerui, they will see a guaranteed documentation

1 Like

In the example the api data is returned by show_operation which is just a function, so you can pull the %Operation{} data from anywhere.

1 Like

Version 3.5.0 is released!

This version has a lot of changes from the last several months. Highlights:

  • Ability to import Open API documents into OpenApiSpex, as an alternative to defining specs using using OpenApiSpex’ Elixir syntax.
  • Experimental support for ExDoc-based operation specs. Use doc tags in your controller to define operations instead of defining callback functions.
  • Improved Open API compliance and bug fixes for casting and validations
  • Deprecate the legacy cast & validate implementation for the newer Cast module.

Thank you to @mbuhot for letting me manage the release.


Version 3.6.0 is released!

This release include some enhancements and important bug fixes:

  • Feature: Improved inspect output of %Schema{} (#193)
  • Feature: Auto-populate schema title from module name (#192)
  • Feature: Derive Operation ID from meta in ExDoc specs (#195)
  • Fix: Validation of array minItems ignores empty array (#179)
  • Fix: Add minimum/maximum validation for number properties (#181)
  • Fix: Properly validate header params (#184)
  • Fix: Support free-form query parameters (#171)
  • Fix: Resolve schema modules from Response in Components (#186)

Is there an example for setting up authentication in the operations? I didn’t find in the example app. Thanks.

1 Like

Sorry no sample code for security yet, a PR to the example app would be most welcome!

It should be a matter of declaring the securitySchemes within the components section of your API spec, then referencing the schemes by name within each Operation.

Are you using something simple like API keys or more complex like OpenIdConnect?

1 Like

Thanks for getting back. to me, I am using simple authorization with a bearer token, the same level of simplicity of API key. I got that working and I can open a PR with some documentation updates to guide other users as the example app does not require authorization.

PR with readme updates:

Version 3.7.0 is released!

This release include some enhancements and important bug fixes:

  • Enhancement: Multiple bug fixes and edge case handling of ExDoc based operation specs
  • Enhancement: Upgrade Swagger UI to 3.24.2 (#210)
  • Enhancement: Improve oneOf casting (#227)
  • Docs: Add SecurityScheme usage and examples in the readme (#215)
  • Fix: References for query params and discriminators with mappings not working (#200)
  • Fix: Errors in parameter pattern validation (#206)
  • Fix example (#212)
  • Fix: CastAndValidate: incorrect content-type handling (#218)
  • Fix: Can’t cast and validate a JSON array as request body (#229)


I am wondering if it is possible to create a flag that uses the supportedSubmitMethods on the network configuration of SwaggerUI ( to disable the Try it Out feature for certain methods?

Great product btw!

I think we can add support for the configUrl option, allowing users to have a JSON file in priv/static that can be used to configure most of the swaggerUI options with needing to add flags in OpenApiSpex.

Interested in sending a PR? There’s a similar feature in the PhoenixSwagger SwaggerUI Plug that can be used for reference :slightly_smiling_face:

Thank you!

Version 3.8.0 is released!

This release comes with a couple of new features alongs with lots of enhancements and fixes:

  • Feature: Custom validators (#243)
  • Feature: Swagger json generation Mix Task (#249)
  • Feature: Customizable cache adapter (#262)
  • Enhancement: Allow passsing false to @doc annotation to skip the warning. (#236)
  • Enhancement: Make @doc parameters declaration consistent with open api (#237)
  • Enhancement: Support security @doc string attribute on operations (#251)
  • Enhancement: Allow a Reference to be used for directly in the parameters definition (#258)
  • Enhancement: Allow a Reference to be used for an Operation’s request body (#260)
  • Docs: Fixes responses example typo “unprocessible” (#248)
  • Docs: Fix security example to use correct types for the keys (#239)
  • Fix: Remove default pop value for :type shortcut in @doc specs (#238)
  • Fix: Nested parameters when served from file based schema (#241)
  • Fix: Error handling for oneOf (#246)
  • Fix: json:api compatible data shape option for JsonRenderError (#245)
  • Fix: ReferenceError: components.parameter missing s in CastParamters (#257)
  • Fix: struct def for custom validators (#263)

As always, a huge thank you to all the contributors and maintainers for keeping the project going :heart: