apipie-rails 0.0.13 → 0.0.14

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.
Files changed (63) hide show
  1. data/Gemfile.lock +5 -3
  2. data/README.rst +688 -0
  3. data/apipie-rails.gemspec +2 -4
  4. data/app/controllers/apipie/apipies_controller.rb +73 -41
  5. data/app/views/apipie/apipies/index.html.erb +10 -3
  6. data/app/views/apipie/apipies/method.html.erb +5 -2
  7. data/app/views/apipie/apipies/resource.html.erb +10 -3
  8. data/lib/apipie-rails.rb +1 -0
  9. data/lib/apipie/apipie_module.rb +28 -79
  10. data/lib/apipie/application.rb +194 -97
  11. data/lib/apipie/client/generator.rb +5 -4
  12. data/lib/apipie/configuration.rb +112 -0
  13. data/lib/apipie/dsl_definition.rb +93 -16
  14. data/lib/apipie/extractor.rb +12 -5
  15. data/lib/apipie/extractor/collector.rb +1 -1
  16. data/lib/apipie/extractor/recorder.rb +2 -1
  17. data/lib/apipie/extractor/writer.rb +11 -4
  18. data/lib/apipie/helpers.rb +15 -4
  19. data/lib/apipie/markup.rb +3 -4
  20. data/lib/apipie/method_description.rb +28 -22
  21. data/lib/apipie/resource_description.rb +44 -42
  22. data/lib/apipie/routing.rb +3 -1
  23. data/lib/apipie/static_dispatcher.rb +0 -1
  24. data/lib/apipie/version.rb +1 -1
  25. data/lib/generators/apipie/install/README +6 -0
  26. data/lib/generators/apipie/install/install_generator.rb +25 -0
  27. data/lib/generators/apipie/install/templates/initializer.rb.erb +7 -0
  28. data/lib/tasks/apipie.rake +31 -39
  29. data/spec/controllers/api/v1/architectures_controller_spec.rb +30 -0
  30. data/spec/controllers/api/v2/architectures_controller_spec.rb +12 -0
  31. data/spec/controllers/apipies_controller_spec.rb +18 -12
  32. data/spec/controllers/users_controller_spec.rb +56 -19
  33. data/spec/dummy/app/controllers/api/base_controller.rb +4 -0
  34. data/spec/dummy/app/controllers/api/v1/architectures_controller.rb +32 -0
  35. data/spec/dummy/app/controllers/api/v1/base_controller.rb +11 -0
  36. data/spec/dummy/app/controllers/api/v2/architectures_controller.rb +32 -0
  37. data/spec/dummy/app/controllers/api/v2/base_controller.rb +11 -0
  38. data/spec/dummy/app/controllers/twitter_example_controller.rb +1 -1
  39. data/spec/dummy/app/controllers/users_controller.rb +2 -3
  40. data/spec/dummy/config/initializers/apipie.rb +29 -6
  41. data/spec/lib/method_description_spec.rb +29 -0
  42. data/spec/lib/param_description_spec.rb +41 -0
  43. data/spec/lib/resource_description_spec.rb +28 -0
  44. data/spec/spec_helper.rb +1 -1
  45. metadata +99 -164
  46. data/README.rdoc +0 -367
  47. data/lib/apipie/client/base.rb +0 -133
  48. data/lib/apipie/client/cli_command.rb +0 -130
  49. data/lib/apipie/client/main.rb +0 -101
  50. data/lib/apipie/client/rest_client_oauth.rb +0 -19
  51. data/lib/apipie/client/template/Gemfile.tt +0 -3
  52. data/lib/apipie/client/template/README.tt +0 -3
  53. data/lib/apipie/client/template/Rakefile.tt +0 -2
  54. data/lib/apipie/client/template/a_name.gemspec.tt +0 -23
  55. data/lib/apipie/client/template/bin/bin.rb.tt +0 -30
  56. data/lib/apipie/client/template/lib/a_name.rb.tt +0 -27
  57. data/lib/apipie/client/template/lib/a_name/commands/cli.rb.tt +0 -22
  58. data/lib/apipie/client/template/lib/a_name/config.yml +0 -6
  59. data/lib/apipie/client/template/lib/a_name/resources/resource.rb.tt +0 -22
  60. data/lib/apipie/client/template/lib/a_name/version.rb.tt +0 -3
  61. data/lib/apipie/client/thor.rb +0 -21
  62. data/rubygem-apipie-rails.spec +0 -122
  63. data/spec/lib/parameter_description_spec.rb +0 -41
