Skip to content

Self Documentation

Spider-Gazelle has the ability to ouput OpenAPI descriptions of the routes defined in your service.

Output#

The source code is required to output OpenAPI as we extract descriptions from regular comments. The simplest way to generate the OpenAPI YAML is to:

  1. build the application shards build
  2. generate the OpenAPI output ./bin/app --docs
  3. If you would like a file then run ./bin/app --docs > ./bin/description.yml

You can then serve this document from your service when it's deployed if desirable.

class OpenAPI < AC::Base
  base "/openapi"

  DOCS = ActionController::OpenAPI.generate_open_api_docs(
    title: "Application",
    version: "0.0.1",
    description: "App description for OpenAPI docs"
  ).to_yaml

  get "/docs" do
    render yaml: DOCS
  end  
end

then visit your documentation at "http://localhost:3000/openapi/docs"

Optimal results#

For optimal output it's recommended that you:

  • decorate your route functions with return types (assumes no body if not decorated)
  • decorate your models to improve JSON schema
class Comments < Application
  base "/comments"

  # description of your model that will be used in the OpenAPI output
  class Comment
    include JSON::Serializable

    # add format information to the output schema
    @[JSON::Field(format: "email")]
    property reply_to : String
    property user_id : Int64
    property text : String
  end

  # This is a route summary
  @[AC::Route::GET("/:comment_id")]
  def show(comment_id : Int64) : Comment
    Comment.find(comment_id)
  end
end

Route descriptions#

Summary and descriptions are extracted from the comments above the function that represents the route.

  • the first line of the comment is used as a summary
  • if there are multiple lines then all the lines are used as a description
class Comments < Application
  base "/comments"

  # This is a route summary
  @[AC::Route::GET("/")]
  def index; end

  # This is a route summary
  # This is a route description
  # and the description continued
  @[AC::Route::POST("/")]
  def create; end
end

Schema descriptions#

JSON schema is automatically extracted for all the types being serialised / deserialised including:

  • Parameters (route and query)
  • Request bodies
  • Response bodies

For JSON::Serializable types you can include additional information.

class Comment
  include JSON::Serializable

  # add format information to the output schema
  @[JSON::Field(format: "email")]
  property reply_to : String
  property user_id : Int64

  @[JSON::Field(format: "email")]
  property text : String

  # The `EpochConverter` here means the JSON value will actually be an integer
  # to avoid the schema output being `type: "string", format: "date-time"` you can
  # supply a type override and custom format string.
  @[JSON::Field(converter: Time::EpochConverter, type: "integer", format: "Int64")]
  getter time : Time
end

Some of the @[JSON::Field] annotations you can use are:

  • type
  • format
  • pattern
  • min_length
  • max_length
  • multiple_of
  • minimum
  • exclusive_minimum
  • maximum
  • exclusive_maximum

as per the JSON Schema spec

Custom types#

If your model doesn't use JSON::Serializable and instead is using a custom serializer then you can implment def self.json_schema(openapi : Bool? = nil) to return a NamedTuple with the JSON Schema representation of your model.