Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 293 lines (233 sloc) 9.746 kb
8933293f » myronmarston
2012-04-02 Initial Gem skeleton from bundler.
1 # Interpol
2
23cc344d » myronmarston
2012-04-03 Add Travis build status to readme.
3 [![Build Status](https://secure.travis-ci.org/seomoz/interpol.png)](http://travis-ci.org/seomoz/interpol)
4
72f221a7 » myronmarston
2012-04-02 First pass at the README.
5 Interpol is a toolkit for policing your HTTP JSON interface. To use it,
f8e24d62 » myronmarston
2012-04-03 Fill out the readme some more.
6 define the endpoints of your HTTP API in simple YAML files.
7 Interpol provides multiple tools to work with these endpoint
8 definitions:
9
10 * `Interpol::TestHelper::RSpec` and `Interpol::TestHelper::TestUnit` are
11 modules that you can mix in to your test context. They provide a means
12 to generate tests from your endpoint definitions that validate example
13 data against your JSON schema definition.
14 * `Interpol::StubApp` builds a stub implementation of your API from
15 the endpoint definitions. This can be distributed with your API's
16 client gem so that API users have something local to hit that
17 generates data that is valid according to your schema definition.
18 * `Interpol::ResponseSchemaValidator` is a rack middleware that
19 validates your API responses against the JSON schema in your endpoint
20 definition files. This is useful in test/development environments to
21 ensure that your real API returns valid responses.
956385c5 » myronmarston
2012-04-09 Document the documentation app.
22 * `Interpol::DocumentationApp` builds a sinatra app that renders
23 documentation for your API based on the endpoint definitions.
f8e24d62 » myronmarston
2012-04-03 Fill out the readme some more.
24
25 You can use any of these tools individually or some combination of all
26 of them.
8933293f » myronmarston
2012-04-02 Initial Gem skeleton from bundler.
27
28 ## Installation
29
30 Add this line to your application's Gemfile:
31
32 gem 'interpol'
33
34 And then execute:
35
36 $ bundle
37
38 Or install it yourself as:
39
40 $ gem install interpol
41
f8e24d62 » myronmarston
2012-04-03 Fill out the readme some more.
42 ## Endpoint Definition
8933293f » myronmarston
2012-04-02 Initial Gem skeleton from bundler.
43
f8e24d62 » myronmarston
2012-04-03 Fill out the readme some more.
44 Endpoints are defined in YAML files, using a separate
45 file per endpoint. Here's an example:
72f221a7 » myronmarston
2012-04-02 First pass at the README.
46
47 ``` yaml
48 ---
49 name: user_projects
50 route: /users/:user_id/projects
51 method: GET
f8e24d62 » myronmarston
2012-04-03 Fill out the readme some more.
52 definitions:
72f221a7 » myronmarston
2012-04-02 First pass at the README.
53 - versions: ["1.0"]
54 schema:
55 description: Returns a list of projects for the given user.
56 type: object
57 properties:
58 projects:
59 description: List of projects.
60 type: array
61 items:
62 type: object
63 properties:
64 name:
65 description: The name of the project.
66 type: string
67 importance:
68 description: The importance of the project, on a scale of 1 to 10.
69 type: integer
70 minimum: 1
71 maximum: 10
72
73 examples:
74 - projects:
75 - name: iPhone App
76 importance: 5
77 - name: Rails App
78 importance: 7
79 ```
80
81 Let's look at this YAML file, point-by-point:
82
83 * `name` can be anything you want. Each endpoint should have a different name. Interpol uses
d97e9cea » myronmarston
2012-04-09 Build documentation app.
84 it in schema validation error messages. It is also used by the
85 documentation app.
f8e24d62 » myronmarston
2012-04-03 Fill out the readme some more.
86 * `route` defines the sinatra route for this endpoint. Note that while
87 Interpol::StubApp supports any sinatra route, Interpol::ResponseSchemaValidator
88 (which has to find a matching endpoint definition from the request path), only
89 supports a subset of Sinatra's routing syntax. Specifically, it supports static
90 segments (`users` and `projects` in the example above) and named
91 parameter segments (`:user_id` in the example above).
72f221a7 » myronmarston
2012-04-02 First pass at the README.
92 * `method` defines the HTTP method for this endpoint. The method should be in uppercase.
f8e24d62 » myronmarston
2012-04-03 Fill out the readme some more.
93 * The `definitions` array contains a list of versioned schema definitions, with
94 corresponding examples. Everytime you modify your schema and change the version,
95 you should add a new entry here.
96 * The `versions` array lists the endpoint versions that should be associated with a
97 particular schema definition.
72f221a7 » myronmarston
2012-04-02 First pass at the README.
98 * The `schema` contains a [JSON schema](http://tools.ietf.org/html/draft-zyp-json-schema-03)
99 description of the contents of the endpoint. This schema definition is used by the
100 `SchemaValidation` middleware to ensure that your implementation of the endpoint
101 matches the definition.
f8e24d62 » myronmarston
2012-04-03 Fill out the readme some more.
102 * `examples` contains a list of valid example data. It is used by the stub app as example data.
103
104 ## Configuration
72f221a7 » myronmarston
2012-04-02 First pass at the README.
105
f8e24d62 » myronmarston
2012-04-03 Fill out the readme some more.
106 Interpol provides two levels of configuration: global default
107 configuration, and one-off configuration, set on a particular
108 instance of one of the provided tools. Each of the tools accepts
109 a configuration block that provides an identical API to the
110 global configuration API shown below.
111
112 ``` ruby
113 require 'interpol'
114
115 Interpol.default_configuration do |config|
116 # Tells Interpol where to find your endpoint definition files.
117 #
118 # Needed by all tools.
119 config.endpoint_definition_files = Dir["config/endpoints/*.yml"]
120
121 # Determines which versioned endpoint definition Interpol uses
122 # for a request. You can also use a block form, which yields
223724aa » myronmarston
2012-04-04 Yield the endpoint from the api_version block as well.
123 # the rack env hash and the endpoint object as arguments.
124 # This is useful when you need to extract the version from a
125 # request header (e.g. Accept) or from the request URI.
f8e24d62 » myronmarston
2012-04-03 Fill out the readme some more.
126 #
127 # Needed by Interpol::StubApp and Interpol::ResponseSchemaValidator.
128 config.api_version '1.0'
129
130 # Determines the stub app response when the requested version is not
131 # available. This block will be eval'd in the context of the stub app
132 # sinatra application, so you can use sinatra helpers like `halt` here.
133 #
134 # Needed by Interpol::StubApp.
1e4fd6bc » myronmarston
2012-04-04 Rename config hook.
135 config.on_unavailable_request_version do |requested_version, available_versions|
f8e24d62 » myronmarston
2012-04-03 Fill out the readme some more.
136 message = JSON.dump(
137 "message" => "Not Acceptable",
138 "requested_version" => requested_version,
139 "available_versions" => available_versions
140 )
141
142 halt 406, message
143 end
72f221a7 » myronmarston
2012-04-02 First pass at the README.
144
f8e24d62 » myronmarston
2012-04-03 Fill out the readme some more.
145 # Determines which responses will be validated against the endpoint
146 # definition when you use Interpol::ResponseSchemaValidator. The
147 # validation is meant to run against the "happy path" response.
148 # For responses like "404 Not Found", you probably don't want any
149 # validation performed. The default validate_if hook will cause
150 # validation to run against any 2xx response except 204 ("No Content").
151 #
152 # Used by Interpol::ResponseSchemaValidator.
153 config.validate_if do |env, status, headers, body|
154 headers['Content-Type'] == my_custom_mime_type
155 end
156
157 # Determines how Interpol::ResponseSchemaValidator handles
158 # invalid data. By default it will raise an error, but you can
159 # make it print a warning instead.
160 #
161 # Used by Interpol::ResponseSchemaValidator.
162 config.validation_mode = :error # or :warn
956385c5 » myronmarston
2012-04-09 Document the documentation app.
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"
f8e24d62 » myronmarston
2012-04-03 Fill out the readme some more.
169 end
170
171 ```
72f221a7 » myronmarston
2012-04-02 First pass at the README.
172
f8e24d62 » myronmarston
2012-04-03 Fill out the readme some more.
173 ## Tool Usage
174
d2182db9 » myronmarston
2012-04-04 Putting code in a section title looks ugly.
175 ### Interpol::TestHelper::RSpec and Interpol::TestHelper::TestUnit
f8e24d62 » myronmarston
2012-04-03 Fill out the readme some more.
176
177 These are modules that you can extend onto an RSpec example group
178 or a `Test::Unit::TestCase` subclass, respectively.
179 They provide a `define_interpol_example_tests` macro that will define
180 a test for each example for each schema definition in your endpoint
181 definition files. The tests will validate that your schema is a valid
182 JSON schema definition and will validate that the examples are valid
183 according to that schema.
184
185 RSpec example:
72f221a7 » myronmarston
2012-04-02 First pass at the README.
186
187 ``` ruby
188 require 'interpol/test_helper'
189
190 describe "My API endpoints" do
191 extend Interpol::TestHelper::RSpec
192
f8e24d62 » myronmarston
2012-04-03 Fill out the readme some more.
193 # the block is only necessary if you want to override the default
194 # config or if you have not set a default config.
72f221a7 » myronmarston
2012-04-02 First pass at the README.
195 define_interpol_example_tests do |ipol|
196 ipol.endpoint_definition_files = Dir["config/endpoints_definitions/*.yml"]
197 end
198 end
199 ```
200
f8e24d62 » myronmarston
2012-04-03 Fill out the readme some more.
201 Test::Unit example:
72f221a7 » myronmarston
2012-04-02 First pass at the README.
202
203 ``` ruby
204 require 'interpol/test_helper'
205
206 class MyAPIEndpointsTest < Test::Unit::TestCase
207 extend Interpol::TestHelper::TestUnit
f8e24d62 » myronmarston
2012-04-03 Fill out the readme some more.
208 define_interpol_example_tests
72f221a7 » myronmarston
2012-04-02 First pass at the README.
209 end
210 ```
211
d2182db9 » myronmarston
2012-04-04 Putting code in a section title looks ugly.
212 ### Interpol::StubApp
72f221a7 » myronmarston
2012-04-02 First pass at the README.
213
f8e24d62 » myronmarston
2012-04-03 Fill out the readme some more.
214 This will build a little sinatra app that returns example data from
215 your endpoint definition files.
72f221a7 » myronmarston
2012-04-02 First pass at the README.
216
f8e24d62 » myronmarston
2012-04-03 Fill out the readme some more.
217 Example:
72f221a7 » myronmarston
2012-04-02 First pass at the README.
218
219 ``` ruby
f8e24d62 » myronmarston
2012-04-03 Fill out the readme some more.
220 # config.ru
221
72f221a7 » myronmarston
2012-04-02 First pass at the README.
222 require 'interpol/stub_app'
223
f8e24d62 » myronmarston
2012-04-03 Fill out the readme some more.
224 # the block is only necessary if you want to override the default
225 # config or if you have not set a default config.
72f221a7 » myronmarston
2012-04-02 First pass at the README.
226 stub_app = Interpol::StubApp.build do |app|
227 app.endpoint_definition_files = Dir["config/endpoints_definitions/*.yml"]
228 app.api_version do |env|
f8e24d62 » myronmarston
2012-04-03 Fill out the readme some more.
229 RequestVersion.extract_from(env['HTTP_ACCEPT'])
72f221a7 » myronmarston
2012-04-02 First pass at the README.
230 end
231 end
232
233 run stub_app
234 ```
235
d2182db9 » myronmarston
2012-04-04 Putting code in a section title looks ugly.
236 ### Interpol::ResponseSchemaValidator
72f221a7 » myronmarston
2012-04-02 First pass at the README.
237
f8e24d62 » myronmarston
2012-04-03 Fill out the readme some more.
238 This rack middleware validates the responses from your app
239 against the schema definition. Here's an example of how you
240 might use it with a class-style sinatra app:
72f221a7 » myronmarston
2012-04-02 First pass at the README.
241
242 ``` ruby
243 require 'sinatra'
244
245 # You probably only want to validate the schema in local development.
246 unless ENV['RACK_ENV'] == 'production'
88ac7607 » myronmarston
2012-04-04 Fix require.
247 require 'interpol/response_schema_validator'
f8e24d62 » myronmarston
2012-04-03 Fill out the readme some more.
248
249 # the block is only necessary if you want to override the default
250 # config or if you have not set a default config.
251 use Interpol::ResponseSchemaValidator do |config|
72f221a7 » myronmarston
2012-04-02 First pass at the README.
252 config.endpoint_definition_files = Dir["config/endpoints_definitions/*.yml"]
253 config.api_version do |env|
f8e24d62 » myronmarston
2012-04-03 Fill out the readme some more.
254 RequestVersion.extract_from(env['HTTP_ACCEPT'])
72f221a7 » myronmarston
2012-04-02 First pass at the README.
255 end
256 end
257 end
258
259 get '/users/:user_id/projects' do
260 JSON.dump(User.find(params[:user_id]).projects)
261 end
262 ```
8933293f » myronmarston
2012-04-02 Initial Gem skeleton from bundler.
263
956385c5 » myronmarston
2012-04-09 Document the documentation app.
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
8933293f » myronmarston
2012-04-02 Initial Gem skeleton from bundler.
287 ## Contributing
288
289 1. Fork it
290 2. Create your feature branch (`git checkout -b my-new-feature`)
291 3. Commit your changes (`git commit -am 'Added some feature'`)
292 4. Push to the branch (`git push origin my-new-feature`)
293 5. Create new Pull Request
Something went wrong with that request. Please try again.