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

Github: https://github.com/mbuhot/open_api_spex
Docs: https://hexdocs.pm/open_api_spex/
Hex: https://hex.pm/packages/open_api_spex

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
    %Operation{
      tags: ["users"],
      summary: "Show user",
      description: "Show a user by ID",
      operationId: "UserController.show",
      parameters: [
        Operation.parameter(:id, :path, :integer, "User ID", example: 123)
      ],
      responses: %{
        200 => Operation.response("User", "application/json", UserResponse)
      }
    }
  end
  def show(conn, %{"id" => id}) do
    {:ok, user} = MyApp.Users.find_by_id(id)
    json(conn, 200, user)
  end

Cast and validate params:

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

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

  def create_operation do
    import Operation
    %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)
      }
    }
  end

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

Version 2.3.0 released.
Now supports validating enum string types.

2 Likes

Hi,

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:

Highlights:

  • 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.

7 Likes

Version 3.4.0 released.

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

Highlights:

  • 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
4 Likes

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.

6 Likes

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)
5 Likes

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.

https://swagger.io/docs/specification/authentication/

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: https://github.com/open-api-spex/open_api_spex/pull/215

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)
4 Likes

Hello,

I am wondering if it is possible to create a flag that uses the supportedSubmitMethods on the network configuration of SwaggerUI (https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/configuration.md#user-content-supportedsubmitmethods) 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 README.md 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:

4 Likes