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.