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

Fix API blueprint documentation #373

Merged
merged 7 commits into from
Apr 14, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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