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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
|
API specification for AGL
=========================
Micro service architectures on web mostly use OpenAPI
for specifying and documenting their API (Application
Programming Interface).
Following that use, AGL's binder provides a tool to
translate OpenAPI specifications to a code skeleton
written either in C or C++ languages.
However, the API descritpion language OpenAPI never
provided some the requirement that AGL expected for
a such tool:
- specify API that throws events
- describe the permission based security model
Using OpenAPI also had the disavantage of implying
some twist of the model and then some uglyness
verbosity.
Unfortunately, search for a replacement of OpenAPI
that would fullfil below requirements failed.
- Describe JSON data of APIs
- Describe events
- Describe permission based security (even as extension)
- Suitable for generating:
* Documentation
* Code skeleton with/without parameter validation
* Automated test
Consequently, a new API specification formalism has
to be proposed.
This document is the proposal for that new formalism.
For the best, that proposal includes advanced designs
introduced after discussions with Joël Champeau and
Philippe Dhaussy, researchers at ENSTA Bretagne (National
Institute of Advanced Technologies of Brittany) specialized
in system modeling and formal verification.
The goals of specifying APIs
----------------------------
The micro service architecture of AGL and its flexible
IPC mechanism emphasis the decomposition of services or
applications in tiny cooperative parts.
This has big advantages in terms of flexibility and
development process but, conversely, implies to
correctly document interfaces.
Documenting or specifying API are the same thing, except
that, traditionnaly, specifying comes forward and
documenting afterward.
Specifying API can be done using simple text documents.
Using text documents is great for humans but not for
computers.
For this reason, because machines can't exploit human
structured texts, the use of simple text documents
should be avoided as much as possible.
In effect, here is the list of all items that computers
can do based on API specifications:
- Automatic generation of documentation
in many formats and using customizable styles
- Automatic generation of code either
minimal or elaborate
- Automatic adaptation to tansport backend or
protocol
- Automatic generation of test cases
- Integration of advanced tools like supervision,
tracing, spying
- Proof of system properties, in particular
when assembling many API together
Many IDL (Interface Description Language) exist
but it rarely fit all that requirements.
First of all, they generally are "languages",
meaning that they are difficult to parse, to
generate and to manipulate by tools.
OpenAPI is not a language. It is a specification
made by a data structure of JSON format [1][json-org],
[2][json-rfc].
Using JSON has the advantage that no parser has
to be written because a standard one exists.
JSON is not human friendly but its data model
is quasi-isomorph with the one of YAML [3][yaml]
that is more human friendly.
For this reasons, the below proposal describes
an API specification format based on YAML.
Nevertheless, for specifying the values expected
by APIs the format will use the JSON Schema formalism
[4][json-schema]. This allows to describe complex
values and their constraints using a format easy to
integrate in tools.
[json-org]: http://json.org/ "JSON format"
[json-rfc]: https://tools.ietf.org/html/rfc8259 "JSON format RFC"
[yaml]: https://yaml.org/ "YAML format"
[json-schema]: https://json-schema.org/ "JSON Schema"
Content of API specifications
-----------------------------
### Top level structure
An API specification has the following structure:
```yaml
%YAML 1.3
---
afbidl: "0.1"
info: # description the content of the specification
tools: # items for tools (doc, afb-genskel, ..)
verbs: # description of verbs of the API
events: # description of the events emitted by the API
state-machines: # description of the state machines of the API
examples: # examples of usage with or without timings
schemas: # place holder for description of the types of items
```
The specification is designed to describe only one API.
If needed (example: simulation of a complex system), the aggregation
of multiple API descriptions can be done but externally with some
other description.
The heading line *%YAML 1.3* is recommended but not mandatory.
The main item of the description is an object. Its fields are:
- afbidl: this field indicates that the description follows that
specification and the value precise what version of the specification
is used. Current version is 0.1
- info: this field contains an object that give informations about the
API. Its mandatory fields are:
- apiname: name of the API
- title: short explanation of the API
- description: long description of the API
- version: version of the API
Other fields are accepted, example: author, maintainer, homepage,
site, copyright, license, ...
- tools: this fields contains an object that can set properties for
processing tools. The fields are the names of tool to setup.
- verbs: this field contains an object whose fields are the names
of the verbs of the API. For each verb the value attached to the
field of the verb is the description of the verb.
- events: this field contains an object whose fields are the names
of the events thrown by the API. For each event the value attached
to the field describes the event.
- state-machines: this field contains an object whose fields are the
names of the state-machines of the API. For each state-machine the
value attached to the field describes the state machine.
- examples: TO BE SPECIFIED - object of named sequences/scenarii -
- schemas: this optionnal field is intended to group the schema of
the common types used by API.
### Describing verbs
The verbs are described using an object containing the fields
```yaml
title: # short explanation of the verb
description: # detailed description of the verb
permissions: # required permissions
request: # schema of the request parameters
reply: # describe the reply
```
### Describing events
The events are described using an object containing the fields
```yaml
schema: # description of the data associated with the event
when-state: # condition of emiting the event
set-state: # when the event is associated to a state change
```
### Describing state machine
Example of the API gps
----------------------
```yaml
%YAML 1.3
---
afbidl: "0.1"
info:
apiname: gps
title: Service for geolocation
description:
GPS service reports current WGS84 coordinates from GNSS devices
via the gpsd application.
version: "0.1"
author: AGL
maintainer: John Difool
homepage: https://doc.automotivelinux.org/...
tools:
afb-genskel:
scope: static
prefix: req_
postfix: _cb
init: init_gps
doc:
id: gps-api
keywords: gps
author:
version:
src_prefix: api-gps
chapters:
- name: Abstract
url: abstract.md
- name: User Guide
url: userguide.md
verbs:
subscribe:
description: subscribe to gps/gnss events
request: $/schemas/subscription-desc
reply:
success:
schema: $/schemas/none
set-state:
listening: yes
unsubscribe:
description: unsubscribe to gps/gnss events
request: $/schemas/subscription-desc
reply:
success:
schema: $/schemas/none
set-state:
listening: no
location:
description: get current gps/gnss coordinates
request: $/schemas/none
reply:
success: $/schemas/location
_: An error can be returned when the service isn't ready
record:
description: |
Entering *record* mode you must send **{"state": "on"}** with the **record**
verb which will have a JSON response of **{"filename": "gps_YYYYMMDD_hhmm.log"}**
pointing to log under *app-data/agl-service-gps*
Now to enter *replaying* mode you must symlink or copy a GPS dump to
*app-data/agl-service-gps/recording.log* and restart the service.
From then on out the previously recorded GPS data will loop infinitely
which is useful for testing or demonstration purposes.
request: $/schemas/record/request
reply:
success:
schema: $/schemas/record/reply
set-state:
recording: yes
_: An error can be returned when the service isn't ready
events:
location:
schema: $/schemas/location
when-state:
listening: yes
state-machines:
listening:
states: [ no, yes ]
initial: no
recording:
states: [ no, yes ]
initial: no
# Follow JsonSchema specification (https://json-schema.org/)
schemas:
subscription-desc:
title: Description of the event subscribed or unsubscribed
type: object
properties:
value: { enum: [ location ] }
required: [ value ]
location:
title: the location
type: object
properties:
altitude:
title: the altitude in meters above the normal geoide
type: number
minimum: -20000
maximum: 20000
latitude:
title: the latitude in degrees
type: number
minimum: -90
maximum: 90
longitude:
title: the longitude in degrees
type: number
minimum: -180
maximum: 180
speed:
title: the speed in meter per seconds m/s
type: number
minimum: 0
maximum: 6000
track:
title: the heading in degrees
type: number
minimum: 0
maximum: 360
timestamp:
title: time stamp of the location as a ISO8601 date
type: string #ISO8601
pattern: \d{4,}-[01][0-9]-[0-3][0-9]T[012][0-9]:[0-5][0-9]:[0-5][0-9].*
record:
request:
type: object
properties:
state: { const: "on" }
required: [ state ]
reply:
type: object
properties:
filename:
title: the name of the file that records the data of format gps_YYYYMMDD_hhmm.log
type: string
pattern: gps_\d{4}\d{2}\d{2}_\d{2}\d{2}.log
required: [ filename ]
none:
title: no value, just null
const: null
```
|