openapi_rest 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +141 -0
  4. data/Rakefile +11 -0
  5. data/bin/console +14 -0
  6. data/bin/setup +8 -0
  7. data/lib/generators/openapi_rest/install_generator.rb +11 -0
  8. data/lib/generators/openapi_rest/openapi_doc.rb +3 -0
  9. data/lib/generators/templates/api_docs.yml +162 -0
  10. data/lib/openapi_rest.rb +22 -0
  11. data/lib/openapi_rest/api_config.rb +12 -0
  12. data/lib/openapi_rest/api_doc.rb +19 -0
  13. data/lib/openapi_rest/api_doc_parser.rb +110 -0
  14. data/lib/openapi_rest/api_model.rb +36 -0
  15. data/lib/openapi_rest/api_parameters.rb +76 -0
  16. data/lib/openapi_rest/api_validator.rb +20 -0
  17. data/lib/openapi_rest/extension.rb +35 -0
  18. data/lib/openapi_rest/operations/filter.rb +24 -0
  19. data/lib/openapi_rest/operations/paginate.rb +19 -0
  20. data/lib/openapi_rest/operations/sort.rb +27 -0
  21. data/lib/openapi_rest/query_builder.rb +70 -0
  22. data/lib/openapi_rest/query_response.rb +89 -0
  23. data/lib/openapi_rest/railtie.rb +9 -0
  24. data/lib/openapi_rest/rest_renderer.rb +75 -0
  25. data/lib/openapi_rest/validators/format.rb +24 -0
  26. data/lib/openapi_rest/validators/pattern.rb +21 -0
  27. data/lib/openapi_rest/version.rb +3 -0
  28. data/test/openapi_rest/api_config_test.rb +9 -0
  29. data/test/openapi_rest/api_doc_parser_test.rb +71 -0
  30. data/test/openapi_rest/api_doc_test.rb +15 -0
  31. data/test/openapi_rest/api_model_test.rb +49 -0
  32. data/test/openapi_rest/api_parameters_test.rb +57 -0
  33. data/test/openapi_rest/api_validator_test.rb +23 -0
  34. data/test/openapi_rest/query_builder_test.rb +32 -0
  35. data/test/openapi_rest/query_response_test.rb +129 -0
  36. data/test/spec_helper.rb +8 -0
  37. data/test/support/data.rb +3 -0
  38. data/test/support/models.rb +3 -0
  39. data/test/support/schema.rb +13 -0
  40. 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
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << 'test'
7
+ t.pattern = 'test/**/*_test.rb'
8
+ end
9
+
10
+ desc "Run tests"
11
+ task :default => :test
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,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -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,3 @@
1
+ OpenAPIRest::ApiDoc.configure do |c|
2
+ c.document = YAML::load_file(File.join(Rails.root, 'config/api_docs.yml'))
3
+ 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
@@ -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,12 @@
1
+ module OpenAPIRest
2
+ ###
3
+ # Api doc config based on OpenAPI specs
4
+ #
5
+ class ApiConfig
6
+ attr_accessor :document
7
+
8
+ def initialize(user_config = {})
9
+ self.document = user_config[:document]
10
+ end
11
+ end
12
+ 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