interpol 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +1 -0
- data/README.md +33 -3
- data/Rakefile +22 -0
- data/lib/interpol/configuration.rb +2 -1
- data/lib/interpol/documentation.rb +72 -0
- data/lib/interpol/documentation_app.rb +103 -0
- data/lib/interpol/documentation_app/config.rb +24 -0
- data/lib/interpol/endpoint.rb +8 -0
- data/lib/interpol/version.rb +1 -1
- metadata +32 -18
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -19,8 +19,8 @@ definitions:
|
|
19
19
|
validates your API responses against the JSON schema in your endpoint
|
20
20
|
definition files. This is useful in test/development environments to
|
21
21
|
ensure that your real API returns valid responses.
|
22
|
-
*
|
23
|
-
|
22
|
+
* `Interpol::DocumentationApp` builds a sinatra app that renders
|
23
|
+
documentation for your API based on the endpoint definitions.
|
24
24
|
|
25
25
|
You can use any of these tools individually or some combination of all
|
26
26
|
of them.
|
@@ -81,7 +81,8 @@ definitions:
|
|
81
81
|
Let's look at this YAML file, point-by-point:
|
82
82
|
|
83
83
|
* `name` can be anything you want. Each endpoint should have a different name. Interpol uses
|
84
|
-
it in schema validation error messages.
|
84
|
+
it in schema validation error messages. It is also used by the
|
85
|
+
documentation app.
|
85
86
|
* `route` defines the sinatra route for this endpoint. Note that while
|
86
87
|
Interpol::StubApp supports any sinatra route, Interpol::ResponseSchemaValidator
|
87
88
|
(which has to find a matching endpoint definition from the request path), only
|
@@ -159,6 +160,12 @@ Interpol.default_configuration do |config|
|
|
159
160
|
#
|
160
161
|
# Used by Interpol::ResponseSchemaValidator.
|
161
162
|
config.validation_mode = :error # or :warn
|
163
|
+
|
164
|
+
# Determines the title shown on the rendered documentation
|
165
|
+
# pages.
|
166
|
+
#
|
167
|
+
# Used by Interpol::DocumentationApp.
|
168
|
+
config.documentation_title = "Acme Widget API Documentaton"
|
162
169
|
end
|
163
170
|
|
164
171
|
```
|
@@ -254,6 +261,29 @@ get '/users/:user_id/projects' do
|
|
254
261
|
end
|
255
262
|
```
|
256
263
|
|
264
|
+
### Interpol::DocumentationApp
|
265
|
+
|
266
|
+
This will build a little sinatra app that renders documentation
|
267
|
+
about your API based on your endpoint definitions.
|
268
|
+
|
269
|
+
``` ruby
|
270
|
+
# config.ru
|
271
|
+
|
272
|
+
require 'interpol/documentation_app'
|
273
|
+
|
274
|
+
# the block is only necessary if you want to override the default
|
275
|
+
# config or if you have not set a default config.
|
276
|
+
doc_app = Interpol::DocumentationApp.build do |app|
|
277
|
+
app.endpoint_definition_files = Dir["config/endpoints_definitions/*.yml"]
|
278
|
+
app.documentation_title = "My API Documentation"
|
279
|
+
end
|
280
|
+
|
281
|
+
run doc_app
|
282
|
+
```
|
283
|
+
|
284
|
+
Note: the documentation app is definitely a work-in-progress and I'm not
|
285
|
+
a front-end/UI developer. I'd happily accept a pull request improving it!
|
286
|
+
|
257
287
|
## Contributing
|
258
288
|
|
259
289
|
1. Fork it
|
data/Rakefile
CHANGED
@@ -21,3 +21,25 @@ else
|
|
21
21
|
end
|
22
22
|
|
23
23
|
task default: [:spec, :quality]
|
24
|
+
|
25
|
+
desc "Watch Documentation App Compass Files"
|
26
|
+
task :compass_watch do
|
27
|
+
Dir.chdir("lib/interpol/documentation_app") do
|
28
|
+
sh "bundle exec compass watch"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
desc "Import the twitter bootstrap assets from the compass_twitter_bootstrap gem"
|
33
|
+
task :import_bootstrap_assets do
|
34
|
+
require 'bundler'
|
35
|
+
Bundler.setup
|
36
|
+
|
37
|
+
# when the gem installed as a :git gem, it has "-" as a separator;
|
38
|
+
# when it's installed as a released rubygem, it has "_" as a separator.
|
39
|
+
gem_lib_path = $LOAD_PATH.grep(/compass[-_]twitter[-_]bootstrap/).first
|
40
|
+
assets = Dir[File.join(gem_lib_path, '..', 'vendor', 'assets', '**')]
|
41
|
+
|
42
|
+
destination_path = File.expand_path("../lib/interpol/documentation_app/public", __FILE__)
|
43
|
+
FileUtils.cp_r(assets, destination_path)
|
44
|
+
end
|
45
|
+
|
@@ -26,7 +26,7 @@ module Interpol
|
|
26
26
|
# Public: Defines interpol configuration.
|
27
27
|
class Configuration
|
28
28
|
attr_reader :endpoint_definition_files, :endpoints
|
29
|
-
attr_accessor :validation_mode
|
29
|
+
attr_accessor :validation_mode, :documentation_title
|
30
30
|
|
31
31
|
def initialize
|
32
32
|
api_version do
|
@@ -46,6 +46,7 @@ module Interpol
|
|
46
46
|
end
|
47
47
|
|
48
48
|
self.endpoint_definition_files = []
|
49
|
+
self.documentation_title = "API Documentation Provided by Interpol"
|
49
50
|
yield self if block_given?
|
50
51
|
end
|
51
52
|
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
module Interpol
|
4
|
+
module Documentation
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def html_for_schema(schema)
|
8
|
+
ForSchemaDefinition.new(schema).to_html
|
9
|
+
end
|
10
|
+
|
11
|
+
# Renders the documentation for a schema definition.
|
12
|
+
class ForSchemaDefinition
|
13
|
+
def initialize(schema)
|
14
|
+
@schema = schema
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_html
|
18
|
+
build do |doc|
|
19
|
+
schema_definition(doc, @schema)
|
20
|
+
end.to_html
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def build
|
26
|
+
Nokogiri::HTML::DocumentFragment.parse("").tap do |doc|
|
27
|
+
Nokogiri::HTML::Builder.with(doc) do |doc|
|
28
|
+
yield doc
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def schema_description(doc, schema)
|
34
|
+
return unless schema.has_key?('description')
|
35
|
+
doc.h3(class: "description") { doc.text(schema['description']) }
|
36
|
+
end
|
37
|
+
|
38
|
+
def schema_definition(doc, schema)
|
39
|
+
doc.div(class: "schema-definition") do
|
40
|
+
schema_description(doc, schema)
|
41
|
+
render_properties(doc, Array(schema['properties']))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def render_properties(doc, properties)
|
46
|
+
return if properties.none?
|
47
|
+
|
48
|
+
doc.dl(class: "properties") do
|
49
|
+
properties.each do |name, property|
|
50
|
+
property_definition(doc, name, property)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def property_definition(doc, name, property)
|
56
|
+
doc.dt(class: "name") { doc.text(property_title name, property) }
|
57
|
+
|
58
|
+
if property.has_key?('description')
|
59
|
+
doc.dd { doc.text(property['description']) }
|
60
|
+
end
|
61
|
+
|
62
|
+
render_properties(doc, Array(property['properties']))
|
63
|
+
end
|
64
|
+
|
65
|
+
def property_title(name, property)
|
66
|
+
return name unless property['type']
|
67
|
+
"#{name} (#{property['type']})"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'interpol'
|
2
|
+
require 'interpol/documentation'
|
3
|
+
require 'sinatra/base'
|
4
|
+
require 'nokogiri'
|
5
|
+
|
6
|
+
module Interpol
|
7
|
+
module DocumentationApp
|
8
|
+
extend self
|
9
|
+
|
10
|
+
def build(&block)
|
11
|
+
config = Configuration.default.customized_duplicate(&block)
|
12
|
+
Builder.new(config).app
|
13
|
+
end
|
14
|
+
|
15
|
+
def render_static_page(&block)
|
16
|
+
require 'rack/mock'
|
17
|
+
app = build(&block)
|
18
|
+
status, headers, body = app.call(Rack::MockRequest.env_for "/", method: "GET")
|
19
|
+
AssetInliner.new(body.join, app.public_folder).standalone_page
|
20
|
+
end
|
21
|
+
|
22
|
+
# Inlines the assets so the page can be viewed as a standalone web page.
|
23
|
+
class AssetInliner
|
24
|
+
def initialize(page, asset_root)
|
25
|
+
@page, @asset_root = page, asset_root
|
26
|
+
@doc = Nokogiri::HTML(page)
|
27
|
+
end
|
28
|
+
|
29
|
+
def standalone_page
|
30
|
+
inline_stylesheets
|
31
|
+
inline_javascript
|
32
|
+
@doc.to_s
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def inline_stylesheets
|
38
|
+
@doc.css("link[rel=stylesheet]").map do |link|
|
39
|
+
inline_asset link, "style", link['href'], type: "text/css"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def inline_javascript
|
44
|
+
@doc.css("script[src]").each do |script|
|
45
|
+
inline_asset script, "script", script['src'], type: "text/javascript"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def contents_for(asset)
|
50
|
+
File.read(File.join(@asset_root, asset))
|
51
|
+
end
|
52
|
+
|
53
|
+
def inline_asset(tag, tag_type, filename, attributes = {})
|
54
|
+
inline_tag = Nokogiri::XML::Node.new(tag_type, @doc)
|
55
|
+
attributes.each { |k, v| inline_tag[k] = v }
|
56
|
+
inline_tag.content = contents_for(filename)
|
57
|
+
tag.add_next_sibling(inline_tag)
|
58
|
+
tag.remove
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
module Helpers
|
65
|
+
def interpol_config
|
66
|
+
self.class.interpol_config
|
67
|
+
end
|
68
|
+
|
69
|
+
def endpoints
|
70
|
+
interpol_config.endpoints
|
71
|
+
end
|
72
|
+
|
73
|
+
def current_endpoint
|
74
|
+
endpoints.first
|
75
|
+
end
|
76
|
+
|
77
|
+
def title
|
78
|
+
interpol_config.documentation_title
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Private: Builds a stub sinatra app for the given interpol
|
83
|
+
# configuration.
|
84
|
+
class Builder
|
85
|
+
attr_reader :app
|
86
|
+
|
87
|
+
def initialize(config)
|
88
|
+
@app = Sinatra.new do
|
89
|
+
dir = File.dirname(File.expand_path(__FILE__))
|
90
|
+
set :views, "#{dir}/documentation_app/views"
|
91
|
+
set :public_folder, "#{dir}/documentation_app/public"
|
92
|
+
set :interpol_config, config
|
93
|
+
helpers Helpers
|
94
|
+
|
95
|
+
get('/') do
|
96
|
+
erb :layout, locals: { endpoints: endpoints, current_endpoint: current_endpoint }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Require any additional compass plugins here.
|
2
|
+
require 'compass_twitter_bootstrap'
|
3
|
+
|
4
|
+
# Set this to the root of your project when deployed:
|
5
|
+
http_path = "/"
|
6
|
+
css_dir = "public/stylesheets"
|
7
|
+
sass_dir = "sass"
|
8
|
+
images_dir = "public/images"
|
9
|
+
javascripts_dir = "public/javascripts"
|
10
|
+
|
11
|
+
# You can select your preferred output style here (can be overridden via the command line):
|
12
|
+
# output_style = :expanded or :nested or :compact or :compressed
|
13
|
+
|
14
|
+
# To enable relative paths to assets via compass helper functions. Uncomment:
|
15
|
+
relative_assets = true
|
16
|
+
|
17
|
+
# To disable debugging comments that display the original location of your selectors. Uncomment:
|
18
|
+
line_comments = false
|
19
|
+
|
20
|
+
# If you prefer the indented syntax, you might want to regenerate this
|
21
|
+
# project again passing --syntax sass, or you can uncomment this:
|
22
|
+
# preferred_syntax = :sass
|
23
|
+
# and then run:
|
24
|
+
# sass-convert -R --from scss --to sass sass scss && rm -rf sass && mv scss sass
|
data/lib/interpol/endpoint.rb
CHANGED
@@ -24,6 +24,7 @@ module Interpol
|
|
24
24
|
@route = fetch_from(endpoint_hash, 'route')
|
25
25
|
@method = fetch_from(endpoint_hash, 'method').downcase.to_sym
|
26
26
|
@definitions = extract_definitions_from(endpoint_hash)
|
27
|
+
validate_name!
|
27
28
|
end
|
28
29
|
|
29
30
|
def find_definition!(version)
|
@@ -76,6 +77,13 @@ module Interpol
|
|
76
77
|
|
77
78
|
definitions
|
78
79
|
end
|
80
|
+
|
81
|
+
def validate_name!
|
82
|
+
unless name =~ /\A[\w\-]+\z/
|
83
|
+
raise ArgumentError, "Invalid endpoint name (#{name.inspect}). "+
|
84
|
+
"Only letters, numbers, underscores and dashes are allowed."
|
85
|
+
end
|
86
|
+
end
|
79
87
|
end
|
80
88
|
|
81
89
|
# Wraps a single versioned definition for an endpoint.
|
data/lib/interpol/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: interpol
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-04-
|
12
|
+
date: 2012-04-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sinatra
|
16
|
-
requirement: &
|
16
|
+
requirement: &2152438820 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -24,10 +24,10 @@ dependencies:
|
|
24
24
|
version: 2.0.0
|
25
25
|
type: :runtime
|
26
26
|
prerelease: false
|
27
|
-
version_requirements: *
|
27
|
+
version_requirements: *2152438820
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: json-schema
|
30
|
-
requirement: &
|
30
|
+
requirement: &2152437840 !ruby/object:Gem::Requirement
|
31
31
|
none: false
|
32
32
|
requirements:
|
33
33
|
- - ~>
|
@@ -35,10 +35,21 @@ dependencies:
|
|
35
35
|
version: 1.0.5
|
36
36
|
type: :runtime
|
37
37
|
prerelease: false
|
38
|
-
version_requirements: *
|
38
|
+
version_requirements: *2152437840
|
39
|
+
- !ruby/object:Gem::Dependency
|
40
|
+
name: nokogiri
|
41
|
+
requirement: &2152437180 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.5'
|
47
|
+
type: :runtime
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: *2152437180
|
39
50
|
- !ruby/object:Gem::Dependency
|
40
51
|
name: rspec
|
41
|
-
requirement: &
|
52
|
+
requirement: &2152436180 !ruby/object:Gem::Requirement
|
42
53
|
none: false
|
43
54
|
requirements:
|
44
55
|
- - ~>
|
@@ -46,10 +57,10 @@ dependencies:
|
|
46
57
|
version: '2.9'
|
47
58
|
type: :development
|
48
59
|
prerelease: false
|
49
|
-
version_requirements: *
|
60
|
+
version_requirements: *2152436180
|
50
61
|
- !ruby/object:Gem::Dependency
|
51
62
|
name: rspec-fire
|
52
|
-
requirement: &
|
63
|
+
requirement: &2152435480 !ruby/object:Gem::Requirement
|
53
64
|
none: false
|
54
65
|
requirements:
|
55
66
|
- - ~>
|
@@ -57,10 +68,10 @@ dependencies:
|
|
57
68
|
version: '0.4'
|
58
69
|
type: :development
|
59
70
|
prerelease: false
|
60
|
-
version_requirements: *
|
71
|
+
version_requirements: *2152435480
|
61
72
|
- !ruby/object:Gem::Dependency
|
62
73
|
name: simplecov
|
63
|
-
requirement: &
|
74
|
+
requirement: &2152434900 !ruby/object:Gem::Requirement
|
64
75
|
none: false
|
65
76
|
requirements:
|
66
77
|
- - ~>
|
@@ -68,10 +79,10 @@ dependencies:
|
|
68
79
|
version: '0.6'
|
69
80
|
type: :development
|
70
81
|
prerelease: false
|
71
|
-
version_requirements: *
|
82
|
+
version_requirements: *2152434900
|
72
83
|
- !ruby/object:Gem::Dependency
|
73
84
|
name: cane
|
74
|
-
requirement: &
|
85
|
+
requirement: &2152433580 !ruby/object:Gem::Requirement
|
75
86
|
none: false
|
76
87
|
requirements:
|
77
88
|
- - ~>
|
@@ -79,10 +90,10 @@ dependencies:
|
|
79
90
|
version: '1.2'
|
80
91
|
type: :development
|
81
92
|
prerelease: false
|
82
|
-
version_requirements: *
|
93
|
+
version_requirements: *2152433580
|
83
94
|
- !ruby/object:Gem::Dependency
|
84
95
|
name: rake
|
85
|
-
requirement: &
|
96
|
+
requirement: &2152433060 !ruby/object:Gem::Requirement
|
86
97
|
none: false
|
87
98
|
requirements:
|
88
99
|
- - ~>
|
@@ -90,10 +101,10 @@ dependencies:
|
|
90
101
|
version: 0.9.2.2
|
91
102
|
type: :development
|
92
103
|
prerelease: false
|
93
|
-
version_requirements: *
|
104
|
+
version_requirements: *2152433060
|
94
105
|
- !ruby/object:Gem::Dependency
|
95
106
|
name: rack-test
|
96
|
-
requirement: &
|
107
|
+
requirement: &2152432580 !ruby/object:Gem::Requirement
|
97
108
|
none: false
|
98
109
|
requirements:
|
99
110
|
- - =
|
@@ -101,7 +112,7 @@ dependencies:
|
|
101
112
|
version: 0.6.1
|
102
113
|
type: :development
|
103
114
|
prerelease: false
|
104
|
-
version_requirements: *
|
115
|
+
version_requirements: *2152432580
|
105
116
|
description: Interpol is a toolkit for working with API endpoint definition files,
|
106
117
|
giving you a stub app, a schema validation middleware, and browsable documentation.
|
107
118
|
email:
|
@@ -115,6 +126,9 @@ files:
|
|
115
126
|
- Gemfile
|
116
127
|
- Rakefile
|
117
128
|
- lib/interpol/configuration.rb
|
129
|
+
- lib/interpol/documentation.rb
|
130
|
+
- lib/interpol/documentation_app/config.rb
|
131
|
+
- lib/interpol/documentation_app.rb
|
118
132
|
- lib/interpol/endpoint.rb
|
119
133
|
- lib/interpol/errors.rb
|
120
134
|
- lib/interpol/response_schema_validator.rb
|