When defining API specs with RAML, the fact that we define all the information in just one RAML file will make it difficult to maintain and there will be parts and data types that are used over and over again in many different requests URI, such definition is not best practice. Breaking the definition of these reused parts into fragments in other RAML files will help us better manage the definition of API specs, avoiding unnecessary repetition. In this tutorial, I will show you how to define API specs with fragments in RAML.
As an example for this tutorial, I will use a RAML file that defines API specs used to manage student information with the following initial content:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
#%RAML 1.0 baseUri: https://localhost:8081/api title: Student Information Management System version: 1.0 types: Student: type: object properties: id?: type: integer example: 1 code: type: string example: "001" name: type: string example: "Huong Dan Java" /students: get: responses: 200: body: application/json: type: array items: Student example: [ { "id": 1, "code": "001", "name": "Khanh" }, { "id": 2, "code": "002", "name": "Quan" } ] post: body: application/json: type: Student example: { "code": "005", "name": "Khanh" } /{id}: uriParameters: id: description: Id of the Student type: string example: "1" get: responses: 200: body: application/json: example: { "id": 1, "code": "001", "name": "Khanh" } put: body: application/json: type: Student example: { "id": 5, "code": "005", "name": "Khanh Nguyen" } delete: responses: 200: body: application/json: example: { "message": "Student deleted!" } |
As you can see, all information about the Student object, examples are declared in the same RAML file. Suppose later my application is extended to add additional requests URI to delete and edit classes, get student information of a class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
#%RAML 1.0 baseUri: https://localhost:8081/api title: Student Information Management System version: 1.0 types: Student: type: object properties: id?: type: integer example: 1 code: type: string example: "001" name: type: string example: "Huong Dan Java" Clazz: type: object properties: id?: type: integer example: 1 name: type: string example: "A" students?: type: array items: Student /students: get: responses: 200: body: application/json: type: array items: Student example: [ { "id": 1, "code": "001", "name": "Khanh" }, { "id": 2, "code": "002", "name": "Quan" } ] post: body: application/json: type: Student example: { "code": "005", "name": "Khanh" } /{id}: uriParameters: id: description: Id of the Student type: string example: "1" get: responses: 200: body: application/json: example: { "id": 1, "code": "001", "name": "Khanh" } put: body: application/json: type: Student example: { "id": 5, "code": "005", "name": "Khanh Nguyen" } delete: responses: 200: body: application/json: example: { "message": "Student deleted!" } /classes: get: responses: 200: body: application/json: type: array items: Clazz example: [{ "id": 1, "name": "A" }, { "id": 2, "name": "B" }] post: body: application/json: type: Clazz example: { "name": "A" } /{id}: uriParameters: id: description: Id of the Class type: string example: "1" get: responses: 200: body: application/json: type: Clazz example: { "id": 1, "name": "A" } put: body: application/json: type: Clazz example: { "id": 5, "name": "B" } delete: responses: 200: body: application/json: example: { "message": "Class deleted!" } /students: get: responses: 200: body: application/json: type: Clazz example: { "id": 1, "name": "A", "students": [ { "id": 1, "code": "001", "name": "Khanh" }, { "id": 2, "code": "002", "name": "Quan" } ] } |
then as you can see: the content of this RAML file will swell more making it difficult to edit, the examples are not reusable, … Using fragments will help us to solve these inadequacies.
To use fragments, what you need to do is split our RAML file (I will call this RAML file the root RAML file!) by defining fragments for the data types, common information between requests URI using other RAML files, and then declare to use these RAML files in the root RAML file using the keyword “!include”.
In our example above, the first thing we can do is define fragments for data type objects in other RAML files.
I will create 2 new files student.raml and class.raml located in the data-types/objects folder:
to define the data type for Student, Class objects.
To define fragment for data types, we need to declare the line “#%RAML 1.0 DataType” at the beginning of each .raml file. For example, the content of student.raml file will be as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#%RAML 1.0 DataType displayName: Student properties: id?: type: integer example: 1 code: type: string example: "001" name: type: string example: "Huong Dan Java" |
In the class.raml file, we will use the “!include” keyword to declare the Student object as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#%RAML 1.0 DataType displayName: Class properties: id: type: integer example: 1 name: type: string example: "A" students: type: array items: !include student.raml |
Now in the root RAML file, we don’t need to declare data type objects anymore. We just need to use the keyword “!include”, for example like this:
1 2 3 |
types: Student: !include data-types/objects/student.raml Clazz: !include data-types/objects/class.raml |
For examples, we can create an examples directory to contain these examples:
At this point, you can declare an example in the root RAML file, for example as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/students: ... /{id}: uriParameters: id: description: Id of the Student type: string example: "1" get: responses: 200: body: application/json: type: Student example: !include examples/student.json |
The content of our RAML root file after using the fragment is left as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
#%RAML 1.0 baseUri: https://localhost:8081/api title: Student Information Management System version: 1.0 types: Student: !include data-types/objects/student.raml Clazz: !include data-types/objects/class.raml /students: get: responses: 200: body: application/json: type: array items: Student example: !include examples/students.json post: body: application/json: type: Student example: !include examples/post-student.json /{id}: uriParameters: id: description: Id of the Student type: string example: "1" get: responses: 200: body: application/json: type: Student example: !include examples/student.json put: body: application/json: type: Student example: !include examples/student.json delete: responses: 200: body: application/json: example: { "message": "Student deleted!" } /classes: get: responses: 200: body: application/json: type: array items: Clazz example: !include examples/classes.json post: body: application/json: type: Clazz example: !include examples/post-class.json /{id}: uriParameters: id: description: Id of the Class type: string example: "1" get: responses: 200: body: application/json: type: Clazz example: !include examples/class.json put: body: application/json: type: Clazz example: !include examples/class.json delete: responses: 200: body: application/json: example: { "message": "Class deleted!" } /students: get: responses: 200: body: application/json: type: Clazz example: !include examples/class-with-students.json |