Adding Service Definitions
By the end of this guide you will have a basic service providing access to temperature data. Some familiarity with the OpenAPI specification is assumed, although you can ignore the OpenAPI JSON snippets and still follow along if you like.
Creating the Root Service
We will start by creating the root service named
"weather" using the add
service command and specifying its name with the --name
(or -n
) option:
$ bb add service -n weather --summary \
"Weather service: Provides temperature and humidity information."
You should see the following output:
Added path /weather
Successfully added service weather
This will add an entry to the paths object inside the openapi.json
file. The
new entry will have a field name of /weather
and support for a basic GET request
that returns an object. The new entry should look something like this:
"/weather": {
"get": {
"summary": "Weather service: Provides temperature and humidity information.",
"operationId": "getWeatherService",
"tags": [
"weather"
],
"parameters": [
{
"$ref": "#/components/parameters/query-depth"
},
{
"$ref": "#/components/parameters/query-verbose"
}
],
"responses": {
"200": {
"description": "200 OK Response.",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
}
}
}
Adding a Sub-service
Our weather service will include two
subservices: Temperature and humidity. We can create these by again using the
add service
command, but this time we will specify a parent service with the
--service
(or -s
) option:
$ bb add service -n temperature -s weather --summary \
"Returns a temperature object."
You should see the following output:
Added path /weather/temperature
Successfully added service temperature
This will add the temperature service with a similar structure to the weather
service at the path /weather/temperature
.
Adding a Datatype
Our service and sub-service currently provide no
actual service; they do not allow us to interact with any data. To remedy this,
we’ll add a data structure for our service to serve. But first we’ll need to
define the datatype; we’ll create a temperature datatype using the bb add
datatype
command:
$ bb add datatype -n temperature
Enter a field name (leave empty to finish): temp
Enter a type name (leave blank to retrieve a list of available types): number
Enter a field name (leave empty to finish): scale
Enter a type name (leave blank to retrieve a list of available types): string
Enter a field name (leave empty to finish):
Successfully added datatype temperature
The add datatype
command prompts us to enter in field names and types. In
this example we’ve added a temp
type for storing the temperature and a scale
to
specify if the temperature is measured in Celsius or Fahrenheit. Our
openapi.json
file will now include a new schema:
"temperature": {
"type": "object",
"properties": {
"temp": {
"type": "number"
},
"scale": {
"type": "string"
}
}
}
Associating a Service with a Datatype
Now we can update the temperature service to
serve a temperature object. This is achieved with the
bb update service
command:
$ bb update service -s weather -n temperature -d temperature -m ""
You should see the following output:
Set get schema for path /weather/temperature
Successfully updated service /weather/temperature with datatype temperature
Notice the use of -m
(or –method
) option. This refers to the HTTP
methods the service should support. The default value is "post, put, patch, delete".
In our case we only want to support GET. The GET method is always supported and does not need
to be specified, so the double quotes effectively stop the other methods from being added,
leaving just GET.
The update command will make a number of changes to our openapi.json
file.
Firstly, the /weather/temperature
GET response now has an array schema for retrieving a
list of temperature objects:
"schema": {
"type": "array",
"items": {
"allOf": [
{ "$ref": "#/components/schemas/temperature" },
{ "$ref": "#/components/schemas/verbose-object" }
]
}
}
Notice that the items returned within the array support a verbose output for when the
verbose
query parameter is used. If we hadn’t
used the -m
option to limit the HTTP methods allowed then a POST field would
have been added to the /weather/temperature
path also.
If we hadn’t used the -m
option to limit the HTTP methods allowed then
a new path would have been added also: /weather/temperature/{name}
. This would have
had a GET response with a schema also of both the temperature
and
verbose-object
types. Additionally, PUT, PATCH and DELETE fields would have
been added to this path.
Creating a Service with a Primative Datatype
The last thing we need to do to complete our weather service
definition is to add in the humidity service. The humidity service will simply return a number
that represents the humidity percentage. As such we don’t need to define a new datatype, so
we will just add the service as a child to the weather root service and specify the datatype
at the same time as we add the service using the -d
(or --datatype
)
option:
$ bb add service -s weather -n humidity -d number -m ""
You should see the following output:
Added path /weather/humidity
Set get schema for path /weather/humidity
Successfully added service humidity
To recap, the options are: -s
for the root service, -n
for the name
of the child service, -d
for the datatype, and -m
for the supported
HTTP methods (remembering that GET is always included).
Rebuilding the Server
So far we have updated the OpenAPI specification through changes to the openapi.json
file.
The newly added services and a datatype will require the server to be regenerated before we can see these in our server's services.
As before, use the following commands to generate, build and run the server
$ bb generate server
$ npm run build
$ npm run start
Visiting http://localhost:8080/
should now show a link to the root service.
{
"description": "A list of services provided by this API.",
"bbversion": "0.0.2",
"links": {
"self": {
"href": "/"
},
"weather": {
"href": "/weather",
"description": "Weather service: Provides temperature and humidity information.",
"types": []
}
}
}
Following the href of the weather service, http://localhost:8080/weather
, then
reveals links to our sub-services:
{
"description": "Weather service: Provides temperature and humidity information.",
"bbversion": "",
"links": {
"self": {
"href": "/weather"
},
"temperature": {
"href": "/weather/temperature",
"description": "Returns a temperature object.",
"types": []
},
"humidity": {
"href": "/weather/humidity",
"description": "Retrieve a list of number objects.",
"types": []
}
}
}
We can further follow the hyperlinks to
http://localhost:8080/weather/humidity
,
however, this will give us an error:
TypeError: weatherWrapper.service.getHumidityList is not a function
at getHumidityList (/Users/bmillar/tmp/bb/dist/gensrc/controllers/Weather.js:52:48)
at swaggerRouter (/Users/bmillar/tmp/bb/node_modules/oas3-tools/middleware/swagger-router.js:392:20)
...
This is brecause we haven't told the server where to get the humidity value from. We will resolve this issue in the next guide.