@@ -1,367 +0,0 @@
1
- = API Documentation Tool {<img src="https://secure.travis-ci.org/Pajk/apipie-rails.png?branch=master" alt="Build Status" />}[http://travis-ci.org/Pajk/apipie-rails]
2
-
3
- == What?
4
-
5
- Every API needs a documentation otherwise no one know how to use it.
6
- It is not easy to maintain such documentation always up to date if it
7
- develops over time. Additionaly to this most programmers don't like writing
8
- documentation and so it could happen that your API is useless because
9
- of outdated documentation. If the documentation is just text completely
10
- separated from code then there is no simple way to verify its correctness.
11
-
12
- This gem adds some new methods to Rails controllers that can be used
13
- to describe resources which are exposed by our API. It is meant to
14
- be used for {RESTful}[http://cs.wikipedia.org/wiki/Representational_State_Transfer]
15
- web services and because we are talking about Rails you probably know
16
- what it is all about.
17
-
18
- Informations you entered with provided DSL are used to generate
19
- online documentation and validate values of incoming requests parameters.
20
-
21
- == Why?
22
-
23
- Documentation will be closer to your code and thus less prone to become
24
- obsolete. You get documentation frontend without effort. And if you want your
25
- own design you can do it anytime because json API for your API documentation
26
- is provided. There are no limits on how to use those informations, the
27
- builtin web interface is only one of possible options.
28
-
29
- Request parameters will be validated before they will get in touch with yours
30
- controller action or model code. And you inform API users about expected
31
- parameters values. This information will be always actual because otherwise
32
- your tests fail (of course you have tests!).
33
-
34
- This is how the web interface look like. Try it live on
35
- http://restapi-likes.rhcloud.com. Example users resource
36
- description are taken from Twitter(c) API.
37
-
38
- https://img.skitch.com/20120428-nruk3e87xs2cu4ydsjujdh11fq.png
39
-
40
- https://img.skitch.com/20120428-bni2cmq5cyhjuw1jkd78e3qjxn.png
41
-
42
- == How?
43
-
44
- === Gemfile
45
-
46
- Add +apipie+ gem to your gemfile and run bundle.
47
-
48
- gem 'apipie-rails'
49
-
50
- For bleeding edge version use GitHub version
51
-
52
- gem 'apipie-rails', :git => 'git://github.com/Pajk/apipie-rails.git'
53
-
54
- === Config file
55
-
56
- Create configuration file in e.g. */config/initializers/apipie.rb*.
57
- You can set application name, footer text, API and documentation base URL
58
- and turn off validations. You can also choose your favorite markup language
59
- of full descriptions.
60
-
61
- [app_name] Name of your application used in breadcrumbs navigation.
62
- [copyright] Copyright information (shown in page footer).
63
- [doc_base_url] Documentation frontend base url.
64
- [api_base_url] Base url of your API, most probably /api.
65
- [validate] Parameters validation is turned off when set to false.
66
- [app_info] Application long description.
67
- [reload_controllers] Set to enable/disable reloading controllers (and the documentation with it), by default enabled in development.
68
- [api_controllers_matcher] For reloading to work properly you need to specify where your API controllers are.
69
- [markup] You can choose markup language for descriptions of your application,
70
- resources and methods. RDoc is the default but you can choose from
71
- Apipie::Markup::Markdown.new or Apipie::Markup::Textile.new.
72
- In order to use Markdown you need Redcarpet gem and for Textile you
73
- need RedCloth. Add those to your gemfile and run bundle if you
74
- want to use them. You can also add any other markup language
75
- processor.
76
- [layout] Name of a layout template to use instead of Apipie's layout. You can use Apipie.include_stylesheets and Apipie.include_javascripts helpers to include Apipie's stylesheets and javascripts.
77
-
78
- Example:
79
-
80
- Apipie.configure do |config|
81
- config.app_name = "Test app"
82
- config.copyright = "&copy; 2012 Pavel Pokorny"
83
- config.doc_base_url = "/apidoc"
84
- config.api_base_url = "/api"
85
- config.validate = false
86
- config.markup = Apipie::Markup::Markdown.new
87
- config.reload_controllers = true
88
- config.api_controllers_matcher = File.join(Rails.root, "app", "controllers", "**","*.rb")
89
- config.app_info = <<-DOC
90
- This is where you can inform user about your application and API
91
- in general.
92
- DOC
93
- end
94
-
95
- === Routes
96
-
97
- Add +apipie+ to your *routes.rb*, that's all.
98
-
99
-
100
- === Resource Description
101
-
102
- Resource can be described in corresponding controller by calling +resource_description+ method with block. Parameters described here are used
103
- for every method unless they are overridden with NilValidator.
104
- Parameters are inherited in controller hierarchy. So for example you can define
105
- in base ApplicationController parameters for authentication and they will
106
- be checked in every request.
107
-
108
- [name] You can force resource to display under some alias.
109
- [short] One line short description.
110
- [path] Relative URL path of this resource.
111
- [version] Version of this resource API, use arbitrary string.
112
- [formats] Resource level request / response formats.
113
- [param] The very same parameter description as you will use method
114
- description. Generally use this for parameters that apply
115
- to every method in the controller (such as :user hash).
116
- It is possible to hide it for individual methods by setting
117
- it's validator to nil.
118
- [description] The full multiline description of the resource and
119
- yours API options
120
-
121
- Example:
122
-
123
- class UsersController < ApplicationController
124
-
125
- resource_description do
126
- name 'Members'
127
- short 'Site members'
128
- path '/users'
129
- version '1.0 - 3.4.2012'
130
- formats ['json', 'xml']
131
- param :id, Fixnum, :desc => "User ID", :required => false
132
- param :user, Hash, :desc => 'Param description for all methods' do
133
- param :username, String, :required => true,
134
- :desc => "Username for login"
135
- param :password, String, :required => true,
136
- :desc => "Password for login"
137
- end
138
- description <<-DOC
139
- Full description of this resource.
140
- DOC
141
- end
142
- #...
143
- end
144
-
145
-
146
- === Method Description
147
-
148
- Then describe methods available to your API.
149
-
150
- [api] Say how is this method exposed and provide short description.
151
- The first parameter is HTTP method (one of :GET/:POST/:PUT/:DELETE).
152
- The second parameter is relative URL path which is mapped to this
153
- method. The last parameter is methods short description.
154
- You can use this +api+ method more than once for one method. It could
155
- be useful when there are more routes mapped to it.
156
- [param] Look at Parameter description section for details.
157
- [formats] Method level request / response formats.
158
- [error] Describe each possible error that can happend what calling this
159
- method. HTTP response code and description can be provided.
160
- [description] Full method description which will be converted to HTML by
161
- choosen markup language processor.
162
- [example] Provide example of server response, whole communication or response type.
163
- It will be formatted as code.
164
- [see] Provide reference to another method, this has to be string with
165
- controller_name#method_name.
166
-
167
- Example:
168
-
169
- api :GET, "/users/:id", "Show user profile"
170
- error :code => 401, :desc => "Unauthorized"
171
- error :code => 404, :desc => "Not Found"
172
- param :session, String, :desc => "user is logged in", :required => true
173
- param :regexp_param, /^[0-9]* years/, :desc => "regexp param"
174
- param :array_param, [100, "one", "two", 1, 2], :desc => "array validator"
175
- param :boolean_param, [true, false], :desc => "array validator with boolean"
176
- param :proc_param, lambda { |val|
177
- val == "param value" ? true : "The only good value is 'param value'."
178
- }, :desc => "proc validator"
179
- description "method description"
180
- formats ['json', 'jsonp', 'xml']
181
- example " 'user': {...} "
182
- see "users#showme"
183
- def show
184
- #...
185
- end
186
-
187
- == Parameter Description
188
-
189
- Use +param+ to describe every possible parameter. You can use Hash validator
190
- in cooperation with block given to param method to describe nested parameters.
191
-
192
- [name] The first argument is parameter name as a symbol.
193
- [validator] Second parameter is parameter validator, choose one from section
194
- Validators.
195
- [desc] Parameter description.
196
- [required] Set this true/false to make it required/optional.
197
- Default is optional
198
-
199
- Example:
200
-
201
- param :user, Hash, :desc => "User info" do
202
- param :username, String, :desc => "Username for login", :required => true
203
- param :password, String, :desc => "Password for login", :required => true
204
- param :membership, ["standard","premium"], :desc => "User membership"
205
- end
206
- def create
207
- #...
208
- end
209
-
210
-
211
- == Validators
212
-
213
- Every parameter needs to have associated validator. For now there are some
214
- basic validators. You can always provide your own to reach complex
215
- results.
216
- If validations are enabled (default state) the parameters of every
217
- request are validated. If the value is wrong a +ArgumentError+ exception
218
- is raised and can be rescued and processed. It contains some description
219
- of parameter value expectations. Validations can be turned off
220
- in configuration file.
221
-
222
- === TypeValidator
223
-
224
- Check the parameter type. Only String, Hash and Array are supported
225
- for the sake of simplicity. Read more to to find out how to add
226
- your own validator.
227
-
228
- param :session, String, :desc => "user is logged in", :required => true
229
- param :facts, Hash, :desc => "Additional optional facts about the user"
230
-
231
- === RegexpValidator
232
-
233
- Check parameter value against given regular expression.
234
-
235
- param :regexp_param, /^[0-9]* years/, :desc => "regexp param"
236
-
237
- === ArrayValidator
238
-
239
- Check if parameter value is included given array.
240
-
241
- param :array_param, [100, "one", "two", 1, 2], :desc => "array validator"
242
-
243
- === ProcValidator
244
-
245
- If you need more complex validation and you know you won't reuse it you
246
- can use Proc/lambda validator. Provide your own Proc taking value
247
- of parameter as the only argument. Return true if value pass validation
248
- or return some text about what is wrong. _Don't use the keyword *return*
249
- if you provide instance of Proc (with lambda it is ok), just use the last
250
- statement return property of ruby_.
251
-
252
- param :proc_param, lambda { |val|
253
- val == "param value" ? true : "The only good value is 'param value'."
254
- }, :desc => "proc validator"
255
-
256
- === HashValidator
257
-
258
- You can describe hash parameters in depth if you provide a block with
259
- description of nested values.
260
-
261
- param :user, Hash, :desc => "User info" do
262
- param :username, String, :desc => "Username for login", :required => true
263
- param :password, String, :desc => "Password for login", :required => true
264
- param :membership, ["standard","premium"], :desc => "User membership"
265
- end
266
-
267
- === NilValidator
268
-
269
- In fact there is any NilValidator but setting it to nil can be used to
270
- override parameters described on resource level.
271
-
272
- Example:
273
-
274
- param :user, nil
275
- def destroy
276
- #...
277
- end
278
-
279
- === Adding custom validator
280
-
281
- Only basic validators are included but it is really easy to add your own.
282
- Create new initializer with subclass of Apipie::Validator::BaseValidator.
283
- Two methods are required to implement - instance method
284
- <tt>validate(value)</tt> and class method
285
- <tt>build(param_description, argument, options, block)</tt>.
286
-
287
- When searching for validator +build+ method of every subclass of
288
- Apipie::Validator::BaseValidator is called. The first one whitch return
289
- constructed validator object is used.
290
-
291
- Example: Adding IntegerValidator
292
-
293
- We want to check if parameter value is an integer like this:
294
-
295
- param :id, Integer, :desc => "Company ID"
296
-
297
- So we create apipie_validators.rb initializer with this content:
298
-
299
- class IntegerValidator < Apipie::Validator::BaseValidator
300
-
301
- def initialize(param_description, argument)
302
- super(param_description)
303
- @type = argument
304
- end
305
-
306
- def validate(value)
307
- return false if value.nil?
308
- !!(value.to_s =~ /^[-+]?[0-9]+$/)
309
- end
310
-
311
- def self.build(param_description, argument, options, block)
312
- if argument == Integer || argument == Fixnum
313
- self.new(param_description, argument)
314
- end
315
- end
316
-
317
- def description
318
- "Must be #{@type}."
319
- end
320
- end
321
-
322
- Parameters of the build method:
323
-
324
- [param_description] Instance of Apipie::ParamDescription contains all
325
- given informations about validated parameter.
326
- [argument] Specified validator, in our example it is +Integer+
327
- [options] Hash with specified options, for us just
328
- <tt>{:desc => "Company ID"}</tt>
329
- [block] Block converted into Proc, use it as you desire. In this example nil.
330
-
331
-
332
- == Markup
333
-
334
- The default markup language is {RDoc}[http://rdoc.rubyforge.org/RDoc/Markup.html]. It can be changed in
335
- config file (config.markup=) to one of these:
336
- [Markdown] Use Apipie::Markup::Markdown.new. You need Redcarpet gem.
337
- [Textile] Use Apipie::Markup::Textile.new. You need RedCloth gem.
338
-
339
- Or provide you own object with <tt>to_html(text)</tt> method.
340
- For inspiration this is how Textile look like:
341
-
342
- class Textile
343
- def initialize
344
- require 'RedCloth'
345
- end
346
- def to_html(text)
347
- RedCloth.new(text).to_html
348
- end
349
- end
350
-
351
- == Static page
352
-
353
- To generate static version of documentation run <tt>rake apipie:static</tt> task.
354
- It will create folder with one-page documentation in your public directory. Rename
355
- or delete it if you want to use 'normal' dynamic version again.
356
-
357
- == {CLI client}[https://github.com/Pajk/apipie-rails/wiki/CLI-client]
358
-
359
- == {Extractor}[https://github.com/Pajk/apipie-rails/wiki/Extractor]
360
-
361
- == Authors
362
-
363
- {Pajk}[https://github.com/Pajk] and {iNecas}[https://github.com/iNecas]
364
-
365
- == Contributors
366
-
367
- See {Contributors page}[https://github.com/Pajk/apipie-rails/graphs/contributors]. Special thanks to all of them!
@@ -1,133 +0,0 @@
1
- require 'rest_client'
2
- require 'oauth'
3
- require 'json'
4
- require 'apipie/client/rest_client_oauth'
5
-
6
- module Apipie
7
- module Client
8
-
9
- class Base
10
- attr_reader :client, :config
11
-
12
- def initialize(config, options = { })
13
- @client = RestClient::Resource.new config[:base_url],
14
- :user => config[:username],
15
- :password => config[:password],
16
- :oauth => config[:oauth],
17
- :headers => { :content_type => 'application/json',
18
- :accept => 'application/json' }
19
- @config = config
20
- end
21
-
22
- def call(method, path, params = { }, headers = { })
23
- headers ||= { }
24
-
25
- args = [method]
26
- if [:post, :put].include?(method)
27
- args << params.to_json
28
- else
29
- headers[:params] = params if params
30
- end
31
-
32
- args << headers if headers
33
- process_data client[path].send(*args)
34
- end
35
-
36
- def self.doc
37
- raise NotImplementedError
38
- end
39
-
40
- def self.validation_hash(method)
41
- validation_hashes[method.to_s]
42
- end
43
-
44
- def self.method_doc(method)
45
- method_docs[method.to_s]
46
- end
47
-
48
- def validate_params!(params, rules)
49
- return unless params.is_a?(Hash)
50
-
51
- invalid_keys = params.keys.map(&:to_s) - (rules.is_a?(Hash) ? rules.keys : rules)
52
- raise ArgumentError, "Invalid keys: #{invalid_keys.join(", ")}" unless invalid_keys.empty?
53
-
54
- if rules.is_a? Hash
55
- rules.each do |key, sub_keys|
56
- validate_params!(params[key], sub_keys) if params[key]
57
- end
58
- end
59
- end
60
-
61
- protected
62
-
63
- def process_data(response)
64
- data = begin
65
- JSON.parse(response.body)
66
- rescue JSON::ParserError
67
- response.body
68
- end
69
- return data, response
70
- end
71
-
72
- def check_params(params, options = { })
73
- raise ArgumentError unless (method = options[:method])
74
- return unless config[:enable_validations]
75
-
76
- case options[:allowed]
77
- when true
78
- validate_params!(params, self.class.validation_hash(method))
79
- when false
80
- raise ArgumentError, "this method '#{method}' does not support params" if params && !params.empty?
81
- else
82
- raise ArgumentError, "options :allowed should be true or false, it was #{options[:allowed]}"
83
- end
84
- end
85
-
86
- # @return url and rest of the params
87
- def fill_params_in_url(url, params)
88
- params ||= { }
89
- # insert param values
90
- url_param_names = params_in_path(url)
91
- url = params_in_path(url).inject(url) do |url, param_name|
92
- param_value = params[param_name] or
93
- raise ArgumentError, "missing param '#{param_name}' in parameters"
94
- url.sub(":#{param_name}", param_value.to_s)
95
- end
96
-
97
- return url, params.reject { |param_name, _| url_param_names.include? param_name }
98
- end
99
-
100
- private
101
-
102
- def self.method_docs
103
- @method_docs ||= doc['methods'].inject({ }) do |hash, method|
104
- hash[method['name']] = method
105
- hash
106
- end
107
- end
108
-
109
- def self.validation_hashes
110
- @validation_hashes ||= method_docs.inject({ }) do |hash, pair|
111
- name, method_doc = pair
112
- hash[name] = construct_validation_hash method_doc
113
- hash
114
- end
115
- end
116
-
117
- def self.construct_validation_hash(method)
118
- if method['params'].any? { |p| p['params'] }
119
- method['params'].reduce({ }) do |h, p|
120
- h.update(p['name'] => (p['params'] ? p['params'].map { |pp| pp['name'] } : nil))
121
- end
122
- else
123
- method['params'].map { |p| p['name'] }
124
- end
125
- end
126
-
127
- def params_in_path(url)
128
- url.scan(/:([^\/]*)/).map { |m| m.first }
129
- end
130
-
131
- end
132
- end
133
- end