Apiator is API Documentation Generator written in Groovy.

Apiator Logo

Follow us on GitHub

Why Apiator?

In our team we prefer to use tools that make life of developer easier. Apiator is one of them. It helps you to build entire API documentation with minimal configuration.

The motivation is to take information about API usage directly from a source code and spend as little as possible time and lines of code to describe your API.

Of course it’s difficult to predict all of the possible cases of API frameworks configuration so our second goal is high configurability. You can override or extends almost every functionality of Аpiator with help of type safe configuration code (not a configuration file)!

Getting started

Apiator is built with JDK 11 so it’s minimum required api level of source code and build tool-chain

Getting a binary

Binary artifacts are hosted on Bintray repo https://dl.bintray.com/ainrif/maven

  • group: com.ainrif.apiator

  • artifact: core-html-renderer (depends on your configuration)

  • version: version

You can use Set Me Up! guide from Bintray repo

You can use it in you gradle or maven project

Configuration

The main class of apiator is Apiator 😉 and it can be configured via ApiatorConfig

By default ApiatorConfig is set up to search for classes annotated with com.ainrif.apiator.api.annotation.Api. So you must select only type of web service provider and type of renderer, f.e.:

ApiatorConfig config = new ApiatorConfig();
config.provider = new JaxRsProvider();
config.renderer = new CoreHtmlRenderer();

String html = new Apiator(config).render();

The result string will be a html which is "all in one" document so you can save it and serve from http server as is.

Note
More examples of configuration can be found at corresponding *SmokeSpec

How to run with …​

Apiator can be used as a library in a classpath of application that you need to document. Good choice is to incorporate apiator into your build process to deliver documentation with application together.

Gradle plugin

Minimum requirement - Gradle 5.3

The Apiator Gradle plugin is published in the same repo with apiator. So you have to add it to build script classpath in root build.gradle:

buildscript {
    repositories {
        maven { url "https://dl.bintray.com/ainrif/maven" }
    }

    dependencies {
        classpath 'com.ainrif.apiator:apiator-gradle-plugin:<apiator-version>'
    }
}

apply plugin: 'com.ainrif.apiator'

After it you can configure Apiator in the required module (which classpath contains all endpoints):

apiator {
    runnerClass = 'path.to.ApiatorRunner' // (1)
}
  1. full name of the class which implements ApiatorGradleRunner and have default (or zero-arg) constructor

Class which implements ApiatorGradleRunner will created and call for documentation generation. In implemented method ApiatorGradleRunner#execute(…​) you have to configure and run Apiator.

Note
Complete configuration examples can be found at testing-gradle-plugin module in classes TestingJavaPluginApiatorConfig for Java and TestGroovyPluginApiatorConfig for Groovy

To separate the dependencies of Apiator from project dependencies the additional Gradle SourceSet can be used. apiator SourceSet have its own classpath which extends main can be configured via apiatorCompile in gradle. See the build.gradle file of testing-gradle-plugin module.

As a library

Apiator can be used as a standard library. Everything you need is to download all necessary libraries and run them in the same classpath with you endpoint classes.

Note
If you need to extend classpath at runtime you can do it with incubating functionality Apiator#setExtraClassPath(URL[]). Extra classpath will be available during scanning and javadoc parsing.

Features overview

  1. Zero additional code for basic documenting

    An annotations configuration of web-frameworks (like jax-rs or micronaut) is quite good basic description of your API. We just deliver it in a different way.

  2. Static generation (doesn’t affect you production code)

    You documentation can be generated during the build and can be deployed separately of your project. Or not (up to you)

  3. JSON representation

    All parsed API can be represented as reproducible JSON. You can store it in VCS (like git) and watch the difference between versions (go to detailed description):

  4. HTML representation

    In a few moments you API will converted into human friendly page (go to detailed description):

    main window
    Figure 1. HTML representation
  5. JavaDoc processing

    Extend you Api information with native JavaDoc support. Now you documentation is served directly from you api classes

  6. Single file HTML representation

    All images and scripts are incorporated in one file which can be open in any browser of even sent via e-mail

  7. And much more in the future :)

Understanding of changelog

The entire list of changes and feature can be found in repository

The semantics of changelog records is:

  • new : for the new features

  • fix : for fixed issues

  • update : for changes or extensions of public api and configurations

  • improvement : for internal updated and performance tweaks

User Guide

Default representation of Apiator collected data is class ApiScheme. It contains all API method (with class hierarchy) and meta information from annotations (from provider) and JavaDoc. It’s difficult to use such data in a raw view therefore there are renderers.

Let’s look at the following example (written on groovy to reduce amount of lines):

Apiator apiator = new Apiator(
    new ApiatorConfig(
            basePackage: 'com.ainrif.apiator.test.model.jaxrs.smoke',
            provider: new JaxRsProvider(),
            renderer: new CoreHtmlRenderer({
                plugins << new JaxRsCompositePlugin()
            }),
            docletConfig: new DocletConfig(includeBasePackage: 'com.ainrif')
    )
)

