Groovy REST Doc helps you to document REST APis. It helps you generate Asciidoc snippets to document your API by using an Groovy DSL.

Installation

Add a new Maven Url entry to your dependencies block:

repositories {
    maven { url 'http://dl.bintray.com/sdelamo/libs' }
}

Add a Gradle dependency:

testCompile 'org.grails:rest-doc:0.2'

Usage

In order to document your REST endpoint you need to:

  • Declare your endpoints using classes extending org.grails.restdoc.RestEndpoint

  • Use those endpoint declarations in your functional tests. While you test your API, you generate documenation.

The next code snipeets display Grails 3 functional tests. However, You can use groovy-rest-doc with any framework.

The first step is to create classes to describe the endpoint under test. Extend org.grails.restdoc.RestEndpoint

package demo

import groovy.transform.CompileStatic
import org.grails.restdoc.HeaderDoc
import org.grails.restdoc.HttpVerb
import org.grails.restdoc.ParamDoc
import org.grails.restdoc.ParamType
import org.grails.restdoc.RestEndpoint

@CompileStatic
class ApiLoginEndpoint extends RestEndpoint {
    List<String> authorizationRoles = []
    HttpVerb httpVerb = HttpVerb.POST
    String path = '/api/login'
    List<HeaderDoc> headers = [
                HeaderDoc.builder()
                        .name('Accept')
                        .value('application/json')
                        .build(),
                HeaderDoc.builder()
                        .name('Content-Type')
                        .value('application/json')
                        .build()
        ]

    List<ParamDoc> params = [
                ParamDoc.builder()
                        .name('username')
                        .type(ParamType.JSON)
                        .required(true)
                        .schema(String.simpleName)
                        .build(),

                ParamDoc.builder()
                        .name('password')
                        .type(ParamType.JSON)
                        .required(true)
                        .schema(String.simpleName)
                        .description('Plain text password')
                        .build(),
        ]
}

Then, you instantiate RestDoc and call the doc method as illustrated in the next Grails 3 functional test.

package demo

import grails.plugins.rest.client.RestBuilder
import grails.testing.mixin.integration.Integration
import groovy.json.JsonOutput
import org.grails.restdoc.RestDoc
import spock.lang.Shared
import spock.lang.Specification
import spock.lang.Subject

@Integration
class ApiLoginSpec extends Specification {

    @Shared
    @Subject
    ApiLoginEndpoint endpoint = new ApiLoginEndpoint()

    def "test login"() {
        given:
        RestBuilder rest = new RestBuilder()

        when: 'login with valid credentials'
        Map m = [username: 'sherlock', password: 'elementary']
        def resp = rest.post("http://localhost:${serverPort}${endpoint.path}") {
            accept(endpoint.accept())
            contentType(endpoint.contentType())
            json JsonOutput.toJson(m)
        }

        then: 'server returns access token and roles'
        resp.status == 200
        resp.json.roles.find { it == 'ROLE_BOSS' }
        resp.json.access_token
        resp.json.refresh_token

        when:
        def accessToken = resp.json.access_token

        then:
        accessToken

        when:
        new RestDoc(endpoint).doc {
            sample {
                description 'Successful login'
                request {
                    headers endpoint.headersMap
                    jsonBody JsonOutput.toJson(m)
                }
                response {
                    statusCode resp.status
                    json resp.json.toString()
                }
            }
        }

        then:
        noExceptionThrown()

        when: 'login with wrong password'
        m = [username: 'sherlock', password: 'wrongpassword']
        resp = rest.post("http://localhost:${serverPort}${endpoint.path}") {
            accept(endpoint.accept())
            contentType(endpoint.contentType())
            json JsonOutput.toJson(m)
        }

        then: 'server returns unauthorized'
        resp.status == 401

        when:
        new RestDoc(endpoint).doc {
            sample {
                description 'login with wrong password, server returns unauthorized'
                request {
                    headers endpoint.headersMap
                    jsonBody JsonOutput.toJson(m)
                }
                response {
                    statusCode resp.status
                }
            }
        }

        then:
        noExceptionThrown()
    }

}

For any endpoint understand you can document different interactions ( successful calls, calls returning errors).

When you run your tests, Asciidoc snippets which describe your API are generated at src/docs/asciidoc/generated.

The file src/docs/asciidoc/generated/index.adoc lists every endpoint documented in your tests.

You can change the folder where the snippets get generated at:

RestDoc restDoc = new RestDoc(endpoint)
restDoc.generatedSnippetsPath = 'build/generated'
restDoc.doc {
...
..
.
}

Sample API Documentation

Using the asciidoctor gradle plugin[Asciidoctor Gradle plugin] is easy to transform the generated API into Documentation in HTML5, PDF or epub.