openapi_rest 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +141 -0
- data/Rakefile +11 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/generators/openapi_rest/install_generator.rb +11 -0
- data/lib/generators/openapi_rest/openapi_doc.rb +3 -0
- data/lib/generators/templates/api_docs.yml +162 -0
- data/lib/openapi_rest.rb +22 -0
- data/lib/openapi_rest/api_config.rb +12 -0
- data/lib/openapi_rest/api_doc.rb +19 -0
- data/lib/openapi_rest/api_doc_parser.rb +110 -0
- data/lib/openapi_rest/api_model.rb +36 -0
- data/lib/openapi_rest/api_parameters.rb +76 -0
- data/lib/openapi_rest/api_validator.rb +20 -0
- data/lib/openapi_rest/extension.rb +35 -0
- data/lib/openapi_rest/operations/filter.rb +24 -0
- data/lib/openapi_rest/operations/paginate.rb +19 -0
- data/lib/openapi_rest/operations/sort.rb +27 -0
- data/lib/openapi_rest/query_builder.rb +70 -0
- data/lib/openapi_rest/query_response.rb +89 -0
- data/lib/openapi_rest/railtie.rb +9 -0
- data/lib/openapi_rest/rest_renderer.rb +75 -0
- data/lib/openapi_rest/validators/format.rb +24 -0
- data/lib/openapi_rest/validators/pattern.rb +21 -0
- data/lib/openapi_rest/version.rb +3 -0
- data/test/openapi_rest/api_config_test.rb +9 -0
- data/test/openapi_rest/api_doc_parser_test.rb +71 -0
- data/test/openapi_rest/api_doc_test.rb +15 -0
- data/test/openapi_rest/api_model_test.rb +49 -0
- data/test/openapi_rest/api_parameters_test.rb +57 -0
- data/test/openapi_rest/api_validator_test.rb +23 -0
- data/test/openapi_rest/query_builder_test.rb +32 -0
- data/test/openapi_rest/query_response_test.rb +129 -0
- data/test/spec_helper.rb +8 -0
- data/test/support/data.rb +3 -0
- data/test/support/models.rb +3 -0
- data/test/support/schema.rb +13 -0
- metadata +139 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c61d29ffa18db72ca6edda6a9c339bc52524a754
|
4
|
+
data.tar.gz: e41d85daabf180c24b46536d978162fdaf6fbc46
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 911b007aa471968568166df886991b762f9ea96787bb0a766766d689478972bcc3444ed80fcd7babef641ef0e36674f16b4d6f8b939f194e322ab321cacda025
|
7
|
+
data.tar.gz: 43fc588ff2fbd5dc9e602a37d9bb174e0e6a24475e04049ef31ecbb0755def950b70722b6cd539d4148dc02570b2e9c45e1ad87306c4595a83c12bf67c797584
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 Bizimply Ltd
|
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,141 @@
|
|
1
|
+
# OpenAPIRest
|
2
|
+
|
3
|
+
This gem aims to provide an easier way to implement REST api endpoints using OpenAPI specs in a Rails project.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'openapi_rest'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle install
|
16
|
+
|
17
|
+
Now, generate the initializer:
|
18
|
+
|
19
|
+
$ rails g openapi_rest:install
|
20
|
+
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
Place your OpenAPI spec yml file in `config/`, see example `generators/templates/api_docs.yml`. The file needs to be formatted in OpenAPI v2.0. You can then use `OpenAPIRest::ApiModel` directly from a controller. Example:
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
class Product < ActiveRecord::Base
|
28
|
+
|
29
|
+
end
|
30
|
+
```
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
module Api
|
34
|
+
module V1
|
35
|
+
class MyController < ActionController::Base
|
36
|
+
def index
|
37
|
+
response = OpenAPIRest::ApiModel.new(:product).where(params)
|
38
|
+
render_rest response
|
39
|
+
end
|
40
|
+
|
41
|
+
def show
|
42
|
+
# The find method will expect a second parameter that ultimately will call find_by
|
43
|
+
response = OpenAPIRest::ApiModel.new(:product).find(params, id: params[:id])
|
44
|
+
if response.results?
|
45
|
+
render_rest response
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def update
|
50
|
+
# The find method will expect a second parameter that ultimately will call find_by
|
51
|
+
response = OpenAPIRest::ApiModel.new(:product).find(params, id: params[:id])
|
52
|
+
if response.results?
|
53
|
+
response.update_resource
|
54
|
+
|
55
|
+
render_rest response
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def create
|
60
|
+
# For cases when our model needs to be inserted through another model.
|
61
|
+
response = OpenAPIRest::ApiModel.new(:product).build(params, extra_param_ids: store.id)
|
62
|
+
|
63
|
+
response.create_resource
|
64
|
+
|
65
|
+
render_rest response
|
66
|
+
end
|
67
|
+
|
68
|
+
def destroy
|
69
|
+
response = OpenAPIRest::ApiModel.new(:product).find(params, id: params[:id])
|
70
|
+
if response.results?
|
71
|
+
# When using cancancan gem, we can get the AR model by calling results.
|
72
|
+
# authorize! :delete, response.results
|
73
|
+
|
74
|
+
response.delete_resource
|
75
|
+
|
76
|
+
render_rest response
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
```
|
83
|
+
|
84
|
+
`render_rest` is a custom method that takes a `QueryResponse` object to be rendered.
|
85
|
+
|
86
|
+
Last but not least, we need to tell to the Rails app which routes will be using the openapi parsing and if the routes have any namespace with the following syntax:
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
|
90
|
+
scope module: :api, defaults: { format: 'json' }, openapi: true, namespace: 'api' do
|
91
|
+
scope module: :v1 do
|
92
|
+
resources :myresources, only: [:index, :show]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
```
|
97
|
+
|
98
|
+
### Adding a Custom Filter
|
99
|
+
|
100
|
+
Create a wrapper object that inherits from `OpenAPIRest::ApiModel` if you need custom filter. From the ApiModel you will have access to the `@model` class variable which is the original AR model.
|
101
|
+
|
102
|
+
Example:
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
module Api
|
106
|
+
class MyFilteredApiModel < OpenAPIRest::ApiModel
|
107
|
+
def filter(params)
|
108
|
+
@model = model.where('mymodelname.updated_at > ?', params[:date_param])
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
```
|
113
|
+
|
114
|
+
On the Controller side:
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
module Api
|
118
|
+
module V1
|
119
|
+
class MyController < ActionController::Base
|
120
|
+
def index
|
121
|
+
# The where and find methods can contain a block which will return the wrapper so you can specify custom filters
|
122
|
+
response = Api::MyFilteredApiModel.new(:product).where(params) do |wrapper|
|
123
|
+
wrapper.filter(params)
|
124
|
+
end
|
125
|
+
|
126
|
+
render_rest response
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
```
|
132
|
+
|
133
|
+
|
134
|
+
## Contributing
|
135
|
+
|
136
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/bizimply/OpenAPI-Rails-REST
|
137
|
+
|
138
|
+
## License
|
139
|
+
|
140
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
141
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "openapi_rest"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
module OpenapiRest
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
source_root(File.expand_path(File.dirname(__FILE__)))
|
5
|
+
def copy_initializer
|
6
|
+
copy_file 'openapi_doc.rb', 'config/initializers/openapi_doc.rb'
|
7
|
+
copy_file '../templates/api_docs.yml', 'config/api_docs.yml'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
# this is an example of the Uber API
|
2
|
+
# as a demonstration of an API spec in YAML
|
3
|
+
swagger: '2.0'
|
4
|
+
info:
|
5
|
+
title: Supermarket API
|
6
|
+
description: Move your app forward with the Supermarket API
|
7
|
+
version: "1.0.0"
|
8
|
+
# the domain of the service
|
9
|
+
host: api.supermarket.com
|
10
|
+
# array of all schemes that your API supports
|
11
|
+
schemes:
|
12
|
+
- https
|
13
|
+
# will be prefixed to all paths
|
14
|
+
basePath: /v1
|
15
|
+
produces:
|
16
|
+
- application/json
|
17
|
+
paths:
|
18
|
+
/products:
|
19
|
+
get:
|
20
|
+
summary: Product Types
|
21
|
+
description: |
|
22
|
+
The Products endpoint returns information about the *Uber* products
|
23
|
+
offered at a given location. The response includes the display name
|
24
|
+
and other details about each product, and lists the products in the
|
25
|
+
proper display order.
|
26
|
+
parameters:
|
27
|
+
- name: latitude
|
28
|
+
in: query
|
29
|
+
description: Latitude component of location.
|
30
|
+
required: true
|
31
|
+
type: number
|
32
|
+
format: double
|
33
|
+
- name: longitude
|
34
|
+
in: query
|
35
|
+
description: Longitude component of location.
|
36
|
+
required: true
|
37
|
+
type: number
|
38
|
+
format: double
|
39
|
+
tags:
|
40
|
+
- Products
|
41
|
+
responses:
|
42
|
+
200:
|
43
|
+
description: An array of products
|
44
|
+
schema:
|
45
|
+
type: array
|
46
|
+
items:
|
47
|
+
$ref: '#/definitions/Product'
|
48
|
+
default:
|
49
|
+
description: Unexpected error
|
50
|
+
schema:
|
51
|
+
$ref: '#/definitions/Error'
|
52
|
+
post:
|
53
|
+
summary: Creates Product
|
54
|
+
description: |
|
55
|
+
The Products endpoint creates a product.
|
56
|
+
parameters:
|
57
|
+
- name: product_id
|
58
|
+
in: body
|
59
|
+
description: Product ID
|
60
|
+
required: true
|
61
|
+
type: string
|
62
|
+
- name: name
|
63
|
+
in: body
|
64
|
+
description: Display Name
|
65
|
+
required: false
|
66
|
+
type: string
|
67
|
+
tags:
|
68
|
+
- Products
|
69
|
+
responses:
|
70
|
+
200:
|
71
|
+
description: A products
|
72
|
+
schema:
|
73
|
+
type: object
|
74
|
+
items:
|
75
|
+
$ref: '#/definitions/Product'
|
76
|
+
default:
|
77
|
+
description: Unexpected error
|
78
|
+
schema:
|
79
|
+
$ref: '#/definitions/Error'
|
80
|
+
/products/{id}:
|
81
|
+
patch:
|
82
|
+
summary: Updates a Product
|
83
|
+
description: |
|
84
|
+
The Products endpoint updates a product.
|
85
|
+
parameters:
|
86
|
+
- name: id
|
87
|
+
in: path
|
88
|
+
description: Product ID
|
89
|
+
required: true
|
90
|
+
type: number
|
91
|
+
- $ref: "#/parameters/ProductUpdate"
|
92
|
+
tags:
|
93
|
+
- Products
|
94
|
+
responses:
|
95
|
+
204:
|
96
|
+
description: A products
|
97
|
+
schema:
|
98
|
+
type: object
|
99
|
+
items:
|
100
|
+
$ref: '#/definitions/Product'
|
101
|
+
default:
|
102
|
+
description: Unexpected error
|
103
|
+
schema:
|
104
|
+
$ref: '#/definitions/Error'
|
105
|
+
delete:
|
106
|
+
summary: Deletes a Product
|
107
|
+
description:
|
108
|
+
Deletes a single product identified by its id.
|
109
|
+
parameters:
|
110
|
+
- name: id
|
111
|
+
in: path
|
112
|
+
description: ID of product
|
113
|
+
required: true
|
114
|
+
type: number
|
115
|
+
tags:
|
116
|
+
- Employees
|
117
|
+
responses:
|
118
|
+
204:
|
119
|
+
description: Success
|
120
|
+
default:
|
121
|
+
description: Unexpected error
|
122
|
+
schema:
|
123
|
+
$ref: '#/definitions/ErrorMessage'
|
124
|
+
parameters:
|
125
|
+
ProductUpdate:
|
126
|
+
name: product
|
127
|
+
in: body
|
128
|
+
required: true
|
129
|
+
schema:
|
130
|
+
properties:
|
131
|
+
name:
|
132
|
+
type: string
|
133
|
+
description: Name of the product
|
134
|
+
definitions:
|
135
|
+
Product:
|
136
|
+
type: object
|
137
|
+
properties:
|
138
|
+
product_id:
|
139
|
+
type: string
|
140
|
+
description: Unique identifier representing a specific product for a given latitude & longitude. For example, uberX in San Francisco will have a different product_id than uberX in Los Angeles.
|
141
|
+
description:
|
142
|
+
type: string
|
143
|
+
description: Description of product.
|
144
|
+
name:
|
145
|
+
type: string
|
146
|
+
description: Display name of product.
|
147
|
+
capacity:
|
148
|
+
type: string
|
149
|
+
description: Capacity of product. For example, 4 people.
|
150
|
+
image:
|
151
|
+
type: string
|
152
|
+
description: Image URL representing the product.
|
153
|
+
Error:
|
154
|
+
type: object
|
155
|
+
properties:
|
156
|
+
code:
|
157
|
+
type: integer
|
158
|
+
format: int32
|
159
|
+
message:
|
160
|
+
type: string
|
161
|
+
fields:
|
162
|
+
type: string
|
data/lib/openapi_rest.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rails'
|
2
|
+
require 'openapi_rest/version'
|
3
|
+
require 'openapi_rest/validators/format.rb'
|
4
|
+
require 'openapi_rest/validators/pattern.rb'
|
5
|
+
require 'openapi_rest/operations/filter.rb'
|
6
|
+
require 'openapi_rest/operations/paginate.rb'
|
7
|
+
require 'openapi_rest/operations/sort.rb'
|
8
|
+
require 'openapi_rest/api_config.rb'
|
9
|
+
require 'openapi_rest/api_doc.rb'
|
10
|
+
require 'openapi_rest/api_doc_parser.rb'
|
11
|
+
require 'openapi_rest/api_model.rb'
|
12
|
+
require 'openapi_rest/api_parameters.rb'
|
13
|
+
require 'openapi_rest/api_validator.rb'
|
14
|
+
require 'openapi_rest/extension.rb'
|
15
|
+
require 'openapi_rest/query_builder.rb'
|
16
|
+
require 'openapi_rest/query_response.rb'
|
17
|
+
require 'openapi_rest/railtie'
|
18
|
+
require 'openapi_rest/rest_renderer'
|
19
|
+
|
20
|
+
module OpenAPIRest
|
21
|
+
# Your code goes here...
|
22
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module OpenAPIRest
|
2
|
+
###
|
3
|
+
# Api doc parser based on OpenAPI specs
|
4
|
+
#
|
5
|
+
module ApiDoc
|
6
|
+
@config = nil
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def configure
|
10
|
+
yield config = OpenAPIRest::ApiConfig.new
|
11
|
+
@config = config
|
12
|
+
end
|
13
|
+
|
14
|
+
def document
|
15
|
+
@config.document
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|