haveapi 0.3.0 → 0.3.1

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.
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