An Overview of RAML 1.0
With RAML 1.0, APIs are much more readable, and data types can be reused in other APIs without the need to write them again.
Join the DZone community and get the full member experience.
Join For FreeRAML, the language for modeling RESTful APIs has reached version 1.0. As we know, RAML was created to improve and enhance the way that APIs are provided.
There are several changes in this release compared to RAML 0.8:
Data types.
Examples.
Annotations.
Libraries.
Overlays and extensions.
Improved security schemes.
Here's a simple example of what a RAML 1.0 file looks like:
#%RAML 1.0
title: Brochure
version: v1
baseUri: http://localhost:8080
protocols: HTTP
mediaType: application/json
types:
ModelTree:
type: object
properties:
modelTreeReference: string
brand: string
series?: string
constructionSeries?: string
bodyType?: string
AGModelCode?: string
UKModelCode?: string
levelCode?: number
Brochure:
type: object
properties:
recordNumber: number
partNumber: number
name: string
brand: string
brochureType: string
CRMGroup: string
CRMSubGroup: string
isActiveIndicator: string
modelTree: ModelTree
Status:
type: object
properties:
responseStatus:
enum: [COMPLETE, ERROR, FATAL]
responseId: number
Transaction:
type: object
properties:
status: Status
data:
type: object
properties:
brochures?: Brochure[]
/brochures:
get:
responses:
200:
description: Status and a list of Brochures
body:
application/json:
example: {
status: {
responseStatus: 'COMPLETE',
responseId: 123
},
data: {
brochures: [{
recordNumber: 1,
partNumber: 56,
name: "Activity Brochure",
brand: "My Brand Ltd",
brochureType: "HARDCOPY",
CRMGroup: "Sales",
CRMSubGroup: "Lifestyle/Access",
isActiveIndicator: "N",
modelTree: {
modelTreeReference: "My Brand",
brand: "My Brand Ltd",
levelCode: 1
}
}
]
}
}
type: Transaction
Data types are probably the most important feature introduced in this release. Taken from object-oriented programming languages like Java, data types allow the user to define objects and reuse them at any level in a RAML file.
Taken from the previous example, ModelTree
is an example of a data type:
types:
ModelTree:
type: object
properties:
modelTreeReference: string
brand: string
series?: string
constructionSeries?: string
bodyType?: string
AGModelCode?: string
UKModelCode?: string
levelCode?: number
This data type defines multiple properties, each of which is declared as a built-in type like string
or number
.
In a RAML file, we can define simple and complex data types.
Let's have a look at the following example:
#%RAML 1.0
title: Brochure
version: v1
baseUri: http://localhost:8080
protocols: HTTP
mediaType: application/json
types:
ModelTree:
type: object
properties:
modelTreeReference: string
brand: string
series?: string
constructionSeries?: string
bodyType?: string
AGModelCode?: string
UKModelCode?: string
levelCode?: number
Brochure:
type: object
properties:
recordNumber: number
partNumber: number
name: string
brand: string
brochureType: string
CRMGroup: string
CRMSubGroup: string
isActiveIndicator: string
modelTree: ModelTree
Status:
type: object
properties:
responseStatus:
enum: [COMPLETE, ERROR, FATAL]
responseId: number
Transaction:
type: object
properties:
status: Status
data:
type: object
properties:
brochures?: Brochure[]
Some properties are defined as data types. For example, the property modelTree
in the type Brochure
is a ModelTree
data type.
According to the RAML specs, RAML types can be summarized as follows:
Types are similar to Java classes.
Multiple inheritance is allowed.
Types can be split into four families:
external
,object
,array
, andscalar
.Types can define two types of members:
properties
and facets. Both are inherited.Properties are regular object-oriented properties.
Facets are special configurations.
Only object types can declare properties. All types can declare facets.
The node types in the root of the document will start the data types declaration. Once the data type has been declared, an object type should be defined for it:
Brochure:
type: object
You can also define some facets, like in the following code, which gives an example of that data type:
Brochure:
type: object
example: {
recordNumber: 1,
partNumber: 56,
name: "Activity Brochure",
brand: "My Brand Ltd",
brochureType: "HARDCOPY",
CRMGroup: "Sales",
CRMSubGroup: "Lifestyle/Access",
isActiveIndicator: "N",
modelTree: {
modelTreeReference: "My Brand",
brand: "My Brand Ltd",
levelCode: 1
}
}
There are several available facets that depend on the chosen type. For instance, for an object type, we could have properties
, minPoperties
, maxPoperties
, additionalProperties
, discriminator
, or discriminatorValue
.
An example of the properties
facet can be declared for this data type:
Brochure:
type: object
properties:
recordNumber: number
partNumber: number
name: string
brand: string
brochureType: string
CRMGroup: string
CRMSubGroup: string
isActiveIndicator: string
modelTree: ModelTree
A property might have the required
facet, which could be declared in two ways. Like this...
Brochure:
type: object
properties:
recordNumber:
required: true
type: number
...or like this:
Brochure:
type: object
properties:
recordNumber?: number
Multiple inheritance is allowed in RAML:
types:
Person:
type: object
properties:
name: string
Employee:
type: object
properties:
employeeNr: integer
Manager:
type: [ Person, Employee ]
This means that Manager
will inherit all the restrictions from Person
and Employee
types.
In RAML, it's possible to organize APIs in a more readable way by using of libraries.
The data types can be put in a new RAML file like this:
#%RAML 1.0 Library
# this file is located at libraries/my_types.raml
types:
ModelTree:
type: object
properties:
modelTreeReference: string
brand: string
series?: string
constructionSeries?: string
bodyType?: string
AGModelCode?: string
UKModelCode?: string
levelCode?: number
Brochure:
type: object
example: {
recordNumber: 1,
partNumber: 56,
name: "Activity Brochure",
brand: "My Brand Ltd",
brochureType: "HARDCOPY",
CRMGroup: "Sales",
CRMSubGroup: "Lifestyle/Access",
isActiveIndicator: "N",
modelTree: {
modelTreeReference: "My Brand",
brand: "My Brand Ltd",
levelCode: 1
}
}
properties:
recordNumber: number
partNumber: number
name: string
brand: string
brochureType: string
CRMGroup: string
CRMSubGroup: string
isActiveIndicator: string
modelTree: ModelTree
Error:
type: object
properties:
errorCode: string
errorDescription: string
Status:
type: object
properties:
responseStatus:
enum: [COMPLETE, ERROR, FATAL]
responseId: number
Transaction:
type: object
properties:
status: Status
data:
type: object
properties:
brochures?: Brochure[]
errors?: Error[]
Pay attention to the Library
keyword in the first line. You are telling RAML that this is going to be a library file.
Then we can use the node uses
to import external libraries:
uses:
file-types: libraries\my_types.raml
This means that we are referencing my_types.raml
with the name file-types
.
Data types will be accessible using the dot notation, i.e., file-types.Transaction
.
We can also put JSON examples in external files. For instance, we might create examples for response with the 200 status code and one for 400.
examples/200.json
:
{
"status": {
"responseStatus": "COMPLETE",
"responseId": 123
},
"data": {
"brochures": [{
"recordNumber": 1,
"partNumber": 56,
"name": "Activity Brochure",
"brand": "My Brand Ltd",
"brochureType": "HARDCOPY",
"CRMGroup": "Sales",
"CRMSubGroup": "Lifestyle/Access",
"isActiveIndicator": "N",
"modelTree": {
"modelTreeReference": "My Brand",
"brand": "My Brand Ltd",
"levelCode": 1
}
}]
}
}
examples/400.json
:
{
"status": {
"responseStatus": "FATAL",
"responseId": 123
},
"data": {
"errors": [{
"errorCode": "ERROR-123",
"errorDescription": "Duplicate requestUUID"
}]
}
}
Then, we can import these examples with the !include
keyword.
Wrapping up a complete example, we would have:
#%RAML 1.0
title: Brochure
version: v1
baseUri: http://localhost:8080
protocols: HTTP
mediaType: application/json
uses:
file-types: libraries\my_types.raml
/brochures:
get:
responses:
400:
description: Status and a list of Errors
body:
application/json:
example: !include examples\400.json
type: file-types.Transaction
200:
description: Status and a list of Brochures
body:
application/json:
example: !include examples\200.json
type: file-types.Transaction
In this way, our API will be much more readable and the data types can be reused in other APIs without the need to write them again.
In the next article, we will go through resource types, annotations, and security schemes.
This guide doesn't mean to be a complete guide to RAML 1.0 — it's mostly a tutorial and an overview of what we can achieve using RAML 1.0.
Opinions expressed by DZone contributors are their own.
Comments