Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HTTP Swagger #412

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
103 changes: 98 additions & 5 deletions docs/usermanual.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,17 +193,18 @@ Some additional remarks regarding polling commands:
MQTT is a machine-to-machine (M2M)/IoT connectivity protocol, focused on a lightweight interaction between peers. MQTT
Copy link
Member

@fgalan fgalan Jan 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest to add the following entry to CHANGES_NEXT_RELEASE:

- Add: /api-docs endpoint providing swagger-based documentation

or something similar

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in 2808c0b

is based on publish-subscribe mechanisms over a hierarchical set of topics defined by the user.

This section specifies the topics and messages allowed when using MQTT as the transport protocol for Ultralight 2.0. All
the topics subscribed by the agent (to send measures, to configuration command retrieval or to get result
of a command) are prefixed with the agent procotol:
This section specifies the topics and messages allowed when using MQTT as the transport protocol for Ultralight 2.0. All
the topics subscribed by the agent (to send measures, to configuration command retrieval or to get result of a command)
are prefixed with the agent procotol:

```text
/ul/<apiKey>/<deviceId>
```

where `<apiKey>` is the API Key assigned to the service and `<deviceId>` is the ID of the device.

All topis published by the agent (to send a comamnd or to send configuration information) to a device are not prefixed
by the protocol, in this case '/ul', just include apikey and deviceid (e.g: `/FF957A98/MydeviceId/cmd` and
All topics published by the agent (to send a comamnd or to send configuration information) to a device are not prefixed
by the protocol, in this case `/ul`, just include apikey and deviceid (e.g: `/FF957A98/MydeviceId/cmd` and
`/FF957A98/MyDeviceId/configuration/values` ).

This transport protocol binding is still under development.
Expand Down Expand Up @@ -544,3 +545,95 @@ To ensure consistent Markdown formatting run the following:
# Use git-bash on Windows
npm run prettier:text
```

### Swagger

In order to run Swagger, you need to execute the
[IoT Agent](https://github.com/telefonicaid/iotagent-ul/blob/master/docs/installationguide.md#usage) and then you can
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
[IoT Agent](https://github.com/telefonicaid/iotagent-ul/blob/master/docs/installationguide.md#usage) and then you can
IOT Agent (as explained [here](installationguide.md#usage) and then you can

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in 2808c0b

access to:

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest to add a sentence about which API is being covered by the swagger documentation. Something like this:

The swagger documentation provided at /api-docs covers the HTTP southbound interface of the agent. The northbound HTTP interface is not covered.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in 2c34c9a

```
<server_host>:7896/api-docs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One doubt...

IOTA exposes two ports: one corresponding to the "southbound interface" (to which the devices send measures and command responses) and another corresponding to the "nourthbound interface" (in which the IOTA provides the provisioning API, i.e. to create a new device, etc.).

Does this /api-docs endpoint work in both ports? Or only in northbound/southbound?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we have developed the Swagger documentation only for the HTTP protocol (https://fiware-iotagent-ul.readthedocs.io/en/latest/usermanual/index.html#http-binding), so this version of swagger documentation (1.0.0) works only in southbound.

Copy link
Member

@fgalan fgalan Jan 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Northbound is also HTTP-based...

However, if /api-docs only works in southbound, fine with it. I just want to confirm how it works ;)

Could you confirm?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This documentation has been based on the sending of measurements using exclusively the HTTP protocol, so works in southbound.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in 2164dc0

```

If you want to test the HTTP Protocol, two importants points:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From this point on, is this really needed to have the swagger web working at api-docs/ ? Or do you refer to steps needed to run IOTA-UL in general?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

steps needed to run IOTA-UL in general

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case, I'd suggest removing all this part (i.e. from L559). Note that you already include a link to a document that explains how to run IOTA in L553. Repeating a long explanation about it here is a bit out of scope from my point of view.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in 2808c0b


- you should know that other services are needed (see
[installation](https://github.com/telefonicaid/iotagent-ul/blob/master/docs/installationguide.md#installation)):

- Mosquitto
- Mongo
- Rabbitmq
- Orion

- you need to Provisioning a Device and Provisioning a Service Group (see this
[tutorial](https://fiware-tutorials.readthedocs.io/en/latest/iot-agent/index.html#connecting-iot-devices))

For example, you could use this script:

```bash
//additional services
docker pull ansi/mosquitto
docker pull mongo
docker pull rabbitmq
docker pull fiware/orion

docker run -d --name mosquitto_container -p 1883:1883 -l mosquitto ansi/mosquitto
docker run -d --name mongo_container -p 27017:27017 -l mongodb mongo
docker run -d --name rabbitmq_container -p 5672:5672 -l rabbitmq rabbitmq
docker run -d --name orion_container --link mongo_container:mongo_container -p 1026:1026 fiware/orion -dbhost mongo_container

//clone repo
git clone https://github.com/fiqare-secmotic/iotagent-ul.git
cd iotagent-ul/

//IoT Agent
npm install
bin/iotagent-ul

// Provisioning a Service Group
curl -X POST \
http://localhost:4061/iot/services \
-H 'Content-Type: application/json' \
-H 'cache-control: no-cache' \
-H 'fiware-service: openiot' \
-H 'fiware-servicepath: /' \
-d '{
"services": [
{
"apikey": "4jggokgpepnvsb2uv4s40d59ovh",
"cbroker": "http://localhost:1026",
"entity_type": "Thing",
"resource": "/iot/d"
}
]
}'

