I showed you how to define RESTful Web Service API specs using RAML. Another way to do this is to use the OpenAPI Specification. How is it in detail? In this tutorial, we will learn together how to define RESTful Web Service API specs using OpenAPI Specification.
We will use YAML or JSON file to define API specs with OpenAPI Specification. Below is the content of the YAML file that defines the API specs in the tutorial Introducing about RAML using the OpenAPI Specification:
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 |
openapi: 3.0.3 info: title: Student Information Management System version: 1.0.0 servers: - url: https://localhost:8081/api paths: /students: get: operationId: getStudents summary: Get all students responses: 200: description: Get all students successfully content: application/json: example: [{ "id": 1, "code": "001", "name": "Khanh" }, { "id": 2, "code": "002", "name": "Quan" }] /students/{id}: get: operationId: getStudentById summary: Get a student by id parameters: - name: id in: path description: "Id of the Student" required: true schema: type: string responses: 200: description: Get student information successfully content: application/json: example: { "id": 1, "code": "001", "name": "Khanh" } delete: operationId: deleteStudentById summary: Delete a student by id parameters: - name: id in: path description: "Id of the Student" required: true schema: type: string responses: 200: description: Delete student information successfully content: application/json: example: { "message": "Student deleted!"} |
As you can see, similar to defining API specs with RAML, at the top of this YAML file we will define some overview information about our API specs. We use the openapi field to define the OpenAPI Specification version we will use to define the API specs, information about the API specs including its purpose (field info.title), the version of this API specs (info.version). The base URL will be defined using the servers.url field.
Request URLs will be defined with section paths.
We cannot define request URLs with the same starting value in the extends type like in RAML. We can only aggregate requests with different HTTP methods but the same request URL. In the above example, request URL “/students/{id}” is defined with GET and DELETE method, we can merge these 2 request URLs together.
We can use the field operationId to identify each request URL. The value of this field is unique within API specs for each request URL.
Similar to RAML, we can also define response for each response status code, each response can have a different data type. In my example, it is application/json.
To define parameters for URL requests, we will use the parameters section in each request. The parameters can be path parameters, query parameters or in headers, cookies. We use the in field of each parameter to declare this.
OpenAPI also supports various data types such as RAML. You can check out more here! In the above example, we can specify the response body data type for request URLs with the Schema object by declaring the components.schemas section as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
components: schemas: Student: type: object properties: id: type: integer format: int64 code: type: string name: type: string Response: type: object properties: message: type: string |
then declare these Schema objects in the response body of each request 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 |
openapi: 3.0.3 info: title: Student Information Management System version: 1.0.0 servers: - url: https://localhost:8081/api paths: /students: get: operationId: getStudents summary: Get all students responses: 200: description: Get all students successfully content: application/json: schema: type: array items: $ref: '#/components/schemas/Student' example: [{ "id": 1, "code": "001", "name": "Khanh" }, { "id": 2, "code": "002", "name": "Quan" }] /students/{id}: get: operationId: getStudentById summary: Get a student by id parameters: - name: id in: path description: "Id of the Student" required: true schema: type: string responses: 200: description: Get student information successfully content: application/json: schema: $ref: '#/components/schemas/Student' example: { "id": 1, "code": "001", "name": "Khanh" } delete: operationId: deleteStudentById summary: Delete a student by id parameters: - name: id in: path description: "Id of the Student" required: true schema: type: string responses: 200: description: Delete student information successfully content: application/json: schema: $ref: '#/components/schemas/Response' example: { "message": "Student deleted!"} components: schemas: Student: type: object properties: id: type: integer format: int64 code: type: string name: type: string Response: type: object properties: message: type: string |
As you can see, we use the keyword “$ref” with the path to the object we want to use, usually starting with “components.schemas”, to declare the data type of the object type.
Defining the API specs before starting to implement the API will help us agree on the API contract, the parties involved only need to follow this API contract to use it, minimizing a lot of possible risks. Think about it before you start implementing RESTful Web Service APIs!