PhoenixSwagger

repository·master·Indexed 20 days ago

https://github.com/xerions/phoenix_swagger

A library for the Phoenix web framework that provides automatic Swagger API specification generation, interactive Swagger UI serving, and schema-based request and response validation. It includes a DSL for defining OpenAPI specifications within controllers and specialized helpers for constructing JSON:API compliant schemas via the PhoenixSwagger.JsonApi module.

Tokens
12.9K
Snippets
47
Records
58
Agent score
22%

What's inside phoenix_swagger

  1. Overview of PhoenixSwagger features

    master

    PhoenixSwagger is a library designed to integrate Swagger capabilities into the Phoenix web framework. Its core functionalities include:

    • API Specification Generation: Automatically generate a Swagger API specification derived from your Phoenix router and controllers.
    • Swagger UI: Serve the Swagger UI interface to interactively explore and test your API.
    • Request Validation: Validate incoming requests against defined parameter schemas.
    • Response Validation: Validate API responses against schemas during your test suites.
  2. How the Swagger host is determined from the Endpoint

    master

    The host value in your generated Swagger file is derived from your Phoenix Endpoint url configuration.

    If your host is configured dynamically (using {:systems, "VAR"} or the :load_from_system_env flag), PhoenixSwagger will omit the host field from the generated JSON. In this case, SwaggerUI will default to using the same host that is serving the swagger file itself.

    # config.exs
    config :my_app, MyApp.Web.Endpoint,
      url: [host: "localhost"] # Results in "host": "localhost:4000" in swagger
    
    # prod.exs
    config :my_app, MyApp.Web.Endpoint,
      load_from_system_env: true, # host will be omitted from swagger
      url: [host: "example.com", port: 80]
  3. Install and configure PhoenixSwagger

    master

    To use PhoenixSwagger in your Phoenix application, follow the official getting started guide. The library provides integration for generating Swagger API specifications from Phoenix routers and controllers, serving Swagger UI, validating requests against parameter schemas, and validating responses against schemas in tests.

    # Refer to the getting started guide for specific installation steps:
    # https://hexdocs.pm/phoenix_swagger/getting-started.html
  4. Define Swagger schemas in Phoenix controllers

    master

    To expose schema definitions for your API, implement a swagger_definitions/0 function within your controller module. This function must return a map where keys are the schema names and values are the schema definitions. The structure of the returned map should follow the standard Swagger definitionsObject format.

    Use the swagger_schema/2 macro combined with functions from the PhoenixSwagger.Schema module to construct these definitions declaratively.

    def swagger_definitions do
      %{
        User: swagger_schema do
          title "User"
          description "A user of the application"
          properties do
            name :string, "Users name", required: true
            id :string, "Unique identifier", required: true
            address :string, "Home address"
            preferences (Schema.new do
              properties do
                subscribe_to_mailing_list :boolean, "mailing list subscription", default: true
                send_special_offers :boolean, "special offers list subscription", default: true
              end
            end)
          end
          example %{
            name: "Joe",
            id: "123",
            address: "742 Evergreen Terrace"
          }
        end,
        Users: swagger_schema do
          title "Users"
          description "A collection of Users"
          type :array
          items Schema.ref(:User)
        end
      }
    end
  5. Enable live reloading for Swagger files and controllers

    master

    You can configure phoenix_swagger to automatically regenerate Swagger JSON files and reload the Swagger UI whenever your controller files change.

    To enable this, follow these three steps:

    1. Ensure :phoenix_swagger is included in your mix.exs file as a compiler.
    2. Update your endpoint configuration to include the paths to your Swagger JSON files and controllers in the live_reload: [patterns: [...]] list.
    3. Add :phoenix_swagger to the reloadable_compilers list in your endpoint configuration.
    config :your_app, YourApp.Endpoint,
      live_reload: [
        patterns: [
          ~r{priv/static/.*(js|css|png|jpeg|jpg|gif|svg|json)$},
          ~r{priv/gettext/.*(po)$},
          ~r{lib/your_app_web/views/.*(ex)$},
          ~r{lib/your_app_web/controllers/.*(ex)$},
          ~r{lib/your_app_web/templates/.*(eex)$}
        ]
      ],
      reloadable_compilers: [:gettext, :phoenix, :elixir, :phoenix_swagger]
  6. Use `PhoenixSwagger.Plug.Validate` for automatic controller validation

    master

    To automatically validate input parameters for all routes within a pipeline, add PhoenixSwagger.Plug.Validate to your Phoenix router pipeline.

    Behavior

    • On Success: The request proceeds to the controller.
    • On Failure: The Plug halts the connection and returns a 400 status code (configurable) with a JSON error body containing the path and message.
    • Skipping Validation: If you need to bypass validation for a specific request, set conn.private[:phoenix_swagger][:valid] to true before the Plug is reached.

    Configuration

    • Use the :validation_failed_status parameter to change the HTTP status code returned on validation errors.
    pipeline :api do
      plug :accepts, ["json"]
      plug PhoenixSwagger.Plug.Validate
    end
    
    scope "/api", MyApp do
      pipe_through :api
      post "/users", UsersController, :send
    end
  7. Generate Swagger specifications with `swagger_path/2`

    master

    Use the swagger_path/2 macro within a Phoenix controller to generate a Swagger specification for a specific action. The macro requires the name of the controller action and a do block containing the Swagger DSL.

    Parameters:

    1. Action Name: The atom representing the controller action (e.g., :index).
    2. DSL Block: A block using PhoenixSwagger.Path functions to define the endpoint's metadata, parameters, and responses.

    Note: The PhoenixSwagger.Path.delete/2 function may clash with your controller's own delete/2 function. If you need to customize the route for Swagger, use a qualified function call to avoid name collisions.

    use PhoenixSwagger
    
    swagger_path :index do
      get "/posts"
      description "List blog posts"
      response 200, "Success"
    end
    
    def index(conn, _params) do
      posts = Repo.all(Post)
      render(conn, "index.json", posts: posts)
    end
  8. Generate a swagger file

    master

    To generate a Swagger specification file, configure the :phoenix_swagger key in your application configuration. Map the desired output path in priv/static to the router responsible for the API.

    Example configuration:

    config :my_app, :phoenix_swagger,
      swagger_files: %{
        "priv/static/swagger.json" => [router: MyAppWeb.Router]
      }

    After configuring, run the following Mix task to generate the file:

    mix phx.swagger.generate
    config :my_app, :phoenix_swagger,
      swagger_files: %{
        "priv/static/swagger.json" => [router: MyAppWeb.Router]
      }
    mix phx.swagger.generate
  9. Reuse swagger parameters by extracting them into modules

    master

    The swagger_path macro in PhoenixSwagger is syntactic sugar over Elixir functions. You can extract common parameters (like headers or query params) into a separate module to avoid duplication across multiple controllers.

    To do this, create functions in a helper module that accept a %PhoenixSwagger.Path.PathObject{} as their first argument and return an updated %PathObject{}. You can then call these functions directly inside the swagger_path block.

    defmodule CommonParameters do
      alias PhoenixSwagger.Path.PathObject
      import PhoenixSwagger.Path
    
      def authorization(path = %PathObject{}) do
        path |> parameter("Authorization", :header, :string, "OAuth2 access token", required: true)
      end
    
      def sorting(path = %PathObject{}) do
        path
        |> parameter(:sort_by, :query, :string, "The property to sort by")
        |> parameter(:sort_direction, :query, :string, "The sort direction", enum: [:asc, :desc], default: :asc)
      end
    end
  10. Configure Swagger properties for schema validation

    master

    To enable effective validation using PhoenixSwagger.SchemaTest, you must explicitly mark properties as required in your swagger definitions using the required: true option. If properties are not marked as required, the schema validator may not correctly enforce their presence in controller responses.

      properties do
        id(:integer, "User ID")
        name(:string, "User name", required: true)
        email(:string, "Email address", format: :email, required: true)
        inserted_at(:string, "Creation timestamp", format: :datetime)
        updated_at(:string, "Update timestamp", format: :datetime)
      end
  11. Run the simple phoenix_swagger demo app

    master

    To see phoenix_swagger in action using the provided simple demo application, follow these steps to install dependencies, set up the database, compile the source (which triggers swagger generation), and start the server.

    1. Install dependencies: mix deps.get
    2. Create the database: mix ecto.setup
    3. Compile source and generate swagger: mix compile
    4. Start the Phoenix server: mix phx.server
    5. Access the Swagger UI: Open your browser and navigate to http://localhost:4000/api/swagger/.
    mix deps.get
    mix ecto.setup
    mix compile
    mix phx.server
  12. Install PhoenixSwagger

    master

    To install PhoenixSwagger, add it to your mix.exs dependencies. You may also optionally add ex_json_schema if you require the schema validation plug and test helpers.

    To ensure swagger files are automatically updated every time your application is compiled, append :phoenix_swagger to your project's compilers list.

    # mix.exs
    
    def deps do
      [
        {:phoenix_swagger, "~> 0.8"},
        {:ex_json_schema, "~> 0.5"} # optional
      ]
    end
    
    def project do
      [
        # ...
        compilers: [:phoenix, :gettext] ++ Mix.compilers ++ [:phoenix_swagger],
        # ...
      ]
    end