Skip to content

Commit

Permalink
Merge pull request #373 from joel/fix-api-blueprint-format
Browse files Browse the repository at this point in the history
Fix API blueprint documentation
  • Loading branch information
oestrich authored Apr 14, 2018
2 parents 87cb1d4 + 561552d commit ca106a0
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 119 deletions.
154 changes: 72 additions & 82 deletions features/api_blueprint_documentation.feature
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,8 @@ Feature: Generate API Blueprint documentation from test examples
Scenario: Index file should look like we expect
Then the file "doc/api/index.apib" should contain exactly:
"""
FORMAT: A1
FORMAT: 1A
# Example API
# Group Instructions
Expand All @@ -262,18 +263,17 @@ Feature: Generate API Blueprint documentation from test examples
+ Headers
Host: example.org
Host: example.org
+ Response 200 (text/html;charset=utf-8)
+ Headers
Content-Type: text/html;charset=utf-8
Content-Length: 57
Content-Length: 57
+ Body
{"data":{"id":"1","type":"instructions","attributes":{}}}
{"data":{"id":"1","type":"instructions","attributes":{}}}
# Group Orders
Expand All @@ -287,73 +287,70 @@ Feature: Generate API Blueprint documentation from test examples
+ Headers
Content-Type: application/json
Host: example.org
Host: example.org
+ Body
{
"data": {
"type": "order",
"attributes": {
"name": "Order 1",
"amount": 100.0,
"description": "A description"
{
"data": {
"type": "order",
"attributes": {
"name": "Order 1",
"amount": 100.0,
"description": "A description"
}
}
}
}
}
+ Response 201 (application/json)
+ Headers
Content-Type: application/json
Content-Length: 73
Content-Length: 73
+ Body
{
"order": {
"name": "Order 1",
"amount": 100.0,
"description": "A great order"
}
}
{
"order": {
"name": "Order 1",
"amount": 100.0,
"description": "A great order"
}
}
### Return all orders [GET]
+ Request Getting a list of orders
+ Headers
Host: example.org
Host: example.org
+ Response 200 (application/vnd.api+json)
+ Headers
Content-Type: application/vnd.api+json
Content-Length: 137
Content-Length: 137
+ Body
{
"page": 1,
"orders": [
{
"name": "Order 1",
"amount": 9.99,
"description": null
},
{
"name": "Order 2",
"amount": 100.0,
"description": "A great order"
"page": 1,
"orders": [
{
"name": "Order 1",
"amount": 9.99,
"description": null
},
{
"name": "Order 2",
"amount": 100.0,
"description": "A great order"
}
]
}
]
}
## Single Order [/orders/:id{?optional=:optional}]
## Single Order [/orders/{id}{?optional=:optional}]
+ Parameters
+ id: 1 (required, string) - Order id
Expand All @@ -370,96 +367,89 @@ Feature: Generate API Blueprint documentation from test examples
+ Headers
Host: example.org
Content-Type: application/x-www-form-urlencoded
Host: example.org
+ Response 200 (text/html;charset=utf-8)
+ Headers
Content-Type: text/html;charset=utf-8
Content-Length: 0
Content-Length: 0
### Returns a single order [GET]
+ Request Getting a specific order
+ Headers
Host: example.org
Host: example.org
+ Response 200 (application/json)
+ Headers
Content-Type: application/json
Content-Length: 73
Content-Length: 73
+ Body
{
"order": {
"name": "Order 1",
"amount": 100.0,
"description": "A great order"
}
}
{
"order": {
"name": "Order 1",
"amount": 100.0,
"description": "A great order"
}
}
### Updates a single order [PUT]
+ Request Invalid request (application/json; charset=utf-16)
+ Headers
Content-Type: application/json; charset=utf-16
Host: example.org
Host: example.org
+ Response 400 (application/json)
+ Headers
Content-Type: application/json
Content-Length: 0
Content-Length: 0
+ Request Update an order (application/json; charset=utf-16)
+ Headers
Content-Type: application/json; charset=utf-16
Host: example.org
Host: example.org
+ Body
{
"data": {
"id": "1",
"type": "order",
"attributes": {
"name": "Order 1"
{
"data": {
"id": "1",
"type": "order",
"attributes": {
"name": "Order 1"
}
}
}
}
}
+ Response 200 (application/json)
+ Headers
Content-Type: application/json
Content-Length: 111
Content-Length: 111
+ Body
{
"data": {
"id": "1",
"type": "order",
"attributes": {
"name": "Order 1",
"amount": 100.0,
"description": "A description"
{
"data": {
"id": "1",
"type": "order",
"attributes": {
"name": "Order 1",
"amount": 100.0,
"description": "A description"
}
}
}
}
}
"""

