Skip to content

Commit ca106a0

Browse files
authored
Merge pull request #373 from joel/fix-api-blueprint-format
Fix API blueprint documentation
2 parents 87cb1d4 + 561552d commit ca106a0

File tree

7 files changed

+120
-119
lines changed

7 files changed

+120
-119
lines changed

features/api_blueprint_documentation.feature

+72-82
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,8 @@ Feature: Generate API Blueprint documentation from test examples
248248
Scenario: Index file should look like we expect
249249
Then the file "doc/api/index.apib" should contain exactly:
250250
"""
251-
FORMAT: A1
251+
FORMAT: 1A
252+
# Example API
252253
253254
# Group Instructions
254255
@@ -262,18 +263,17 @@ Feature: Generate API Blueprint documentation from test examples
262263
263264
+ Headers
264265
265-
Host: example.org
266+
Host: example.org
266267
267268
+ Response 200 (text/html;charset=utf-8)
268269
269270
+ Headers
270271
271-
Content-Type: text/html;charset=utf-8
272-
Content-Length: 57
272+
Content-Length: 57
273273
274274
+ Body
275275
276-
{"data":{"id":"1","type":"instructions","attributes":{}}}
276+
{"data":{"id":"1","type":"instructions","attributes":{}}}
277277
278278
# Group Orders
279279
@@ -287,73 +287,70 @@ Feature: Generate API Blueprint documentation from test examples
287287
288288
+ Headers
289289
290-
Content-Type: application/json
291-
Host: example.org
290+
Host: example.org
292291
293292
+ Body
294293
295-
{
296-
"data": {
297-
"type": "order",
298-
"attributes": {
299-
"name": "Order 1",
300-
"amount": 100.0,
301-
"description": "A description"
294+
{
295+
"data": {
296+
"type": "order",
297+
"attributes": {
298+
"name": "Order 1",
299+
"amount": 100.0,
300+
"description": "A description"
301+
}
302+
}
302303
}
303-
}
304-
}
305304
306305
+ Response 201 (application/json)
307306
308307
+ Headers
309308
310-
Content-Type: application/json
311-
Content-Length: 73
309+
Content-Length: 73
312310
313311
+ Body
314312
315-
{
316-
"order": {
317-
"name": "Order 1",
318-
"amount": 100.0,
319-
"description": "A great order"
320-
}
321-
}
313+
{
314+
"order": {
315+
"name": "Order 1",
316+
"amount": 100.0,
317+
"description": "A great order"
318+
}
319+
}
322320
323321
### Return all orders [GET]
324322
325323
+ Request Getting a list of orders
326324
327325
+ Headers
328326
329-
Host: example.org
327+
Host: example.org
330328
331329
+ Response 200 (application/vnd.api+json)
332330
333331
+ Headers
334332
335-
Content-Type: application/vnd.api+json
336-
Content-Length: 137
333+
Content-Length: 137
337334
338335
+ Body
339336
340-
{
341-
"page": 1,
342-
"orders": [
343-
{
344-
"name": "Order 1",
345-
"amount": 9.99,
346-
"description": null
347-
},
348337
{
349-
"name": "Order 2",
350-
"amount": 100.0,
351-
"description": "A great order"
338+
"page": 1,
339+
"orders": [
340+
{
341+
"name": "Order 1",
342+
"amount": 9.99,
343+
"description": null
344+
},
345+
{
346+
"name": "Order 2",
347+
"amount": 100.0,
348+
"description": "A great order"
349+
}
350+
]
352351
}
353-
]
354-
}
355352
356-
## Single Order [/orders/:id{?optional=:optional}]
353+
## Single Order [/orders/{id}{?optional=:optional}]
357354
358355
+ Parameters
359356
+ id: 1 (required, string) - Order id
@@ -370,96 +367,89 @@ Feature: Generate API Blueprint documentation from test examples
370367
371368
+ Headers
372369
373-
Host: example.org
374-
Content-Type: application/x-www-form-urlencoded
370+
Host: example.org
375371
376372
+ Response 200 (text/html;charset=utf-8)
377373
378374
+ Headers
379375
380-
Content-Type: text/html;charset=utf-8
381-
Content-Length: 0
376+
Content-Length: 0
382377
383378
### Returns a single order [GET]
384379
385380
+ Request Getting a specific order
386381
387382
+ Headers
388383
389-
Host: example.org
384+
Host: example.org
390385
391386
+ Response 200 (application/json)
392387
393388
+ Headers
394389
395-
Content-Type: application/json
396-
Content-Length: 73
390+
Content-Length: 73
397391
398392
+ Body
399393
400-
{
401-
"order": {
402-
"name": "Order 1",
403-
"amount": 100.0,
404-
"description": "A great order"
405-
}
406-
}
394+
{
395+
"order": {
396+
"name": "Order 1",
397+
"amount": 100.0,
398+
"description": "A great order"
399+
}
400+
}
407401
408402
### Updates a single order [PUT]
409403
410404
+ Request Invalid request (application/json; charset=utf-16)
411405
412406
+ Headers
413407
414-
Content-Type: application/json; charset=utf-16
415-
Host: example.org
408+
Host: example.org
416409
417410
+ Response 400 (application/json)
418411
419412
+ Headers
420413
421-
Content-Type: application/json
422-
Content-Length: 0
414+
Content-Length: 0
423415
424416
+ Request Update an order (application/json; charset=utf-16)
425417
426418
+ Headers
427419
428-
Content-Type: application/json; charset=utf-16
429-
Host: example.org
420+
Host: example.org
430421
431422
+ Body
432423
433-
{
434-
"data": {
435-
"id": "1",
436-
"type": "order",
437-
"attributes": {
438-
"name": "Order 1"
424+
{
425+
"data": {
426+
"id": "1",
427+
"type": "order",
428+
"attributes": {
429+
"name": "Order 1"
430+
}
431+
}
439432
}
440-
}
441-
}
442433
443434
+ Response 200 (application/json)
444435
445436
+ Headers
446437
447-
Content-Type: application/json
448-
Content-Length: 111
438+
Content-Length: 111
449439
450440
+ Body
451441
452-
{
453-
"data": {
454-
"id": "1",
455-
"type": "order",
456-
"attributes": {
457-
"name": "Order 1",
458-
"amount": 100.0,
459-
"description": "A description"
442+
{
443+
"data": {
444+
"id": "1",
445+
"type": "order",
446+
"attributes": {
447+
"name": "Order 1",
448+
"amount": 100.0,
449+
"description": "A description"
450+
}
451+
}
460452
}
461-
}
462-
}
463453
"""
464454