// Provisioning a Device
curl -X POST \
http://localhost:4061/iot/devices \
-H 'Content-Type: application/json' \
-H 'cache-control: no-cache' \
-H 'fiware-service: openiot' \
-H 'fiware-servicepath: /' \
-d '{
"devices": [
{
"device_id": "motion001",
"entity_name": "urn:ngsd-ld:Motion:001",
"entity_type": "Motion",
"protocol": "PDI-IoTA-UltraLight",
"timezone": "Europe/Berlin",
"attributes": [
{ "object_id": "c", "name":"count", "type":"Integer"}
],
"static_attributes": [
{"name":"refStore", "type": "Relationship","value": "urn:ngsi-ld:Store:001"}
]
}
]
}
'

//Finally, go to locahost:7896/api-docs
```
105 changes: 105 additions & 0 deletions lib/bindings/HTTPBindings.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ var http = require('http'),
context = {
op: 'IOTAUL.HTTP.Binding'
},
swaggerUi = require('swagger-ui-express'),
swaggerJSDoc = require('swagger-jsdoc'),
transport = 'HTTP';

function handleError(error, req, res, next) {
Expand Down Expand Up @@ -406,11 +408,70 @@ function start(callback) {
router: express.Router()
};

var options = {
swaggerDefinition: {
info: {
title: 'IoT Agent UL2 - HTTP', // Title (required)
version: '1.0.0', // Version (required)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This refers to the version of the IOTA? In that case, it should be obtained from version field in package.json.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is related to Swagger documentation version.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be a good idea to tie the version of the swagger documentation to the version of the IOTA Agent. It would be simpler.

The only case in which makes sense to have a version for the documentation and a version for the IOTA is the one in which the same IOTA version (from a code point of view) could have different documentation versions, which I think is not realistic.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The version of the swagger documentation has been changed to the same IOTA UL version how as requested but is important to know that this version really is the first documentation version.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in 2164dc0

description: 'This documentation explains the POST and GET requests to the route /iot/d' // Description (not required)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Swagger spec states that the route is always /iot/d, however the config.js can be overridden by using a non-standard config or applying a Docker env variable. Maybe the description should use config.getConfig().iota.defaultResource to describe the route. It would be kind of tricky to alter the swagger definition itself.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in 43ed851

}
},
apis: ['./lib/bindings/*'] // Path to the API docs
};
var swaggerSpec = swaggerJSDoc(options);

httpBindingServer.app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));

config.getLogger().info(context, 'HTTP Binding listening on port [%s]', config.getConfig().http.port);

httpBindingServer.app.set('port', config.getConfig().http.port);
httpBindingServer.app.set('host', config.getConfig().http.host || '0.0.0.0');

/**
* @swagger
*
* /iot/d:
* get:
* tags:
* - "iot/d"
* summary: "Report new measures"
* description: "A device can report new measures to the IoT Platform using an HTTP GET request to the /iot/d path"
* consumes:
* - "application/json"
* produces:
* - "application/json"
* parameters:
* - in: "query"
* name: "i"
* description: "Device ID"
* type: string
* required: true
* - in: "query"
* name: "k"
* description: "API Key for the service the device is registered on"
* type: string
* required: true
* - in: "query"
* name: "d"
* description: "Ultralight 2.0 payload. Payloads for GET requests should not contain multiple measure groups"
* type: string
* required: true
* - in: "query"
* name: "t"
* description: "Timestamp of the measure"
* type: timestamp
* required: false
* responses:
* 200:
* description: "The new measure has been registered "
* 404:
* description: 'No device was found with "device_name"'
* DEVICE_GROUP_NOT_FOUND:
* description: "Could not find device group"
* PARSE_ERROR:
* description: 'There was a syntax error in the Ultralight request: Unknown error parsing Ultralight 2.0: "syntax_error"'
*/

httpBindingServer.router.get(
config.getConfig().iota.defaultResource || constants.HTTP_MEASURE_PATH,
checkMandatoryParams(true),
Expand All @@ -420,6 +481,50 @@ function start(callback) {
returnCommands
);

/**
* @swagger
*
* /iot/d:
* post:
* tags:
* - "iot/d"
* summary: "Registrer a new measure"
* description: "This request add a new measure to the datebase."
* operationId: "addDevices"
* consumes:
* - text/plain
* parameters:
* - in: query
* name: "i"
* description: "Device ID"
* type: string
* required: true
* - in: query
* name: "k"
* description: "API key. Service identification."
* type: string
* required: true
* - in: query
* name: "t"
* description: "Date and time of register"
* type: timestamp
* required: false
* - in: body
* name: "Sensors"
* description: 'Sensors Measurements. The different sensor values ​​are sent in IoT Agent format. For example: "c|1"'
* type: string
* required: true
* responses:
* 200:
* description: "Report new measures to the IoT Platform"
* 404:
* description: 'DEVICE_NOT_FOUND - No device was found with "device_name"'
* DEVICE_GROUP_NOT_FOUND:
* description: "Could not find device group"
* PARSE_ERROR:
* description: 'There was a syntax error in the Ultralight request: Unknown error parsing Ultralight 2.0: "syntax_error"'
*/

httpBindingServer.router.post(
config.getConfig().iota.defaultResource || constants.HTTP_MEASURE_PATH,
addDefaultHeader,
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@
"textlint-rule-terminology": "~1.1.30",
"textlint-rule-write-good": "~1.6.2",
"should": "13.2.3",
"swagger-jsdoc": "~3.4.0",
"swagger-ui-express": "~4.1.2",
"timekeeper": "2.1.2",
"watch": "~1.0.2"
},
Expand Down