Skip to content
This repository has been archived by the owner on Oct 31, 2024. It is now read-only.

Commit

Permalink
Merge pull request #1 from Paradem/group_api_blueprint_by_resource
Browse files Browse the repository at this point in the history
Group api blueprint by resource
  • Loading branch information
netikular committed Jun 5, 2015
2 parents bd21513 + e967c03 commit 1a69221
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 115 deletions.
33 changes: 25 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,36 @@ Write tests using the following convention:
Example:

describe 'Arenas Requests' do
describe 'GET /v1/arenas/{id}' do
it 'responds with the requested arena' do
arena = create :arena, foursquare_id: '5104'
get v1_arena_path(arena)

response.status.should eq(200)
describe 'arenas [/v1/arenas]' do
describe 'create an arena [POST]' do
it 'responds with the created arena' do
arena = build :arena, foursquare_id: '5104'
post v1_arena_path(arena)

response.status.should eq(201)
end
end
end
end
end

The output:

# GET /v1/arenas/{id}
# Arenas

## arenas [/v1/arenas]

### create an arena [POST]
+ Request
+ Headers
+ Body
{
"id": "4e9dbbc2-830b-41a9-b7db-9987735a0b2a",
"name": "Clinton St. Baking Co. & Restaurant",
"latitude": 40.721294,
"longitude": -73.983994,
"foursquare_id": "5104"
}

+ Response 200 (application/json)

Expand Down
120 changes: 14 additions & 106 deletions lib/rspec_api_blueprint.rb
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
require "rspec_api_blueprint/version"
require "rspec_api_blueprint/string_extensions"

require "rspec_api_blueprint/spec_blueprint_translator"

RSpec.configure do |config|
config.before(:suite) do
if defined? Rails
api_docs_folder_path = File.join(Rails.root, '/docs/', '/api_docs/')
else
api_docs_folder_path = File.join(File.expand_path('.'), '/api_docs/')
end

Dir.mkdir(api_docs_folder_path) unless Dir.exists?(api_docs_folder_path)

Dir.glob(File.join(api_docs_folder_path, '*_blueprint.md')).each do |f|
Expand All @@ -18,14 +12,7 @@
end

config.after(:suite) do

if defined? Rails
api_docs_folder_path = File.join(Rails.root, '/docs/', '/api_docs/')
else
api_docs_folder_path = File.join(File.expand_path('.'), '/api_docs/')
end

append = ->(handle, file){ handle.puts File.read(File.join(api_docs_folder_path, file)) }
append = -> (handle, file){ handle.puts File.read(File.join(api_docs_folder_path, file)) }

File.open(File.join(api_docs_folder_path ,'apiary.apib'), 'wb') do |apiary|
append.call(apiary, 'introduction.md')
Expand All @@ -45,98 +32,19 @@
end

config.after(:each, type: :request) do |example|
next unless example.metadata[:document] === true

if response
example_group = example.example_group.metadata
example_groups = []

while example_group
example_groups << example_group
example_group = example_group[:parent_example_group]
end

if example_groups[-2]
action = example_groups[-2][:description_args].first
extra_description = example_groups[-2][:extra_documentation]
end
example_groups[-1][:description_args].first.match(/(.+)\sRequests/)
file_name = $1.gsub(' ','').underscore

if defined? Rails
file = File.join(Rails.root, "/docs/api_docs/#{file_name}_blueprint.md")
else
file = File.join(File.expand_path('.'), "/api_docs/#{file_name}_blueprint.md")
end


File.open(file, 'a') do |f|
# Resource & Action
query_strings = URI.decode(request.env['QUERY_STRING']).split('&')
params = query_strings.map do |value|
value.gsub("[","%5B").gsub("]","%5D")
end

f.write "# #{action}"

unless params.empty?
f.write "?#{params.join('&')}"
end

f.write("\n")
if extra_description.present?
f.write File.read(File.join(Rails.root, '/docs/api_docs', extra_description))
end

# Request
request_body = request.body.read

current_env = request.env ? request.env : request.headers

authorization_header = current_env['HTTP_AUTHORIZATION'] ||
env['X-HTTP_AUTHORIZATION'] ||
env['X_HTTP_AUTHORIZATION'] ||
env['REDIRECT_X_HTTP_AUTHORIZATION'] ||
env['AUTHORIZATION']


if request_body.present? || authorization_header.present? || request.env['QUERY_STRING']
f.write "+ Request #{request.content_type}\n\n"

if request.env['QUERY_STRING'].present?
f.write "+ Parameters\n\n".indent(4)
query_strings = URI.decode(request.env['QUERY_STRING']).split('&')
translator = SpecBlueprintTranslator.new(example, request, response)

query_strings.each do |value|
key, example = value.split('=')
f.write "+ #{key} = '#{example}'\n".indent(12)
end
f.write("\n")
end

allowed_headers = %w(HTTP_AUTHORIZATION AUTHORIZATION CONTENT_TYPE)
f.write "+ Headers\n\n".indent(4)
current_env.each do |header, value|
next unless allowed_headers.include?(header)
header = header.gsub(/HTTP_/, '') if header == 'HTTP_AUTHORIZATION'
f.write "#{header}: #{value}\n".indent(12)
end
f.write "\n"

