RESTful API Modeling Language more commonly known as RAML has been around for quite some time now (more than 4 years). As its name suggests, it is an API Modeling language used by plenty of developers to design their APIs from scratch. It offers features like reusable libraries, traits, etc. that are not yet available in other popular API description formats.
In this blog, I will highlight some of the frequently seen mistakes in RAML files (for both versions 0.8
and 1.0
). If you have read my previous blog about the common mistakes developers make in their OpenAPI 3 files, you may notice some similarities which is to do with the fact that these API description formats, although serving their own distinct purposes, have a lot in common.
Trying to Reference Components That Don’t Exist
The biggest portion of the RAML failures associated with developer mistakes are ones in which certain components are referenced but these references fail to get resolved. Common causes are discussed below:
Externally referenced files not provided
RAML allows developers to split their API description file into multiple files and reference the components across these files using the !include
tag. Depending on the size of the API, a RAML file is usually split into a large number of files e.g. the main RAML file, schema files, schema JSON example files, etc.
Plenty of developers upload only their main RAML file but do not provide the other referenced files. In general, a ZIP is required or a base URL from which relative files can be loaded. Sometimes even when these are provided, the failures can still occur if there are files referenced that are not present in the uploaded ZIP file or could not be loaded relatively from the URL. Our Transformer tool performs validation of URLs/ZIP files to help indicate any such missing files. Keep an eye out for the warnings when performing your conversion to avoid failures due to missing files.
Incorrect paths/Invalid file names
Some common scenarios observed where developers face conversion failures in such cases is when:
- The file they are trying to reference (e.g.
IAmAFile.raml
) exists with a different name (e.g.IAmAFile_Version2.raml
). - The file exists in a different directory (e.g.
Directory1/IAmAFile.raml
) to the one in which they are trying to locate the file (e.g.Directory2/IAmAFile.raml
). - The file path is a URL like http://example.com/files/IAmAFile.raml but the URL is either broken/not publicly accessible.
RAML components (Types, Resource Types, Traits, etc.) referenced but not defined
As discussed previously, RAML processing generally involves plenty of files. Developers bring in files that reference a component (like a type definition, resource type, or a trait) in another file (e.g. a library) but the component is not defined in that file. It is possible that the component exists with a slightly different name or is located in some other file. This issue can occur in a single-file RAML as well.
#%RAML 1.0
title: Hello world
mediaType: application/json
/helloworld:
post:
body:
type: HelloMessage
In the above example, the request body of the POST
method references type HelloMessage
but this type is not declared anywhere. Since it is not a RAML primitive type, it MUST be declared under the types
section as follows:
#%RAML 1.0
title: Hello world
mediaType: application/json
types:
HelloMessage:
/helloworld:
post:
body:
type: HelloMessage
Similarly, if a library type is referenced the developer needs to ensure that the definition for the type resides in that library.
You can’t reference a RAML type in a JSON Schema
A very interesting mistake noted in RAML 1.0
files was that several developers try referencing RAML types from within a JSON schema definition e.g. in the following example the body schema contains a property input
that tries referencing a RAML type HelloMessage
(defined using RAML types
component).
#%RAML 1.0
title: Hello world
mediaType: application/json
types:
HelloMessage:
properties:
message: string
/helloworld:
post:
body:
type: |
{
"$schema": "http://json-schema.org/draft-04/schema",
"properties": {
"input": {
"type": "HelloMessage"
}
},
"type": "object"
}
This is invalid as a JSON schema definition is completely independent of the RAML specification and any types that need to be used must be defined in the root definitions
of the schema itself.
Invalid YAML Means Invalid RAML
RAML uses YAML as its underlying format. So a RAML file has to abide by the rules set by both YAML and RAML specifications. A large number of developers upload files with invalid YAML content. Some of the common causes are discussed below.
Using tab spacing which is not allowed
That is correct. YAML does not allow tabs but a lot of developers still use it for the indentation of their RAML files.
Treating YAML as case-insensitive
YAML is case-sensitive. Developers try referencing types named IAmAType
as iamatype
which is invalid as they both are different.
Missing space between property key and value
When defining a property, YAML requires that there be a space between the property key and the value. Developers still try and define the property like:
property1:propertyValue
This is invalid as the correct way is:
property1: propertyValue
Improper nesting
Every nested item must be indented with two spaces inside the parent one e.g. a property property2 nested inside property1 must be declared as follows:
property1:
property2:
This is not followed by most of the developers.
Unescaped strings
A lot of developers forget to escape strings that contain reserved characters e.g. the following is invalid as the description field containing the reserved character :
is not escaped properly.
/helloworld:
post:
body:
description: Testing: 123
The description must be escaped using quotes as follows:
/helloworld:
post:
body:
description: 'Testing: 123'
Incorrect Usage of RAML Libraries
RAML introduced its users to libraries in version 1.0
. Developers make certain mistakes when applying these libraries.
Declaring library content inline
A library must be defined in a RAML fragment file which is separate from the files that will reference it. The file referencing it (a master RAML file or some other fragment file) must use the
uses:
file-type: file-type.raml
property to specify a name and path to the library as shown below:
uses:
file-type: file-type.raml
However, it is seen that a lot of developers try and define the library inline where otherwise a library path is expected:
uses:
file-type:
types:
File:
This is invalid and likely to cause failures.
Using !include to load the libraries
Since all external files are referenced in RAML by adding the !include
tag before the path, it is a common mistake to do the same for when loading external libraries. This is, therefore, invalid:
uses:
file-type: !include file-type.raml
The !include
tag is not applicable for applying libraries. Instead, the library path must be specified directly as follows:
uses:
file-type: file-type.raml
Composition of Library Namespaces
RAML does not allow the composition of namespaces using .
across multiple libraries. Developers try to reference types across multiple libraries (files, file-type) as follows which is invalid:
type: files.file-type.File
Trouble Caused by a Missing Colon ‘:’
So small and insignificant it is and yet, surprisingly, one of the reasons behind so many failures that developers make. When defining response bodies plenty of developers specify it as follows:
responses:
200:
body:
application/json
Do you see the missing colon at the end of application/json
? It is what changes the meaning of the whole definition because it implies that the response body is of type application/json
i.e. application/json
is treated as a string value. Since the types defined in your file will definitely not contain a type named application/json
, the file throws an error and fails to convert. To give this value back its original role as a media type/content type name you need to restore the colon as follows:
responses:
200:
body:
application/json:
Now it’s a media type with an empty type declaration which is allowed and won’t cause errors.
Missing/Invalid Required RAML Version Comment Line
Relatively less frequent but common, nevertheless, are the issues that developers face when trying to convert their RAML files that do not start with the YAML comment indicating the RAML version. RAML specifications declares them mandatory for both RAML 0.8 and RAML 1.0.
For RAML 0.8
, it is specified as:
#%RAML 0.8
For RAML 1.0
, it is specified as:
#%RAML 1.0
These comment lines are important because they help us distinguish your RAML files from any other YAML files. Also, any other versions specified (like 2.0
, 3.0
) are invalid because the only available versions are 0.8
and 1.0
. This is, therefore, incorrect:
#%RAML 3.0
Need Array Parameters? Choose RAML 1.0 not 0.8
The support for array parameters is available for only request/response body definitions through JSON schema specification. For all other cases (query, header, form or URI parameters) the only available types are: string
, number
, integer
, file
, date
and boolean
. A lot of developers try to use array
type for their query parameters which is not supported and in such cases, it is recommended to use RAML 1.0
which has full support for array parameters.
Incorrect Usage of Primitive Types Available
- The
null
type is available asnil
in RAML 1.0. A lot of developers still try to usenull
instead. - The primitive date type available in RAML 0.8 is
date
while RAML 1.0 offers multiple primitive date types:date-only
,time-only
,datetime-only
,datetime
. Developers tend to confuse both and try usingdate
in RAML1.0
anddate-only
in RAML 0.8. - Floating-point numbers are defined by setting
type
tonumber
andformat
tofloat
. Developers, however, sometimes try to set type asfloat
directly which is invalid.
Nonconformance to RAML Specification
Failing to follow the RAML specification in any way may result in failures when using any tool. A property stated to be an object but declared as an array can cause failures. Common mistakes that fall in this category are listed below:
- The specification for RAML 0.8 states that the
protocols
property MUST be an array of strings. A lot of developers still declare it as a simple string. Similarly, the specification for RAML 1.0 declares propertyscopes
as a list of strings and yet plenty of developers declare it as a simple string. - RAML
0.8
allows named parameters to have multiple types that can be specified as follows:
file:
- type: string
- type: file
Developers sometimes make the mistake of declaring property type
as an array instead which is invalid e.g.
file:
type:
- string
- file
Conclusion
RAML is a format that comes bundled with plenty of features and with a large feature set comes more complexity. It is very important that the specification documents are detailed, try to cover all cases, and are free from ambiguities. Given the number of mistakes seen above, perhaps there is a need to improve the specifications currently available or a need to increase the number of tooling available for RAML to facilitate users to validate their files and fix potential issues.
Have RAML files of your own that you want to convert? Please head over to Transformer and start converting for free!
Thanks to Adeel Ali.