Scenario: Example 'Deleting an order' file should not be created
Expand Down
11 changes: 7 additions & 4 deletions lib/rspec_api_documentation/dsl/endpoint/params.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@ def initialize(example_group, example, extra_params)
end

def call
parameters = example.metadata.fetch(:parameters, {}).inject({}) do |hash, param|
set_param = -> hash, param {
SetParam.new(self, hash, param).call
end
parameters.deep_merge!(extra_params)
parameters
}

example.metadata.fetch(:parameters, {}).inject({}, &set_param)
.deep_merge(
example.metadata.fetch(:attributes, {}).inject({}, &set_param)
).deep_merge(extra_params)
end

private
Expand Down
18 changes: 15 additions & 3 deletions lib/rspec_api_documentation/views/api_blueprint_example.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module RspecApiDocumentation
module Views
class ApiBlueprintExample < MarkupExample
TOTAL_SPACES_INDENTATION = 8.freeze
TOTAL_SPACES_INDENTATION = 12.freeze

def initialize(example, configuration)
super
Expand All @@ -20,14 +20,14 @@ def parameters

def requests
super.map do |request|
request[:request_headers_text] = remove_utf8_for_json(request[:request_headers_text])
request[:request_headers_text] = remove_utf8_for_json(remove_content_type(request[:request_headers_text]))
request[:request_headers_text] = indent(request[:request_headers_text])
request[:request_content_type] = content_type(request[:request_headers])
request[:request_content_type] = remove_utf8_for_json(request[:request_content_type])
request[:request_body] = body_to_json(request, :request)
request[:request_body] = indent(request[:request_body])

request[:response_headers_text] = remove_utf8_for_json(request[:response_headers_text])
request[:response_headers_text] = remove_utf8_for_json(remove_content_type(request[:response_headers_text]))
request[:response_headers_text] = indent(request[:response_headers_text])
request[:response_content_type] = content_type(request[:response_headers])
request[:response_content_type] = remove_utf8_for_json(request[:response_content_type])
Expand All @@ -46,6 +46,18 @@ def extension

private

# `Content-Type` header is removed because the information would be duplicated
# since it's already present in `request[:request_content_type]`.
def remove_content_type(headers)
return unless headers
headers
.split("\n")
.reject { |header|
header.start_with?('Content-Type:')
}
.join("\n")
end

def has_request?(metadata)
metadata.any? do |key, value|
[:request_body, :request_headers, :request_content_type].include?(key) && value
Expand Down
13 changes: 12 additions & 1 deletion lib/rspec_api_documentation/views/api_blueprint_index.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def sections
{
"has_attributes?".to_sym => attrs.size > 0,
"has_parameters?".to_sym => params.size > 0,
route: route,
route: format_route(examples[0]),
route_name: examples[0][:route_name],
attributes: attrs,
parameters: params,
Expand All @@ -45,6 +45,17 @@ def examples

private

# APIB follows the RFC 6570 to format URI templates.
# According to it, simple string expansion (used to perform variable
# expansion) should be represented by `{var}` and not by `/:var`
# For example `/posts/:id` should become `/posts/{id}`
# cf. https://github.com/apiaryio/api-blueprint/blob/format-1A/API%20Blueprint%20Specification.md#431-resource-section
# cf. https://tools.ietf.org/html/rfc6570#section-3.2.6
def format_route(example)
route_uri = example[:route_uri].gsub(/:(.*?)([.\/?{]|$)/, '{\1}\2')
"#{route_uri}#{example[:route_optionals]}"
end

# APIB has both `parameters` and `attributes`. This generates a hash
# with all of its properties, like name, description, required.
# {
Expand Down
Loading

0 comments on commit ca106a0

Please sign in to comment.