# Request Body
if request_body.present? && request.content_type.to_s == 'application/json'
f.write "+ Body\n\n".indent(4) if authorization_header
f.write "#{JSON.pretty_generate(JSON.parse(request_body))}\n\n".indent(authorization_header ? 12 : 8)
end
end

# Response
f.write "+ Response #{response.status} (#{response.content_type}; charset=#{response.charset})\n\n"

if response.body.present? && response.content_type.to_s =~ /application\/json/
f.write "#{JSON.pretty_generate(JSON.parse(response.body))}\n\n".indent(8)
end
end unless response.status == 401 || response.status == 403 || response.status == 301
if translator.can_make_blueprint?
translator.open_file_from_grouping
translator.write_resource_to_file
translator.write_action_to_file
translator.close_file
end
end
end

def api_docs_folder_path
return File.join(Rails.root, '/docs/', '/api_docs/') if defined? Rails

File.join(File.expand_path('.'), '/api_docs/')
end
146 changes: 146 additions & 0 deletions lib/rspec_api_blueprint/spec_blueprint_translator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
class SpecBlueprintTranslator
@@actions_covered = {}

def initialize(example, request, response)
group_metas = []
group_meta = example.example_group.metadata

while group_meta.present?
group_metas << group_meta
group_meta = group_meta[:parent_example_group]
end

@example = example
@action_group = group_metas[-3]
@resource_group = group_metas[-2]
@grouping_group = group_metas[-1]

@request = request
@response = response
end

def can_make_blueprint?
@action_group.present? && @resource_group.present? && @grouping_group.present? && @example.metadata[:document] === true && basic_status?
end

def basic_status?
response.status == 200 || response.status == 201 || response.status == 202
end

def request
@request
end

def response
@response
end

def resource
@resource_group[:description_args].first.match(/(.+)\[(.+)\]/)
$2
end

def resource_description
@resource_group[:description_args].first.match(/(.+)\[(.+)\]/)
$1
end

def action
@action_group[:description_args].first.match(/(.+)\[(.+)\]/)
$2.upcase
end

def action_description
@action_group[:description_args].first.match(/(.+)\[(.+)\]/)
$1
end

def open_file_from_grouping
@handle = File.open(file_path, 'a')
end

def close_file
@handle.close
end

def file_path
@grouping_group[:description_args].first.match(/(.+)\sRequests/)
file_name = $1.gsub(' ','').underscore

"#{api_docs_folder_path}#{file_name}_blueprint.md"
end

def write_resource_to_file
return if @@actions_covered.has_key?(resource)

@@actions_covered["#{resource}"] = []

@handle.write "## #{resource_description} [#{resource}]"
@handle.write("\n")
end

def write_action_to_file
return if @@actions_covered["#{resource}"].include?(action)

@@actions_covered["#{resource}"] << action

@handle.write "### #{action_description} [#{action}]"

query_strings = URI.decode(request.env['QUERY_STRING']).split('&')

@handle.write("\n")
write_request_to_file
write_response_to_file
end

def write_request_to_file
request_body = request.body.read

current_env = request.env ? request.env : request.headers

authorization_header = current_env['HTTP_AUTHORIZATION'] ||
env['X-HTTP_AUTHORIZATION'] ||
env['X_HTTP_AUTHORIZATION'] ||
env['REDIRECT_X_HTTP_AUTHORIZATION'] ||
env['AUTHORIZATION']


if request_body.present? || authorization_header.present? || request.env['QUERY_STRING']
@handle.write "+ Request #{request.content_type}\n\n"

if request.env['QUERY_STRING'].present?
@handle.write "+ Parameters\n\n".indent(4)
query_strings = URI.decode(request.env['QUERY_STRING']).split('&')

query_strings.each do |value|
key, example = value.split('=')
@handle.write "+ #{key} = '#{example}'\n".indent(12)
end
@handle.write("\n")
end

allowed_headers = %w(HTTP_AUTHORIZATION AUTHORIZATION CONTENT_TYPE)
@handle.write "+ Headers\n\n".indent(4)
current_env.each do |header, value|
next unless allowed_headers.include?(header)
header = header.gsub(/HTTP_/, '') if header == 'HTTP_AUTHORIZATION'
@handle.write "#{header}: #{value}\n".indent(12)
end
@handle.write "\n"

# Request Body
if request_body.present? && request.content_type.to_s == 'application/json'
@handle.write "+ Body\n\n".indent(4) if authorization_header
@handle.write "#{JSON.pretty_generate(JSON.parse(request_body))}\n\n".indent(authorization_header ? 12 : 8)
end
end
end

def write_response_to_file
@handle.write "+ Response #{response.status} (#{response.content_type}; charset=#{response.charset})\n\n"

if response.body.present? && response.content_type.to_s =~ /application\/json/
@handle.write "#{JSON.pretty_generate(JSON.parse(response.body))}\n\n".indent(8)
end
end
end
2 changes: 1 addition & 1 deletion lib/rspec_api_blueprint/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module RspecApiBlueprint
VERSION = "0.0.8"
VERSION = "0.0.9"
end

0 comments on commit 1a69221

Please sign in to comment.