This code configuration uses:

  • Provider which understands jax-rs frameworks,

  • Render which produces html view for api

  • Plugin for renderer that adds special model types for jax-rs frameworks

  • Doclet support and required base package to scan.

Note
For additional configuration params you can look at configuration classes and read the doc. Available components are described in corresponding chapters of current doc.

How it works

This part contains high level description of major Apiator features and mechanics

Introspection

When Apiator starts to work it scans your source code in search of known web services configurations. The information is collected from source code like:

  • used classes in request as params

  • types of response as a return value

  • specific annotations

  • hierarchy of classes

  • JavaDoc descriptions

Such process when source code tells about itself are called introspection. In this case we don’t expect any specific information for Apiator.

There are several introspection types:

  • on classes — when Apiator retrieves information like properties (based on accessibility, i.e. on public getters, setters and fields) or templates (checking class hierarchy and generics).

  • on web service provider — if web services provider uses annotations for configuration then Apiator will use them to get info about endpoints.

  • on JavaDoc — we collect JavaDoc and attach them everywhere it is possible :)

Core annotations

Annotation can be found in module api and can be used fot providing of additional information or for the overrides.

Available annotations:

  • Api - marker is used to highlight classes to scans

  • ConcreteTypes - overrides return value from endpoint method

  • Param - set additional meta about param usage

JavaDoc support

Apiator can gather some information from your JavaDoc comments. With help of it you can provide description for your Api Contexts (classes), Endpoints (methods) and Params (method arguments).

There are two modes:

  • set paths to sources manually (the fastest one for the huge projects with a lot of source roots)

  • auto-search according to found Api classes (default, suitable for small projects with small depth of nested modules)

Providers

Providers have knowledge about web frameworks and their dsl. Providers implement WebServiceProvider and return data about methods which represent API endpoints

JaxRsProvider

JAX-RS specification describes in some details how your REST endpoints should look like. This information is stored in many annotations across your application. We just collect it together and add some data from implementation.

In some cases it’s difficult to use only JAX-RS api. F.e. when you return javax.ws.rs.core.Response as a result content can be any. To solve such cases we provide Apiator api module which can clarify implementation details.

MicronautProvider

This provider is built as integration with Micronaut Framework. Micronaut provides api and libraries to build REST-like microservices.

Currently Apiator supports only routing and API declarations built via annotations described in the documentation

Renderers

Renderers describe how does Apiator output should look. In general renderers are transformers from internal Apiator scheme to something like JSON, XML, HTML, etc.

Core JSON renderer

This renderer is a JSON representation of internal Apiator Schema. It can be used as input source data for other renderers (like HTML Renderer) or for comparison of different api versions.
The result output can be customized with Plugins

Model description

The top level of resulting JSON represents next data:

  • apiContexts - list of all contexts that were found (usually coincides with the class in java)

  • apiatorInfo - technical information about Apiator version and settings

  • clientApiInfo - additional information provided by Api creator

  • usedApiTypes - list of business domain objects

  • usedEnumerations - list of enums (sets of string constants)

JSON Representation of Api Type
Note
Api Type - the common abstraction for all the complex types (not : STRING, LONG, ARRAY…​ )
All Api Types which are used as params or return types obey the Model Type abstraction

Basic structure of Api Type includes only two fields

  • modelType - one of Model Type set

  • type - string with Api Type name (only if modelType is OBJECT)

Additional fields of Api Type are used for Templates Types (aka Java Generics)

  • basedOn - array of Templates, structure of nested objects is also Template Type

  • templateName - name of template variable used in source code

Note
Many of others Types inherit the Template type structure
Api Context
Note
JSON fields with value null are omitted in result output. They are presented in the next example only in demo purpose.
{
  "apiContexts": [
    {
      "apiEndpoints": [
        /*...*/
        {
          "description": "Method level javadoc",
          "method": "GET", // (1)
          "name": "getAuthors", // (2)
          "params": [ // (3)
            {
              "basedOn": [], // (4)
              "description": "Param level javadoc",
              "defaultValue": null,
              "httpParamType": "QUERY",
              "index": 0,
              "modelType": "STRING",
              "name": "search",
              "templateName": null,
              "type": null
            }
          ],
          "path": "/", // (5)
          "returnTypes": [{
            "basedOn": [ // (4)
              {
                "basedOn": [],
                "modelType": "OBJECT",
                "templateName": null,
                "type": "org.example.library.Author"
              }
            ],
            "modelType": "ARRAY",
            "templateName": null,
            "type": null
          }]
        },
        /*...*/
      ],
      "apiPath": "/library", // (6)
      "description": "Some info from JavaDoc",
      "name": "org.example.library.controllers.LibraryController"
    },
    /*...*/
  ]
  /*...*/
}
  1. name of HTTP method to call this endpoint

  2. handler name in a source code

  3. available parameterization for this endpoint

  4. template type information (like Generics in Java)

  5. path to endpoint related to context path (6)

  6. prefix path to the endpoint

