haveapi 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3eed7a7a97050e343134cb1d9cfd614099a613c6
4
- data.tar.gz: 09d4bc3e055b2d385b8e6bdf49140425852b4a6f
3
+ metadata.gz: 4fa0da1f1b314ff7278f68c3f6388579d963b21c
4
+ data.tar.gz: 7df0e7f2124286d109535b860e53f64c44a06b1c
5
5
  SHA512:
6
- metadata.gz: ed8241e6a1e8d65b41fb56671fe421730eaab16a748d8373d4331c06a5b14990e2e4a7b535919524bf655ab8a0ca0f6fccdb4c83932d9ec78ece6caffb7e9397
7
- data.tar.gz: 992ef4d404cdd0b07564b6bd9310c59280544a026382ec1a84b753586a8cab2482a293f72b3ea15b55f4dcd487181747b7abf14f2f04b880b057ea7b8bef7272
6
+ metadata.gz: 945c9596473a913973fc06bc1432a5c8c6cb6b921a780ab420eddea9036b281d81b117aabbaf911e3844c5f0391da728a45e00674a482dcd398ac5e3a02ac961
7
+ data.tar.gz: dd965f92e0c67a799e053fa9b3f5817e3c1b899127884d81372f3f40872df2751450001d4bfbfc525ed6b1f9d7100dd3f46a1ee78e77ad1ec3e1b7946691a6be
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ lib/bundler/man
11
+ pkg
12
+ rdoc
13
+ spec/reports
14
+ test/tmp
15
+ test/version_tmp
16
+ tmp
17
+ *.bundle
18
+ *.so
19
+ *.o
20
+ *.a
21
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'activerecord'
4
+ gem 'require_all'
5
+ gem 'json'
6
+ gem 'sinatra'
7
+ gem 'mysql'
8
+ gem 'sinatra-activerecord'
9
+ gem 'rake'
10
+ gem 'rspec'
11
+ gem 'rack-test'
12
+ gem 'railties'
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Jakub Skokan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,277 @@
1
+ HaveAPI
2
+ =======
3
+ A framework for creating self-describing APIs in Ruby.
4
+
5
+ Note: HaveAPI is under heavy development. It is not stable, its interface may change.
6
+
7
+ ## What is a self-describing API?
8
+ A self-describing API responds to HTTP method `OPTIONS` and returns description
9
+ of available resources and their actions. The description contains
10
+ full list of parameters, their labels, text notes, data types, validators
11
+ and example usage.
12
+
13
+ Clients use the self-description to learn how to communicate with the API,
14
+ which they otherwise know nothing about.
15
+
16
+ ## Main features
17
+ - Creates RESTful APIs
18
+ - Handles network communication, input/output formats and parameters
19
+ on both server and client, you need only to define resources and actions
20
+ - By writing the code you get the documentation which is available to all clients
21
+ - Auto-generated online HTML documentation
22
+ - Generic interface for clients - one client can be used to access all APIs
23
+ using this framework
24
+ - Ruby, PHP and JavaScript clients already available
25
+ - A change in the API is immediately reflected in all clients
26
+ - Supports API versioning
27
+ - Ready for ActiveRecord - validators from models are included in the
28
+ self-description
29
+
30
+ ## Usage
31
+ This text might not be complete or up-to-date, as things still often change.
32
+ Full use of HaveAPI may be seen
33
+ in [vpsadminapi](https://github.com/vpsfreecz/vpsadminapi), which may serve
34
+ as an example of how are things meant to be used.
35
+
36
+ All resources and actions are represented by classes. They all must be stored
37
+ in a module, whose name is later given to HaveAPI.
38
+
39
+ HaveAPI then searches all classes in that module and constructs your API.
40
+
41
+ For the purposes of this document, all resources will be in module `MyAPI`.
42
+
43
+ ### Example
44
+ This is a basic example, it does not show all options and functions.
45
+
46
+ Let's assume a model:
47
+
48
+ ```ruby
49
+ class User < ActiveRecord::Base
50
+ validates :login, :full_name, :role, presence: true
51
+ validates :login, format: {
52
+ with: /[a-zA-Z\.\-]{3,30}/,
53
+ message: 'not a valid login'
54
+ }, uniqueness: true
55
+ validates :role, inclusion: {
56
+ in: %w(admin user),
57
+ message '%{value} is not a valid role'
58
+ }
59
+
60
+ # An example authentication with plain text password
61
+ def self.authenticate(username, password)
62
+ u = User.find_by(login: username)
63
+
64
+ if u
65
+ u if u.password == password
66
+ end
67
+ end
68
+ end
69
+ ```
70
+
71
+ Resource user might look like this:
72
+ ```ruby
73
+ module MyAPI
74
+ class User < HaveAPI::Resource
75
+ # This resource belongs to version 1.
76
+ # It is also possible to put resource to multiple versions, e.g. [1, 2]
77
+ version 1
78
+
79
+ # Provide description for this resource
80
+ desc 'Manage users'
81
+
82
+ # ActiveRecord model to load validators from
83
+ model ::User
84
+
85
+ # Require authentication, this is the default
86
+ auth true
87
+
88
+ # Create a named group of shared params, that may be later included
89
+ # by actions.
90
+ params(:id) do
91
+ id :id, label: 'User ID'
92
+ end
93
+
94
+ params(:common) do
95
+ string :login, label: 'Login', desc: 'Used for authentication'
96
+ string :full_name, label: 'Full name'
97
+ string :role, label: 'User role', desc: 'admin or user'
98
+ end
99
+
100
+ # Actions
101
+ # Module HaveAPI::Actions::Default contains helper classes that define
102
+ # HTTP methods and routes for generic actions.
103
+ class Index < HaveAPI::Actions::Default::Index
104
+ desc 'List all users'
105
+
106
+ # There are no input parameters
107
+
108
+ # Output parameters
109
+ output(:object_list) do
110
+ use :id
111
+ use :common
112
+ end
113
+
114
+ # Determine if current user can use this action.
115
+ # allow/deny immediately returns from this block.
116
+ # Default rule is deny.
117
+ authorize do |u|
118
+ allow if u.role == 'admin'
119
+ deny # deny is implicit, so it may be omitted
120
+ end
121
+
122
+ # Provide example usage
123
+ example do
124
+ request({})
125
+ response({
126
+ users: [
127
+ {
128
+ id: 1,
129
+ login: 'myuser',
130
+ full_name: 'My Very Name'
131
+ }
132
+ ]
133
+ })
134
+ comment 'Get a list of all users like this'
135
+ end
136
+
137
+ # Helper method returning a query for all users
138
+ def query
139
+ ::User.all
140
+ end
141
+
142
+ # This method is called if the request has meta[:count] = true
143
+ def count
144
+ query.count
145
+ end
146
+
147
+ # Execute action, return the list
148
+ def exec
149
+ query.limit(input[:limit]).offset(input[:offset])
150
+ end
151
+ end
152
+
153
+ class Create < HaveAPI::Actions::Default::Create
154
+ desc 'Create new user'
155
+
156
+ input do
157
+ use :common
158
+ end
159
+
160
+ output do
161
+ use :id
162
+ use :common
163
+ end
164
+
165
+ authorize do |u|
166
+ allow if u.role == 'admin'
167
+ deny
168
+ end
169
+
170
+ example do
171
+ request({
172
+ user: {
173
+ login: 'anotherlogin',
174
+ full_name: 'My Very New Name'
175
+ }
176
+ })
177
+ response({
178
+ user: {
179
+ id: 2
180
+ }
181
+ })
182
+ comment 'Create new user like this'
183
+ end
184
+
185
+ def exec
186
+ user = ::User.new(input)
187
+
188
+ if user.save
189
+ ok(user)
190
+ else
191
+ error('save failed', user.errors.to_hash)
192
+ end
193
+ end
194
+ end
195
+ end
196
+ end
197
+ ```
198
+
199
+ ### What you get
200
+ From this piece of code, HaveAPI will generate a self-describing API.
201
+ It will contain resource `User` with actions `Index` and `Create`,
202
+ using which you can list existing users and create new ones.
203
+
204
+ You can use any of the available clients to work with the API.
205
+
206
+ ### Run the example
207
+ ```ruby
208
+ api = HaveAPI::Server.new(MyAPI)
209
+
210
+ # Use HTTP basic auth
211
+ class BasicAuth < HaveAPI::Authentication::Basic::Provider
212
+ def find_user(request, username, password)
213
+ User.authenticate(username, password)
214
+ end
215
+ end
216
+
217
+ api.use_version(:all)
218
+ api.set_default_version(1)
219
+ api.auth_chain << BasicAuth
220
+ api.mount('/')
221
+
222
+ api.start!
223
+ ```
224
+
225
+ This should start the application using WEBrick. Check
226
+ [http://localhost:4567](http://localhost:4567).
227
+
228
+ - `GET /` - a list of API versions
229
+ - `GET /doc` - HaveAPI documentation
230
+ - `GET /v1/` - documentation for version 1
231
+ - `OPTIONS /` - description for the whole API
232
+ - `OPTIONS /v1/` - description for API version 1
233
+
234
+ and more.
235
+
236
+ ### Run with rackup
237
+ Use the same code as above, only the last line would be
238
+
239
+ ```ruby
240
+ run api.app
241
+ ```
242
+
243
+ ## Authentication
244
+ HaveAPI defines an interface for creating authentication providers.
245
+ HTTP basic auth and token providers are built-in.
246
+
247
+ Authentication options are self-described. A client can choose what authentication
248
+ method it understands and wants to use.
249
+
250
+ ## Authorization
251
+ HaveAPI provides means for authorizing user access to actions. This process
252
+ is not self-described.
253
+
254
+ If the user is authenticated when requesting self-description, only allowed
255
+ resources, actions and parameters will be returned.
256
+
257
+ ## Available clients
258
+ These clients completely rely on the API description and can be used for all
259
+ APIs that are using HaveAPI.
260
+
261
+ - Ruby client library and CLI: https://github.com/vpsfreecz/haveapi-client
262
+ - PHP client: https://github.com/vpsfreecz/haveapi-client-php
263
+ - JavaScript client: https://github.com/vpsfreecz/haveapi-client-js
264
+
265
+ or [create your own client](doc/create-client.md).
266
+
267
+ ## Read more
268
+ - [Protocol definition](doc/protocol.md)
269
+ - [How to create a client](doc/create-client.md)
270
+
271
+ ## Contributing
272
+
273
+ 1. Fork it ( https://github.com/vpsfreecz/haveapi/fork )
274
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
275
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
276
+ 4. Push to the branch (`git push origin my-new-feature`)
277
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core'
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec) do |spec|
6
+ spec.pattern = FileList['spec/**/*_spec.rb']
7
+ end
@@ -0,0 +1,98 @@
1
+ # Client definition
2
+ It is necessary to differentiate between clients for HaveAPI based APIs
3
+ and clients to work with your API instance. This document describes
4
+ the former. If you only want to use your API, you should check a list
5
+ of available clients and pick the one in the right language. Only when
6
+ there isn't a client already available in the language you want, then
7
+ continue reading.
8
+
9
+ # Design rules
10
+ The client must completely depend on the API description:
11
+
12
+ - it has no assumptions and API-specific code,
13
+ - it does not know any resources, actions and parameters,
14
+ - everything the client knows must be found out from the API description.
15
+
16
+ All clients should use a similar paradigm, so that it is possible to use
17
+ clients in different languages in the same way, as far as the language syntax
18
+ allows. Clients bundled with HaveAPI may serve as a model. A client should
19
+ use all the advantages and coding styles of the language it is written
20
+ in (e.g. use objects in object oriented languages).
21
+
22
+ A model paradigm (in no particular language):
23
+
24
+ // Create client instance
25
+ api = new HaveAPI.Client("https://your.api.tld")
26
+
27
+ // Authenticate
28
+ api.authenticate("basic", {"user": "yourname", "password": "yourpassword"})
29
+
30
+ // Access resources and actions
31
+ api.<resource>.<action>( { <parameters> } )
32
+ api.user.new({"name": "Very Name", "password": "donottellanyone"})
33
+ api.user.list()
34
+ api.nested.resource.deep.list()
35
+
36
+ // Pass IDs to resources
37
+ api.nested(1).resource(2).deep.list()
38
+
39
+ // Object-like access
40
+ user = api.user.show(1)
41
+ user.id
42
+ user.name
43
+ user.destroy()
44
+
45
+ // Logout
46
+ api.logout()
47
+
48
+ # Necessary features to implement
49
+ A client should implement all of the listed features in order to be useful.
50
+
51
+ ## Resource tree
52
+ The client gives access to all listed resources and their actions.
53
+
54
+ In scripting languages, resources and actions are usually defined as dynamic
55
+ properties/objects/methods, depending on the language.
56
+
57
+ ## Input/output parameters
58
+ Allow sending input parameters and accessing the response.
59
+
60
+ ## Input/output formats
61
+ A client must send appropriate HTTP header `Accept`. As only JSON is by now built-in
62
+ in HaveAPI, it should send `application/json`.
63
+
64
+ ## Authentication
65
+ All authentication methods that are built-in the HaveAPI should be supported
66
+ if possible. The client should choose suitable authentication method
67
+ for its purpose and allow the developer to select the authentication method
68
+ if it makes sense to do so.
69
+
70
+ It is a good practise to implement authentication methods as plugins,
71
+ so that developers may add custom authentication providers easily.
72
+
73
+ ## Object-like access
74
+ A client must interpret the API response according to action output layout.
75
+ Layouts `object` and `object_list` should be handled as object instances,
76
+ if the language allows it.
77
+
78
+ Object instances represent the object fetched from the database. Received
79
+ parameters are accessed via object attributes/properties. Actions are defined
80
+ as instance methods. Objects may have associations to other resources which
81
+ must be made available and be easy to access.
82
+
83
+ # Supplemental features
84
+ Following features are supplemental. It is good to support them,
85
+ but is not necessary.
86
+
87
+ ## Client-side validations
88
+ Client may make use of described validators and validate the input before
89
+ sending it to the API, to lessen the API load and make it more user-friendly.
90
+
91
+ However, as the input is validated on the server anyway, it does not have
92
+ to be implemented.
93
+
94
+ ## Metadata channel
95
+ Metadata channel is currently used to specify what associated resources should
96
+ be prefetched and whether an object list should contain total number of items.
97
+
98
+ Metadata is nothing more than a hash in input parameters under key `_meta`.
data/doc/index.md ADDED
@@ -0,0 +1,6 @@
1
+ HaveAPI documentation
2
+ =====================
3
+
4
+ - [README](doc/readme)
5
+ - [Protocol definition](doc/protocol.md)
6
+ - [How to create a client](doc/create-client.md)
data/doc/protocol.md ADDED
@@ -0,0 +1,355 @@
1
+ # Protocol definition
2
+ HaveAPI defines the format for the self-description and URLs where the self-description
3
+ can be found.
4
+
5
+ ## Self-description
6
+ The API is self-describing. It documents itself. Clients use the self-description
7
+ to work with the API. The Self-description contains access URLs, HTTP methods,
8
+ input and output parameters and their validators.
9
+ A part of description is also an example usage and text notes.
10
+
11
+ The API responds to ``OPTIONS /``, which returns description of whole
12
+ API, containing all its versions. To get description only of selected version,
13
+ use e.g. ``OPTIONS /v1/``.
14
+
15
+ Every action also responds to HTTP method ``OPTIONS``,
16
+ with which you can get description for selected action. To distinguish actions with
17
+ the same URL, use parameter ``?method=HTTP_METHOD``.
18
+
19
+ Thanks to this ability, API changes immediately reflects in all clients without
20
+ changing a single line of code. A client can also be used on all APIs with compatible
21
+ self-describing format, without any changes at all.
22
+
23
+ ## Envelope
24
+ In addition to output format specified below, every API response
25
+ is wrapped in an envelope.
26
+ The envelope reports if action succeeded or failed, provides return value or error
27
+ messages.
28
+
29
+ {
30
+ "status": true if action succeeded or false if error occured,
31
+ "response": return value,
32
+ "message": error message, if status is false,
33
+ "errors: {
34
+ "parameter1": ["list", "of", "errors"],
35
+ "parameter2": ["and", "so", "on"]
36
+ }
37
+ }
38
+
39
+ ## Description format
40
+ In this document, the self-description is encoded in JSON. However, it can
41
+ be encoded in any of the supported output formats.
42
+
43
+ ### Version
44
+ Version is described as:
45
+
46
+ {
47
+ "authentication": {
48
+ ... authentication methods ...
49
+ },
50
+ "resources": {
51
+ ... resources ...
52
+ },
53
+ "meta": {
54
+ "namespace": "_meta"
55
+ },
56
+ "help": "/<version>/"
57
+ }
58
+
59
+ See appropriate section for detailed description of each section.
60
+
61
+ ### Authentication
62
+ HaveAPI defines an interface for implementing custom authentication methods.
63
+ HTTP basic and token authentication is built-in.
64
+
65
+ Authentication methods can be set per API version. They are a part of
66
+ the self-description, but must be understood by the client.
67
+ The client can choose whichever available authentication method he prefers.
68
+
69
+ #### HTTP basic authentication
70
+ HTTP basic authentication needs no other configuration, only informs about its presence.
71
+
72
+ "basic": {}
73
+
74
+ #### Token authentication
75
+ Token authentication contains a resource ``token``, that is used
76
+ to acquire and revoke token.
77
+
78
+ Token is acquired by action ``request``. The client provides login and password and gets a token
79
+ that is used afterwards. Token has a validity period, which may also be infinity.
80
+
81
+ Token can be revoked by calling the ``revoke`` action.
82
+
83
+ "token": {
84
+ "http_header": "<name of HTTP header to transfer token in, by default X-HaveAPI-Auth-Token>",
85
+ "query_parameter": "<name of query parameter for token, by default auth_token>",
86
+ "resources": {
87
+ "actions": {
88
+ "request": {
89
+ ...
90
+ "input": {
91
+ ...
92
+ "parameters": {
93
+ "login": ...
94
+ "password": ...
95
+ "lifetime": ...
96
+ "interval": ...
97
+ },
98
+ ...
99
+ },
100
+ "output": {
101
+ ...
102
+ "parameters": {
103
+ "token": ...
104
+ "valid_to": ...
105
+ },
106
+ ...
107
+ },
108
+ ...
109
+ }
110
+ "revoke": ...
111
+ }
112
+ }
113
+ }
114
+
115
+ The format for ``resources`` section is the same as for any other resource.
116
+
117
+ ### Resources
118
+ Each resource is described as:
119
+
120
+ "<resource_name>": {
121
+ "description": "Some description that explains everything",
122
+ "actions": {
123
+ ... actions ...
124
+ },
125
+ "resources": {
126
+ ... nested resources ...
127
+ }
128
+ }
129
+
130
+ ### Actions
131
+ Every action is described as:
132
+
133
+ "<action_name>": {
134
+ "auth": true|false,
135
+ "description": "Describe what this action does",
136
+ "aliases": ["list", "of", "aliases"],
137
+ "input": {
138
+ "layout": "layout type",
139
+ "namespace": "namespace name",
140
+ "parameters": {
141
+ ... parameters ...
142
+ }
143
+ },
144
+ "output": {
145
+ "layout": "layout type",
146
+ "namespace": "namespace name",
147
+ "parameters": {
148
+ ... parameters ...
149
+ }
150
+ },
151
+ "examples": [
152
+ ... list of examples ...
153
+ ],
154
+ "meta": ... metadata ...,
155
+ "url": "URL for this action",
156
+ "method": "HTTP method to be used",
157
+ "help": "URL to get this very description of the action"
158
+ }
159
+
160
+ #### Layouts
161
+ Layout type is specified for input/output parameters. Thanks to the layout type,
162
+ clients know how to send the request and how to interpret the response.
163
+
164
+ Defined layout types:
165
+
166
+ - object - mainly the response is to be treated as an instance of a resource
167
+ - object_list - list of objects
168
+ - hash - simply a hash of parameters, it is to be treated as such
169
+ - hash_list - list of hashes
170
+
171
+ In client libraries, the ``object`` layout output usually results in returning
172
+ an object that represents the instance of the resource. The parameters are defined
173
+ as object properties and the like.
174
+
175
+ #### Namespace
176
+ All input/output parameters are put in a namespace, which is usually
177
+ the name of the resource.
178
+
179
+ For example:
180
+
181
+ {
182
+ "user": {
183
+ ... parameters ...
184
+ }
185
+ }
186
+
187
+ ### Parameters
188
+ There are two parameter types.
189
+
190
+ #### Data types
191
+ The type can be one of:
192
+
193
+ - String
194
+ - Text
195
+ - Boolean
196
+ - Integer
197
+ - Float
198
+ - Datetime
199
+
200
+ "<parameter_name>": {
201
+ "required": true/false/null,
202
+ "label": "Label for this parameter",
203
+ "description": "Describe it's meaning",
204
+ "type": "<one of the data types>",
205
+ "choices": a list or a hash of accepted values
206
+ "validators": ... validators ...,
207
+ "default": "default value that is used if the parameter is omitted"
208
+ }
209
+
210
+ If the choices are in a list, than it is a list of accepted values.
211
+ If the choices are in a hash, the keys of that hash are accepted values,
212
+ values in that hash are to be shown in UI.
213
+
214
+ #### Resource association
215
+ This is used for associations between resources, e.g. car has a wheel.
216
+
217
+ "<parameter_name>": {
218
+ "required": true/false/null,
219
+ "label": "Label for this parameter",
220
+ "description": "Describe it's meaning",
221
+ "type": "Resource",
222
+ "resource": ["path", "to", "resource"],
223
+ "value_id": "<name of a parameter that is used as an id>",
224
+ "value_label": "<name of a parameter that is used as a value>",
225
+ "value": {
226
+ "url": "URL to 'show' action of associated resource",
227
+ "method": "HTTP method to use",
228
+ "help": "URL to get the associated resource's 'show' description"
229
+ },
230
+ "choices": {
231
+ "url": "URL to action that returns a list of possible associations",
232
+ "method": "HTTP method to use",
233
+ "help": "URL to description of the list action"
234
+ }
235
+ }
236
+
237
+ The _resource_ type also has a different output in action response. It returns
238
+ a hash containing associated resource ID and its label, so that clients
239
+ can show the human-friendly label instead of just an ID.
240
+
241
+ "<parameter_name>": {
242
+ "<value of value_id from description>": <resource id>,
243
+ "<value of value_label from description>": "<label>"
244
+ }
245
+
246
+ ### Examples
247
+ Examples are described in a generic way, so that every client can
248
+ render them according to its syntax.
249
+
250
+ {
251
+ "title": "A title",
252
+ "request": {
253
+ ... a hash of request parameters ...
254
+ },
255
+ "response": {
256
+ ... a hash of response parameters ...
257
+ },
258
+ "comment": "Description of the example"
259
+ }
260
+
261
+ ### Metadata
262
+ Metadata can be global and per-object. Global metadata are sent once for each
263
+ response, where as per-object are sent with each object that is a part of the
264
+ response.
265
+
266
+ {
267
+ "global": {
268
+ "input": ... parameters or null ...,
269
+ "output: ... parameters or null ...
270
+ } or null,
271
+
272
+ "object": {
273
+ "input": ... parameters or null ...,
274
+ "output: ... parameters or null ...
275
+ } or null,
276
+ }
277
+
278
+ ### List API versions
279
+ Send request ``OPTIONS /?describe=versions``. The description format:
280
+
281
+ {
282
+ "versions": [1, 2, 3, ... list of versions],
283
+ "default": <which version is default>
284
+ }
285
+
286
+ ### Describe default version
287
+ Send request ``OPTIONS /?describe=default`` the get the description
288
+ of the default version.
289
+
290
+ ### Describe the whole API
291
+ It is possible to get self-description of all versions at once.
292
+
293
+ Send request ``OPTIONS /``. The description format:
294
+
295
+ {
296
+ "default_version": <which version is default>,
297
+ "versions": {
298
+ "default": ... full version self-description ...,
299
+ "<version>": ... full version self-description,
300
+ ... all other versions ...
301
+ }
302
+ }
303
+
304
+ ## Authorization
305
+ Actions may require different levels of authorization. HaveAPI provides means for
306
+ implementing authorization, but it is not self-described.
307
+
308
+ If the user is authenticated when requesting self-description, only allowed
309
+ resources/actions/parameters will be returned.
310
+
311
+ ## Input/output formats
312
+ For now, the only supported input format is JSON.
313
+
314
+ Output format can be chosen by a client. However, no other format than JSON is built-in.
315
+ The output format can be chosen with HTTP header ``Accept``.
316
+
317
+ ## Request
318
+ Action URL and HTTP method the client learns from the self-description.
319
+
320
+ Example request:
321
+
322
+ POST /users HTTP/1.1
323
+ Content-Type: application/json
324
+ Accept: application/json
325
+ Connection: Close
326
+
327
+ {
328
+ "user": {
329
+ "login": "mylogin",
330
+ "name": "Very Name",
331
+ "role": "admin"
332
+ }
333
+ }
334
+
335
+ ## Response
336
+ Clients know how to interpret the response thanks to the layout type they learn
337
+ from the self-description.
338
+
339
+ Example response to the request above:
340
+
341
+ Content-Type: application/json
342
+
343
+ {
344
+ "status": true,
345
+ "response": {
346
+ "user": {
347
+ "id": 1,
348
+ "login": "mylogin",
349
+ "name": "Very Name",
350
+ "role": "admin"
351
+ }
352
+ },
353
+ "message": null,
354
+ "errors: null
355
+ }
data/haveapi.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'haveapi/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'haveapi'
7
+ s.version = HaveAPI::VERSION
8
+ s.date = '2015-08-13'
9
+ s.summary =
10
+ s.description = 'Framework for creating self-describing APIs'
11
+ s.authors = 'Jakub Skokan'
12
+ s.email = 'jakub.skokan@vpsfree.cz'
13
+ s.files = `git ls-files -z`.split("\x0")
14
+ s.license = 'MIT'
15
+
16
+ s.required_ruby_version = '~> 2.0'
17
+
18
+ s.add_runtime_dependency 'activerecord', '~> 4.1.6'
19
+ s.add_runtime_dependency 'require_all'
20
+ s.add_runtime_dependency 'json'
21
+ s.add_runtime_dependency 'sinatra'
22
+ s.add_runtime_dependency 'mysql'
23
+ s.add_runtime_dependency 'sinatra-activerecord'
24
+ s.add_runtime_dependency 'rake'
25
+ s.add_runtime_dependency 'github-markdown', '~> 0.6.6'
26
+
27
+ s.add_development_dependency 'rspec'
28
+ s.add_development_dependency 'railties'
29
+ s.add_development_dependency 'rack-test'
30
+ end
@@ -1,3 +1,3 @@
1
1
  module HaveAPI
2
- VERSION = '0.3.0'
2
+ VERSION = '0.3.1'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: haveapi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jakub Skokan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-15 00:00:00.000000000 Z
11
+ date: 2015-08-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -170,6 +170,15 @@ executables: []
170
170
  extensions: []
171
171
  extra_rdoc_files: []
172
172
  files:
173
+ - .gitignore
174
+ - Gemfile
175
+ - LICENSE.txt
176
+ - README.md
177
+ - Rakefile
178
+ - doc/create-client.md
179
+ - doc/index.md
180
+ - doc/protocol.md
181
+ - haveapi.gemspec
173
182
  - lib/haveapi.rb
174
183
  - lib/haveapi/action.rb
175
184
  - lib/haveapi/actions/default.rb
@@ -186,7 +195,6 @@ files:
186
195
  - lib/haveapi/example.rb
187
196
  - lib/haveapi/extensions/action_exceptions.rb
188
197
  - lib/haveapi/extensions/base.rb
189
- - lib/haveapi/extensions/resource_prefetch.rb
190
198
  - lib/haveapi/hooks.rb
191
199
  - lib/haveapi/metadata.rb
192
200
  - lib/haveapi/model_adapter.rb
@@ -235,7 +243,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
235
243
  version: '0'
236
244
  requirements: []
237
245
  rubyforge_project:
238
- rubygems_version: 2.2.2
246
+ rubygems_version: 2.2.5
239
247
  signing_key:
240
248
  specification_version: 4
241
249
  summary: Framework for creating self-describing APIs
@@ -1,7 +0,0 @@
1
- module HaveAPI::Extensions
2
- class ResourcePrefetch < Base
3
- def self.enabled
4
-
5
- end
6
- end
7
- end