465455
Scenario: Example 'Deleting an order' file should not be created

lib/rspec_api_documentation/dsl/endpoint/params.rb

+7-4
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,14 @@ def initialize(example_group, example, extra_params)
1313
end
1414

1515
def call
16-
parameters = example.metadata.fetch(:parameters, {}).inject({}) do |hash, param|
16+
set_param = -> hash, param {
1717
SetParam.new(self, hash, param).call
18-
end
19-
parameters.deep_merge!(extra_params)
20-
parameters
18+
}
19+
20+
example.metadata.fetch(:parameters, {}).inject({}, &set_param)
21+
.deep_merge(
22+
example.metadata.fetch(:attributes, {}).inject({}, &set_param)
23+
).deep_merge(extra_params)
2124
end
2225

2326
private

lib/rspec_api_documentation/views/api_blueprint_example.rb

+15-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module RspecApiDocumentation
22
module Views
33
class ApiBlueprintExample < MarkupExample
4-
TOTAL_SPACES_INDENTATION = 8.freeze
4+
TOTAL_SPACES_INDENTATION = 12.freeze
55

66
def initialize(example, configuration)
77
super
@@ -20,14 +20,14 @@ def parameters
2020

2121
def requests
2222
super.map do |request|
23-
request[:request_headers_text] = remove_utf8_for_json(request[:request_headers_text])
23+
request[:request_headers_text] = remove_utf8_for_json(remove_content_type(request[:request_headers_text]))
2424
request[:request_headers_text] = indent(request[:request_headers_text])
2525
request[:request_content_type] = content_type(request[:request_headers])
2626
request[:request_content_type] = remove_utf8_for_json(request[:request_content_type])
2727
request[:request_body] = body_to_json(request, :request)
2828
request[:request_body] = indent(request[:request_body])
2929

30-
request[:response_headers_text] = remove_utf8_for_json(request[:response_headers_text])
30+
request[:response_headers_text] = remove_utf8_for_json(remove_content_type(request[:response_headers_text]))
3131
request[:response_headers_text] = indent(request[:response_headers_text])
3232
request[:response_content_type] = content_type(request[:response_headers])
3333
request[:response_content_type] = remove_utf8_for_json(request[:response_content_type])
@@ -46,6 +46,18 @@ def extension
4646

4747
private
4848

49+
# `Content-Type` header is removed because the information would be duplicated
50+
# since it's already present in `request[:request_content_type]`.
51+
def remove_content_type(headers)
52+
return unless headers
53+
headers
54+
.split("\n")
55+
.reject { |header|
56+
header.start_with?('Content-Type:')
57+
}
58+
.join("\n")
59+
end
60+
4961
def has_request?(metadata)
5062
metadata.any? do |key, value|
5163
[:request_body, :request_headers, :request_content_type].include?(key) && value

lib/rspec_api_documentation/views/api_blueprint_index.rb

+12-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def sections
2323
{
2424
"has_attributes?".to_sym => attrs.size > 0,
2525
"has_parameters?".to_sym => params.size > 0,
26-
route: route,
26+
route: format_route(examples[0]),
2727
route_name: examples[0][:route_name],
2828
attributes: attrs,
2929
parameters: params,
@@ -45,6 +45,17 @@ def examples
4545

4646
private
4747

48+
# APIB follows the RFC 6570 to format URI templates.
49+
# According to it, simple string expansion (used to perform variable
50+
# expansion) should be represented by `{var}` and not by `/:var`
51+
# For example `/posts/:id` should become `/posts/{id}`
52+
# cf. https://github.com/apiaryio/api-blueprint/blob/format-1A/API%20Blueprint%20Specification.md#431-resource-section
53+
# cf. https://tools.ietf.org/html/rfc6570#section-3.2.6
54+
def format_route(example)
55+
route_uri = example[:route_uri].gsub(/:(.*?)([.\/?{]|$)/, '{\1}\2')
56+
"#{route_uri}#{example[:route_optionals]}"
57+
end
58+
4859
# APIB has both `parameters` and `attributes`. This generates a hash
4960
# with all of its properties, like name, description, required.
5061
# {

0 commit comments

Comments
 (0)