-
Notifications
You must be signed in to change notification settings - Fork 3
Documenting Your Service
The DropWizard RAML project uses a combination of JAX-RS + Jackson annotations with the RAML Annotations library to document your application's code base.
An example of a documented service can be found in the Example Service Project.
In conjunction with Jackson's own JSON annotations, the project also uses Morten Kjetland's Jackson JSON Schema project to provide more JSON schema documentation.
The @RamlApp
annotation is used to provide the description information for your application. This annotation needs to exist once (and once only) within the base package and sub-packages defined when the specification document gets generated.
This annotation does not need to reside on your application class and due to the size it can reach, we recommend placing it on a supporting class. You can see such usage here.
Property | Required | Default | Description |
---|---|---|---|
title | yes | The title of your application | |
description | no | The description of your application | |
protocols | yes | HTTPS |
The protocols your application can be connected on |
baseUri | yes | The base URI of the application | |
documentation | no | The collection of documentation pages defined using the @RamlDocumentation annotation |
|
security | no | The collection of security schemes your application supports using the @RamlSecurity annotation |
|
traits | no | The collection of traits your application's resource methods can inherit from |
The documentation
property on the @RamlApp
annotation can accept a list of @RamlDocumentation
annotations. This annotation provides the RAML specification with a collection of documentation pages to be referenced.
Property | Required | Description |
---|---|---|
title | yes | The title of the documentation page |
content | yes | The content of the documentation page. Can be a reference to a resource file or the content directly. |
The security
property on the @RamlApp
annotation can accept a list of @RamlSecurityScheme
annotations. This annotation provides a description of supported security schemes that your application uses.
This collection is used in combination with the @RamlSecuredBy
annotation to bind resource methods to the associated security schemes.
Property | Required | Description |
---|---|---|
key | yes | The key the security scheme will be referenced by in the @RamlSecuredBy annotation |
type | yes | The security scheme type. Must adhere to the types defined here by the RAML 1.0 specification. |
description | no | The description of the security scheme. |
describedBy | yes | The system descriptor of the security scheme's behaviour. See the @RamlDescribedBy annotation. |
oauth1Settings | yes if type is OAuth 1.0
|
The settings related to OAuth 1.0 security type |
oauth2Settings | yes if type is OAuth 2.0
|
The settings related to OAuth 2.0 security type |
The traits
property on the @RamlApp
annotation can accept a list of @RamlTrait
annotations. This annotation is used to describe traits that resource methods can inherit behaviour from.
This collection is used in combination with the @RamlIs
annotation to attach trait behaviour to resource methods.
Property | Required | Description |
---|---|---|
key | yes | The key the trait will be referenced by in the @RamlIs annotation |
usage | no | A usage description of the trait |
description | no | The description of the trait |
describedBy | yes | The system descriptor of the trait's behaviour. See the @RamlDescribedBy annotation. |
Both the @RamlSecurityScheme
and @RamlTrait
annotations to describe their request/response behaviour and properties.
Property | Required | Description |
---|---|---|
headers | no | The collection of request header parameters. Uses the @RamlParameter annotation to define the parameters. |
queryParameters | no | The collection of request query parameters. Uses the @RamlParameter annotation to define the parameters. |
responses | no | The collection of responses that can be returned. Uses the @RamlResponse annotation to define the responses. |
Any resource class or method with the @RamlIgnore
annotation will be excluded for documentation purposes.
The @RamlParameter
annotation is used to define a URI, header or query parameter as per the RAML 1.0 specifications.
Property | Required | Default | Description |
---|---|---|---|
name | yes | The name of the parameter (as it will be used in actual requests or URI templates) | |
type | yes | The type of parameter. Must adhere to the types defined here. If the parameter is an array of type, define the type here. Flagging the multiple property as true will ensure the parameter gets defined as an array of type
|
|
displayName | no | The display name of the parameter | |
description | no | The description of the parameter | |
required | no | true | The flag indicating if the parameter is compulsory or not. |
multiple | no | false | The flag indicating if the parameter is multi-value. |
allowedValues | no | The list of allowed values. If allowedValuesEnum is defined, this property is ignored. |
|
allowedValuesEnum | no | A reference to a Enum class that represents the list of allowed values. |
|
example | no | An example value of the parameter. | |
pattern | no | A regular expression pattern the parameter value must adhere to. This is ignored for non-string types. | |
minimum | no | The minimum value of the parameter (as a long ). This is ignored for non-numeric types. |
|
maximum | no | The maximum value of the parameter (as a long ). This is ignored for non-numeric types. |
The @RamlResponse
annotation is used to describe a response related to a status. This annotation is used by the @RamlDescribedBy
annotation within the security schemes and traits as well as by the @RamlResponses
annotation on a resource method. A response consists of a status code, description and collection of available body entities.
Property | Required | Description |
---|---|---|
status | yes | The status code of this response |
description | no | A description of what this response represents |
bodies | yes | A collection of @RamlBody definitions related to the response |
The @RamlBody
annotation is used to describe a body entity for a specific content type. With this annotation you specify a content type and can either reference a class type to generate schemas and examples from or directly reference resources/text for these.
Property | Required | Description |
---|---|---|
contentType | yes | The content type of the body payload |
type | no | The body class reference (either request or response type) |
schema | no | A reference to a resource file or direct text specifying the body schema. Ignored if type is defined. |
example | no | A reference to a resource file or direct text providing a body example. Ignored if type is defined. |
The generation process currently supports the following media types:
Media Type | Schema Generation | Example Generation | Notes |
---|---|---|---|
application/json | yes | yes | |
text/xml | no | yes | Currently, there is no tooling for an XSD to be easily derived from a Jackson-annotated class |
The @RamlExample
annotation can be placed on a response or request class, a static method on the afore mentioned classes or annotating a header or query parameter in a resource method.
When the annotation is attached to a class, the generation tools will use the value of that annotation to generate the example document for the API class. The value can either point at a document file on the classpath or contain a raw value.
@JsonDeserialize
@JsonIgnoreProperties(ignoreUnknown = true)
@RamlExample("apidocs/examples/book-request.json")
public class BookRequest {
// POJO code
}
If the annotation is attached to a public static, zero-argument method on a response or request class, this method will be executed to generate a serializable instance of the class.
@JsonDeserialize
@JsonIgnoreProperties(ignoreUnknown = true)
public class BookRequest {
// Stuff
@RamlExample
public static BookRequest example() {
return new BookRequest(
"Something something something dark side",
Genre.SciFi,
"2018-01-01",
1
);
}
}
When attached to a @HeaderParam
or @QueryParam
method parameter, the generator will use the value of the annotation to derive an example of that parameter type.
The @RamlSchema
annotation is used to point the generation tools at a statically-defined schema definition for a request or response class.
When this annotation is attached to the class, the generation process will use it's contents instead of trying to auto-generate it's schema documentation.
The value of this schema can either reference a documentation file on the classpath or a raw value.
If pointing at a response type, you can also specify that the type is returned in a collection by setting the isCollection
property to true.
Resources are the bread and butter of your application. This section onwards will look at how you will document resources using a combination of JAX-RS annotations and the RAML annotations project.
The generation process will assume that any class with a @Path
annotation is a base resource location unless that class has the @RamlIgnore
annotation on it.
Any resource class with a @Path
annotation also requires a @RamlResource
annotation on it.
Property | Required | Description |
---|---|---|
displayName | yes | The display name for the resource |
description | yes | A meaningful description for the resource |
If a @Path
annotation on a resource class or for any sub-resource methods includes a URI parameter in it's template, the class will also require the @RamlUriParameters
annotation, describing those path parameters for the resource and sub-resources. The parameter takes one or more @RamlParameter
annotations.
A resource class can contain sub-resources. For example, the resource could have a @Path("/authors")
annotation on it with methods within the class having their own @Path
annotations (eg. @Path("/{id}")
indicating a sub-resource path of /authors/{id}
). Because sub-resource paths can be shared across multiple methods, sub-resources need to be defined through the use of the @RamlSubResources
annotation on the resource class itself.
This annotation takes on or many @RamlSubResource
annotations.
This annotation is used to describe a single sub-resource that will be found inside the resource class.
Property | Required | Description |
---|---|---|
path | yes | The @Path annotation matching the sub resource method(s) in the resource |
description | no | A meaningful description for the sub resource |
A resource method is any method within a resource class annotated with one of the following JAX-RS annotations:
@GET
@DELETE
@POST
@PUT
@PATCH
If a method inside the resource does not have one of the above annotations or has the @RamlIgnore
annotation, it will not be included in the specification.
A meaningful description of what the method is for can be supplied via the use of the @RamlDescription
annotation on the method.
The @RamlSecuredBy
annotation can be used to bind the resource method to one or more security schemes defined by the @RamlApp.security
property.
This annotation can be used to inherit specific traits defined by the @RamlApp.traits
property.
This annotation will add a reserved trait of deprecated
to the resource method. This trait has no special features except for documentation purposes. The API docs web view will detect this trait and place a DEPRECATED
flag alongside methods that are flagged as such, making it easier to indicate to users what endpoints should not be developed against.
There are two ways to define headers and query parameters on a resource. They can be defined explicitly via the @RamlHeaders
, @RamlQueryParameters
and @RamlFormParameters
annotations. These annotations take one or many @RamlParameter
definitions.
If these annotations are used on a method, the generation process will not attempt to describe any of the respective parameter types by discovery. This means if your annotation contains a different parameter set to what is actually accepted by the resource, the difference will not be reported on.
The explicit approach is ideal if there are parameters consumed by the request through filters or manual request processing but are not explicitly parameters within the method definition of the code.
If the @RamlHeaders
, @RamlQueryParameters
and/or @RamlFormParameters
annotations are not present on a resource method, the generation process will implicitly look for parameters with the @HeaderParam
or @QueryParam
annotations.
The discovery will detect Collection
parameters and appropriately map them as array
of type
parameters, using generic declaration discovery to determine the internal type.
If the type is an Enum
, the allowed values will be defined for the parameter.
The following annotations attached to a parameter will help drive out further documentation:
Annotation | Description |
---|---|
@RamlDescription |
Adds a meaningful description to the parameter |
@RamlExample |
Provides an example value for the parameter |
@javax.validation.constraints.NotNull |
Flags the parameter as being required |
@javax.ws.rs.DefaultValue |
Sets a default value for the parameter |
@javax.validation.constraints.Pattern |
Defines a regular expression pattern the parameter must adhere to |
@javax.validation.constraints.Min |
Defines a minimum numeric value the parameter must be greater than |
@javax.validation.constraints.Max |
Defines a maximum numeric value the parameter must be less than |
Request bodies are defined via the @RamlRequests
annotation. This annotation takes one or many @RamlBody
annotations.
If no @RamlRequests
annotation is found on a method with a request parameter associated with it, a generation error will occur.
At this point in time, the generator will not auto-discover request body POJO's and generate documentation.
Documenting responses for a resource method is best achieved through the @RamlResponses
annotation, which takes one or many @RamlResponse
annotations. If however this annotation isn't present, the generation process will assume a 200 OK
response code and try to generate a response definition from a combination of then @Produces
annotation (defaulting to application/json
if not present) and the return type.
If the return type of the method is a Jackson-annotated object, then the generator will automatically create a schema for JSON payloads. If the return type has a static @RamlExample
method present, it will create an example automatically.
The @RamlResponses
annotation allows better control over defining the status codes being returned.
This library will use the Jackson jsonSchema Generator library to attempt to generate JSON schemas for your POJO request and response objects.
There are limitations to just how much this library can achieve. As a general rule of thumb, it cannot handle type switching through serializers. For example, a method signature like:
@JsonProperty("myField")
@JsonSerialize(using = ByteToStringSerializer.class)
public byte[] getMyField() {
return myField;
}
will not be seen as a string
type (assuming the serializer does something like new String(value)
), but rather an array
of items = integer
when generating the schema.
Try to keep your property types aligned with the actual types of your JSON properties to ensure schema generation is accurate as possible.
At present, it is not possible to generate XSD documents automatically from Jackson-annotated classes. You will need to use the schema
property on the @RamlBody
annotation to provide a manual XSD document.
The generation libraries are somewhat dependent on classes being serializable and traversable by Jackson. For response classes, this isn't generally a problem because the class is intrinsically designed to be serialized into a JSON representation.
But for request classes, this can become problematic as the class' primary purpose is to deserialize request payloads. This means for request classes there may be more superfluous Jackson annotations to ensure accuracy.
An example of a documented request object can be found here
If defining a schema for a class becomes too complicated or breaks functionality for the sake of documentation, then you can use the @RamlSchema
annotation to point the class at a static documentation file.