Used Api Types and Enumerations

Example of JSON representation:

{
 "fields": [
   {
     "basedOn": [],
     "modelType": "LONG",
     "name": "id",
     "readable": true,
     "writable": false
   },
   {
     "basedOn": [],
     "modelType": "STRING",
     "name": "firstName",
     "readable": true,
     "writable": true
   },
   /*...*/
 ],
 "modelType": "OBJECT",
 "type": "org.example.library.Author"
}

readable/writable mean that server have getters / setters for those fields (or they are public in java terms)

Enumeration is kind of Api type:

{
  "modelType": "ENUMERATION",
  "type": "org.example.library.Book$Status",
  "values": [
    "PUBLISHED",
    "DRAFT",
    "REPRINT"
  ]
}

Model Type

Model Types are Apiator internal types which exists to classify every processed object

ModelType Example Description

VOID BOOLEAN BYTE INTEGER LONG FLOAT DOUBLE STRING

java.lang.Long long java.lang.String

correspond to native JDK types

DICTIONARY ARRAY SET

java.util.Map String[] java.util.Set

describe different types of collections

DATE BINARY

java.util.Date byte[] java.io.InputStream

custom types which can be represented as well known format

ENUMERATION

java.lang.Thread.State

class which describes inheritors of java.lang.Enum

OBJECT

org.UserDto (user-defined class)

this model type is used for custom classes which are exposed via API as part of interface. Such classes will be introspected recursively to determine types of their fields

ANY

java.lang.Object

this type means Apiator cannot get useful info about such class. It is type for general classes.

SYSTEM

java.lang.Class java.lang.reflect.Field

internal type. Is used to show that given class shouldn’t be introspected. If such type have appeared in you documentation in most cases it means you API exposes some language dependent internals

Plugins

Plugins are generic mechanism to extend and override Core JSON Renderer behavior.

All plugins implement CoreJsonRendererPlugin interface and can be combined in CompositePlugin for ease of use.

Note
Plugins with suffix *CompositePlugin contain all available plugins with it’s prefix . I.E.: JaxRsCompositePlugin contains JaxRsModelTypePlugin, JaxRsParamPlugin…​
ModelTypePlugin

These plugins encapsulate the logic of classes to Model Types matching. The matching goes while Model Type wouldn’t be found or plugins run out. From one plugin to another along the chain.

The ModelTypePlugin interface contains only one method returning whether ModelType or null. If plugin returns null next plugin will be used.

Note
The order of this type of Plugins is important. So non-default plugins are processed first, i.e. in LIFO order of addition

The plugins are ON by default DefaultModelTypeCompositePlugin:

  • AnyModelTypePlugin

  • CollectionsModelTypePlugin

  • BinaryModelTypePlugin

  • OldDateModelTypePlugin

  • CoreJavaModelTypePlugin

  • Jsr310ModelTypePlugin

And some custom plugins which can be used to extend amount of known types

  • JaxRsModelTypePlugin

PropertyPlugin

This type of plugin allows to customize fields representation of model objects. By default Properties are public fields and properties in terms of JavaBeans (get* & set* methods)

Available Plugins:

  • JacksonPropertyPlugin - support Jackson property annotations

ParamPlugin

ParamPlugins allows to extend information about endpoint param (like default value or optional).

Available Plugins:

  • JaxRsParamPlugin - supports @DefaultValue

Core HTML renderer

Reference HTML representation of Apiator results. This renderer produces the most complete graphic interface according to core model. Html Render extends configuration from Json Renderer with path to output file.

Interface description

interface description
  1. Fuzzy search

  2. List of Endpoints

  3. Menu with used Api Types

  4. Card of Endpoint (detailed view)

Card of Endpoint

Show generic information about http endpoint and provides navigation links

endpoint card
Card of Api Type

Describes model fields and types in terms of Model Type

api type card

Development Guide

Requirements:

  • Gradle 5.3 to build apiator plugin

  • JDK 11 to build and test all Apiator modules

  • Node.js 10 to develop Core Html Renderer

Core HTML renderer

The package.json is located in source root of html renderer view - renderer/core-html-renderer/src/main/node. To run dev version on http://localhost:1234 execute next commands:

; npm i
; npm run dev

Html renderer is based on Json Render so there is a prepared dataset (json) which represents all features available in Apiator. It’s located at renderer/core-html-renderer/src/main/node/apiator/js/apiatorJsonStub.js and is used by default in dev mode. There is a task from root gradle project to regenerate this json:

; # use wrapper version according to your OS
; ./gradlew generate_stub

The generated stub can be committed into the repo as is without additional formating to keep history of changes.