endpoint-flux2 1.1.6

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 (93) hide show
  1. checksums.yaml +7 -0
  2. data/.github/FUNDING.yml +3 -0
  3. data/.github/workflows/gem-push.yml +42 -0
  4. data/.gitignore +36 -0
  5. data/CONTRIBUTING.md +18 -0
  6. data/Gemfile +6 -0
  7. data/Gemfile.lock +49 -0
  8. data/README.md +634 -0
  9. data/Rakefile +1 -0
  10. data/_config.yml +1 -0
  11. data/circle.yml +14 -0
  12. data/endpoint_flux.gemspec +20 -0
  13. data/lib/endpoint_flux.rb +22 -0
  14. data/lib/endpoint_flux/class_loader.rb +58 -0
  15. data/lib/endpoint_flux/config.rb +85 -0
  16. data/lib/endpoint_flux/config/interceptor.rb +23 -0
  17. data/lib/endpoint_flux/config/middleware.rb +38 -0
  18. data/lib/endpoint_flux/config/rescue_from.rb +28 -0
  19. data/lib/endpoint_flux/endpoint.rb +81 -0
  20. data/lib/endpoint_flux/exceptions.rb +10 -0
  21. data/lib/endpoint_flux/exceptions/base.rb +21 -0
  22. data/lib/endpoint_flux/exceptions/forbidden.rb +12 -0
  23. data/lib/endpoint_flux/exceptions/not_found.rb +12 -0
  24. data/lib/endpoint_flux/exceptions/service_unavailable.rb +12 -0
  25. data/lib/endpoint_flux/exceptions/unauthorized.rb +12 -0
  26. data/lib/endpoint_flux/exceptions/validation.rb +13 -0
  27. data/lib/endpoint_flux/middlewares.rb +8 -0
  28. data/lib/endpoint_flux/middlewares/authenticator/skip.rb +11 -0
  29. data/lib/endpoint_flux/middlewares/authorizator/skip.rb +11 -0
  30. data/lib/endpoint_flux/middlewares/decorator/add_status.rb +12 -0
  31. data/lib/endpoint_flux/middlewares/decorator/skip.rb +11 -0
  32. data/lib/endpoint_flux/middlewares/policy/skip.rb +11 -0
  33. data/lib/endpoint_flux/middlewares/validator/empty.rb +12 -0
  34. data/lib/endpoint_flux/rails/concerns/endpoint_controller.rb +43 -0
  35. data/lib/endpoint_flux/railtie.rb +14 -0
  36. data/lib/endpoint_flux/request.rb +17 -0
  37. data/lib/endpoint_flux/response.rb +30 -0
  38. data/lib/endpoint_flux/tasks/endpoint_flux/generators/endpoint_flux/decorators/articles/base.rb +12 -0
  39. data/lib/endpoint_flux/tasks/endpoint_flux/generators/endpoint_flux/decorators/boards/base.rb +12 -0
  40. data/lib/endpoint_flux/tasks/endpoint_flux/generators/endpoint_flux/decorators/boards/show.rb +22 -0
  41. data/lib/endpoint_flux/tasks/endpoint_flux/generators/endpoint_flux/decorators/tasks/base.rb +12 -0
  42. data/lib/endpoint_flux/tasks/endpoint_flux/generators/endpoint_flux/endpoints/articles/create.rb +27 -0
  43. data/lib/endpoint_flux/tasks/endpoint_flux/generators/endpoint_flux/endpoints/articles/destroy.rb +23 -0
  44. data/lib/endpoint_flux/tasks/endpoint_flux/generators/endpoint_flux/endpoints/articles/index.rb +26 -0
  45. data/lib/endpoint_flux/tasks/endpoint_flux/generators/endpoint_flux/endpoints/boards/create.rb +24 -0
  46. data/lib/endpoint_flux/tasks/endpoint_flux/generators/endpoint_flux/endpoints/boards/index.rb +21 -0
  47. data/lib/endpoint_flux/tasks/endpoint_flux/generators/endpoint_flux/endpoints/boards/show.rb +23 -0
  48. data/lib/endpoint_flux/tasks/endpoint_flux/generators/endpoint_flux/endpoints/tasks/create.rb +27 -0
  49. data/lib/endpoint_flux/tasks/endpoint_flux/generators/endpoint_flux/endpoints/tasks/destroy.rb +23 -0
  50. data/lib/endpoint_flux/tasks/endpoint_flux/generators/endpoint_flux/endpoints/tasks/index.rb +25 -0
  51. data/lib/endpoint_flux/tasks/endpoint_flux/generators/endpoint_flux/endpoints/tasks/update.rb +28 -0
  52. data/lib/endpoint_flux/tasks/endpoint_flux/generators/endpoint_flux/middlewares/decorator/paginate.rb +19 -0
  53. data/lib/endpoint_flux/tasks/endpoint_flux/generators/endpoint_flux/middlewares/decorator/representable.rb +24 -0
  54. data/lib/endpoint_flux/tasks/endpoint_flux/generators/endpoint_flux/middlewares/validator/inline.rb +17 -0
  55. data/lib/endpoint_flux/tasks/endpoint_flux/generators/endpoint_flux/validations/base.rb +21 -0
  56. data/lib/endpoint_flux/tasks/endpoint_flux/generators/endpoint_flux/validations/concern/error.rb +7 -0
  57. data/lib/endpoint_flux/tasks/endpoint_flux/generators/endpoint_flux/validations/predicates/base.rb +12 -0
  58. data/lib/endpoint_flux/tasks/endpoint_flux/generators/endpoint_flux/validations/predicates/bool.rb +20 -0
  59. data/lib/endpoint_flux/tasks/endpoint_flux/generators/endpoint_flux/validations/predicates/dates.rb +34 -0
  60. data/lib/endpoint_flux/tasks/endpoint_flux/generators/endpoint_flux/validations/predicates/decimal.rb +24 -0
  61. data/lib/endpoint_flux/tasks/endpoint_flux/generators/endpoint_flux/validations/predicates/email.rb +18 -0
  62. data/lib/endpoint_flux/tasks/endpoint_flux/generators/endpoint_flux/validations/predicates/password.rb +29 -0
  63. data/lib/endpoint_flux/tasks/endpoint_flux/generators/initializers/endpoint_flux.rb +41 -0
  64. data/lib/endpoint_flux/tasks/endpoint_flux/init.rake +12 -0
  65. data/lib/endpoint_flux/version.rb +3 -0
  66. data/spec/lib/class_loader_spec.rb +31 -0
  67. data/spec/lib/config/default_middlewares_spec.rb +21 -0
  68. data/spec/lib/config/endpoints_namespace_spec.rb +13 -0
  69. data/spec/lib/config/flow_spec.rb +8 -0
  70. data/spec/lib/config/interceptor_spec.rb +34 -0
  71. data/spec/lib/config/middleware_spec.rb +62 -0
  72. data/spec/lib/config/rescue_from_spec.rb +45 -0
  73. data/spec/lib/endpoint/flow_spec.rb +43 -0
  74. data/spec/lib/endpoint/middlewares_spec.rb +110 -0
  75. data/spec/lib/endpoint/perform_spec.rb +61 -0
  76. data/spec/lib/endpoint/rescue_from_spec.rb +61 -0
  77. data/spec/lib/endpoint_flux/rails/concerns/endpoint_controller_spec.rb +158 -0
  78. data/spec/lib/endpoint_flux/request_spec.rb +44 -0
  79. data/spec/lib/exceptions/forbidden_spec.rb +12 -0
  80. data/spec/lib/exceptions/not_found_spec.rb +12 -0
  81. data/spec/lib/exceptions/service_unavailable_spec.rb +12 -0
  82. data/spec/lib/exceptions/unauthorized_spec.rb +12 -0
  83. data/spec/lib/exceptions/validation_spec.rb +14 -0
  84. data/spec/lib/middlewares/authenticator/skip_spec.rb +5 -0
  85. data/spec/lib/middlewares/authorizator/skip_spec.rb +5 -0
  86. data/spec/lib/middlewares/decorator/add_status_spec.rb +17 -0
  87. data/spec/lib/middlewares/decorator/skip_spec.rb +5 -0
  88. data/spec/lib/middlewares/policy/skip_spec.rb +5 -0
  89. data/spec/lib/middlewares/shared_examples.rb +19 -0
  90. data/spec/lib/middlewares/validator/empty_spec.rb +15 -0
  91. data/spec/lib/response_spec.rb +131 -0
  92. data/spec/spec_helper.rb +56 -0
  93. metadata +203 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f8dbd875003146bffda2e6fbf4fb81465c08ad78ab9fce4aa81677a3349fdd3a
4
+ data.tar.gz: bba6dba28cb7b5c94ad36ab2c3cb963d2c74cdc7c98e2a2cf9065d2fa28ee21f
5
+ SHA512:
6
+ metadata.gz: ca4cd14ca97b9eb78fee1e861871bc59c8e2ac43803d9403a31a77c8003542b59be50e974de979cd3d83cbc5c3b846ce295f005d15bfc94adc81c5214df4ce06
7
+ data.tar.gz: 9bd801364282a5a689582fae72b6fd4f93166aba52b8ff5f9b796c0651adf7150d07d9000936c86a7d6af5fa090ba969bfa8412ce329f0c9345646beb456915c
@@ -0,0 +1,3 @@
1
+
2
+ patreon: pavelkvasnikov
3
+
@@ -0,0 +1,42 @@
1
+ name: Ruby Gem
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ jobs:
10
+ build:
11
+ name: Build + Publish
12
+ runs-on: ubuntu-latest
13
+
14
+ steps:
15
+ - uses: actions/checkout@v2
16
+ - name: Set up Ruby 2.6
17
+ uses: actions/setup-ruby@v1
18
+ with:
19
+ ruby-version: 2.6.x
20
+
21
+ - name: Publish to GPR
22
+ run: |
23
+ mkdir -p $HOME/.gem
24
+ touch $HOME/.gem/credentials
25
+ chmod 0600 $HOME/.gem/credentials
26
+ printf -- "---\n:github: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
27
+ gem build *.gemspec
28
+ gem push --KEY github --host https://rubygems.pkg.github.com/${OWNER} *.gem
29
+ env:
30
+ GEM_HOST_API_KEY: "Bearer ${{secrets.GITHUB_TOKEN}}"
31
+ OWNER: ${{ secrets.GEM_OWNER }}
32
+
33
+ - name: Publish to RubyGems
34
+ run: |
35
+ mkdir -p $HOME/.gem
36
+ touch $HOME/.gem/credentials
37
+ chmod 0600 $HOME/.gem/credentials
38
+ printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
39
+ gem build *.gemspec
40
+ gem push *.gem
41
+ env:
42
+ GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
@@ -0,0 +1,36 @@
1
+ # Ignore bundler config.
2
+ /.bundle
3
+
4
+ # Ignore all logfiles and tempfiles.
5
+ /log/*
6
+ /tmp/*
7
+ !/log/.keep
8
+ !/tmp/.keep
9
+
10
+ .docker-sync
11
+
12
+ .rspec
13
+ .ruby-*
14
+ coverage
15
+ .DS_Store
16
+ .idea
17
+ .dev_secrets
18
+ .env
19
+ .env.test
20
+ .vimrc
21
+
22
+ # vim ignores
23
+ # swap
24
+ [._]*.s[a-v][a-z]
25
+ [._]*.sw[a-p]
26
+ [._]s[a-v][a-z]
27
+ [._]sw[a-p]
28
+ # session
29
+ Session.vim
30
+ # temporary
31
+ .netrwhist
32
+ *~
33
+ # auto-generated tag files
34
+ tags
35
+
36
+ .byebug_history
@@ -0,0 +1,18 @@
1
+ ## Contributing
2
+
3
+ While not required to contribute, we recommend [RBENV](https://github.com/rbenv/rbenv) to manage your rubies.
4
+
5
+ 1. Read the [Contributor Code of Conduct](https://www.contributor-covenant.org/version/1/0/0/code-of-conduct.html)
6
+ 2. [Fork it](https://help.github.com/articles/about-forks/)
7
+ 3. Clone the project `git clone git@github.com:[YOUR GITHUB USERNAME]/endpoint-flux.git`
8
+ 4. `cd endpoint-flux`
9
+ 5. Create your feature branch `git checkout -b my-new-feature`
10
+ 6. Write tests for your changes (feature/bug)
11
+ 7. Write your (feature/bugfix)
12
+ 8. Install the dependencies `bundle install`
13
+ 9. Run the tests `bundle exec rspec`
14
+ 10. Commit your changes `git commit -am 'Added some feature'`
15
+ 11. Push to the branch `git push origin my-new-feature`
16
+ 12. Create new [Pull Request](https://help.github.com/articles/creating-a-pull-request/)
17
+
18
+ If we've missed something please open an [issue](https://github.com/resolving/endpoint-flux/issues/new)
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ ruby '2.5.3'
2
+ #ruby-gemset=endpoint-flux
3
+
4
+ source 'https://rubygems.org'
5
+
6
+ gemspec
@@ -0,0 +1,49 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ endpoint-flux (1.1.4)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ byebug (11.1.1)
10
+ codecov (0.2.11)
11
+ json
12
+ simplecov
13
+ url
14
+ diff-lcs (1.3)
15
+ docile (1.3.2)
16
+ json (2.3.0)
17
+ rspec (3.9.0)
18
+ rspec-core (~> 3.9.0)
19
+ rspec-expectations (~> 3.9.0)
20
+ rspec-mocks (~> 3.9.0)
21
+ rspec-core (3.9.1)
22
+ rspec-support (~> 3.9.1)
23
+ rspec-expectations (3.9.1)
24
+ diff-lcs (>= 1.2.0, < 2.0)
25
+ rspec-support (~> 3.9.0)
26
+ rspec-mocks (3.9.1)
27
+ diff-lcs (>= 1.2.0, < 2.0)
28
+ rspec-support (~> 3.9.0)
29
+ rspec-support (3.9.2)
30
+ simplecov (0.18.5)
31
+ docile (~> 1.1)
32
+ simplecov-html (~> 0.11)
33
+ simplecov-html (0.12.2)
34
+ url (0.3.2)
35
+
36
+ PLATFORMS
37
+ ruby
38
+
39
+ DEPENDENCIES
40
+ byebug (>= 9.0)
41
+ codecov
42
+ endpoint-flux!
43
+ rspec (>= 3.5.0)
44
+
45
+ RUBY VERSION
46
+ ruby 2.5.3p105
47
+
48
+ BUNDLED WITH
49
+ 1.16.6
@@ -0,0 +1,634 @@
1
+ # EndpointFlux
2
+ A simple way to organise API endpoints
3
+
4
+ ✍✍✍ **Feedback is welcome** ✅✅✅
5
+
6
+ 💚💚💚 **Stars are welcome** 💚💚💚
7
+
8
+ Telegram group https://t.me/endpoint_flux
9
+
10
+ ![Logo](https://svgshare.com/i/PQo.svg)
11
+
12
+ [![Gem Version](https://badge.fury.io/rb/endpoint-flux.svg)](http://badge.fury.io/rb/endpoint-flux)
13
+
14
+ [![CircleCI](https://circleci.com/gh/pavelkvasnikov/endpoint-flux.svg?style=svg)](https://app.circleci.com/pipelines/github/pavelkvasnikov/endpoint-flux)
15
+
16
+ [![Maintainability](https://api.codeclimate.com/v1/badges/a99a88d28ad37a79dbf6/maintainability)](https://codeclimate.com/github/codeclimate/codeclimate/maintainability)
17
+
18
+ [![Known Vulnerabilities](https://snyk.io/test/github/pavelkvasnikov/endpoint-flux/badge.svg?targetFile=Gemfile.lock)](https://snyk.io/test/github/pavelkvasnikov/endpoint-flux?targetFile=Gemfile.lock)
19
+
20
+ [![codecov](https://codecov.io/gh/pavelkvasnikov/endpoint-flux/branch/master/graph/badge.svg)](https://codecov.io/gh/pavelkvasnikov/endpoint-flux)
21
+
22
+ ![dependabot](https://badgen.net/dependabot/pavelkvasnikov/endpoint-flux/?icon=dependabot)
23
+
24
+ ## Index
25
+ - [Projects code organisation](#projects-code-organisation)
26
+ - [Usage](#usage)
27
+ - [Installation](#installation)
28
+ - [Configuration](#configuration)
29
+ - [Endpoints](#endpoints)
30
+ - [Routing](#routing)
31
+ - [Controllers](#controllers)
32
+ - [Middlewares](#middlewares)
33
+ - [Authenticator](#authenticator)
34
+ - [Authorizator](#authorizator)
35
+ - [Policy](#policy)
36
+ - [Validator](#validator)
37
+ - [Decorator](#decorator)
38
+ - [Decorators](#decorators)
39
+ - [Validations](#validations)
40
+ - [Services](#services)
41
+ - [Exceptions](#exceptions)
42
+ - [Response helpers](#response-helpers)
43
+ - [Contributing](CONTRIBUTING.md)
44
+ - [Maintainers](https://github.com/resolving/endpoint-flux/graphs/contributors)
45
+ - [License](#license)
46
+
47
+
48
+ ## Projects code organisation
49
+
50
+ EndpointFlux offers you a new file and logic organisation in Ruby applications.
51
+
52
+ ```
53
+ app
54
+ ├── controllers
55
+ │ ├── users_controller.rb
56
+ ├── endpoint_flux
57
+ │ ├── decorators
58
+ │ │ ├── users
59
+ │ │ │ ├── project.rb
60
+ │ │ ├── user.rb
61
+ │ │ ├── ...
62
+ │ ├── endpoints
63
+ │ │ ├── users
64
+ │ │ ├── create.rb
65
+ │ │ ├── update.rb
66
+ │ │ ├── ...
67
+ │ ├── middlewares
68
+ │ │ ├── authenticator
69
+ │ │ │ ├── default.rb
70
+ │ │ ├── authorizator
71
+ │ │ │ ├── default.rb
72
+ │ │ ├── decorator
73
+ │ │ │ ├── paginate.rb
74
+ │ │ │ ├── representable.rb
75
+ │ │ │ ├── ...
76
+ │ │ ├── policy
77
+ │ │ │ ├── comment.rb
78
+ │ │ │ ├── ...
79
+ │ │ ├── validator
80
+ │ │ ├── inline.rb
81
+ │ ├── services
82
+ │ │ ├── auth.rb
83
+ │ │ ├── ...
84
+ │ ├── validations
85
+ │ │ ├── predicates
86
+ │ │ │ ├── base.rb
87
+ │ │ │ ├── date.rb
88
+ │ │ │ ├── ...
89
+ │ │ ├── base.rb
90
+ │ │ ├── error.rb
91
+ │ │ ├── user.rb
92
+ ```
93
+
94
+
95
+ ## Usage
96
+
97
+ ### Installation
98
+ Add this line to your application's Gemfile:
99
+
100
+ ```ruby
101
+ gem 'endpoint-flux', require: 'endpoint_flux'
102
+ ```
103
+
104
+ For a latest versvion
105
+ ```ruby
106
+ gem 'endpoint-flux', git: 'https://github.com/pavelkvasnikov/endpoint-flux.git', require: 'endpoint_flux'
107
+ ```
108
+
109
+ And then execute:
110
+ ```bash
111
+ $ bundle install
112
+ ```
113
+
114
+ Or install it yourself as:
115
+ ```bash
116
+ $ gem install endpoint-flux
117
+ ```
118
+
119
+ Run rake task to generate project structure (currently available in a latest version)
120
+ ```bash
121
+ $ rails endpoint_flux:init
122
+ ```
123
+ It will add a new dir `app/endpoint_flux` and new initializer `config/initializers/endpoint_flux.rb`
124
+
125
+ ### Configuration
126
+
127
+ You can initialize the EndpointFlux before using and can specify a bunch of params as you need. Locate it in
128
+ `config/initializers/endpoint_flux.rb`.
129
+
130
+ With the `EndpointFlux.config.middlewares_namespaces` directive you can specify the location of middleware.
131
+ ```ruby
132
+ EndpointFlux.config.middlewares_namespaces << 'middlewares'
133
+ ```
134
+
135
+ To specify the default middleware that will be used for each response, if nothing specified in Endpoint class, use
136
+ `EndpointFlux.config.default_middlewares` directive. For example:
137
+ ```ruby
138
+ EndpointFlux.config.default_middlewares :validator, :inline
139
+ ```
140
+ Where `:validator` is a middleware and `:inline` is a class that defined in
141
+ `app/endpoint_flux/middlewares/validator/inline.rb`. More details [here](#validator).
142
+
143
+ With `EndpointFlux.config.rescue_from` you can specify how to handle the custom exceptions that would be raised in
144
+ Application. For example:
145
+ ```ruby
146
+ not_found_errors = [ActiveRecord::RecordNotFound]
147
+ EndpointFlux.config.rescue_from(not_found_errors) do |_, attrs, _|
148
+ attrs[1].body = EndpointFlux::Exceptions::NotFound.new.to_hash
149
+ attrs
150
+ end
151
+ ```
152
+
153
+ Also you can specify interceptor that would be called before processing each response
154
+ ```ruby
155
+ EndpointFlux.config.interceptor do |attrs|
156
+ Rails.root.join('maintenance.txt').exist? &&
157
+ raise(EndpointFlux::Exceptions::ServiceUnavailable)
158
+
159
+ attrs
160
+ end
161
+ ```
162
+
163
+ And if you need you can define your own methods like this:
164
+ ```ruby
165
+ EndpointFlux::Endpoint.class_eval do
166
+ define_method(:raise_validation_error) do |errors|
167
+ raise EndpointFlux::Exceptions::Validation, errors
168
+ end
169
+ end
170
+ ```
171
+
172
+ Config example:
173
+ ```ruby
174
+ # config/initializers/endpoint_flux.rb
175
+ require 'endpoint_flux'
176
+
177
+ EndpointFlux.config.middlewares_namespaces << 'middlewares'
178
+
179
+ EndpointFlux.config.default_middlewares :authenticator, :default
180
+ EndpointFlux.config.default_middlewares :authorizator, :default
181
+ EndpointFlux.config.default_middlewares :validator, :inline
182
+ EndpointFlux.config.default_middlewares :policy, :skip
183
+ EndpointFlux.config.default_middlewares :decorator, :skip
184
+
185
+ not_found_errors = [ActiveRecord::RecordNotFound]
186
+ EndpointFlux.config.rescue_from(not_found_errors) do |_, attrs, _|
187
+ attrs[1].body = EndpointFlux::Exceptions::NotFound.new.to_hash
188
+ attrs
189
+ end
190
+
191
+ EndpointFlux.config.interceptor do |attrs|
192
+ Rails.root.join('maintenance.txt').exist? &&
193
+ raise(EndpointFlux::Exceptions::ServiceUnavailable)
194
+
195
+ attrs
196
+ end
197
+
198
+ EndpointFlux::Endpoint.class_eval do
199
+ define_method(:raise_validation_error) do |errors|
200
+ raise EndpointFlux::Exceptions::Validation, errors
201
+ end
202
+ end
203
+ ```
204
+
205
+ ### Routing
206
+
207
+ EndpointFlux has Rails helper -
208
+ [`present`](https://github.com/resolving/endpoint-flux/blob/master/lib/endpoint_flux/rails/concerns/endpoint_controller.rb),
209
+ which integrates with Rails controllers. So, you can use the default Rails routing system to define routes.
210
+
211
+ ```ruby
212
+ Rails.application.routes.draw do
213
+ resources :users
214
+ end
215
+ ```
216
+
217
+ ```ruby
218
+ class UsersController < ApplicationController
219
+ def index
220
+ present 'users/index' # it dispatches to Endpoints::Users::Index endpoint class.
221
+ end
222
+ end
223
+ ```
224
+
225
+ Or if you're using it in not Rails application, you can implement the middleware for providing
226
+ such data to Endpoints namespace, for example:
227
+
228
+ ```ruby
229
+ class BaseHandler
230
+ def process(msg, options, namespace)
231
+ params = JSON.parse(msg)
232
+ action = options[:headers]['action']
233
+ endpoint = endpoint_for("#{namespace}/#{action}")
234
+
235
+ _, response = endpoint.perform(request_object(params))
236
+
237
+ response.body
238
+ end
239
+
240
+ private
241
+
242
+ def endpoint_for(namespace)
243
+ if ::EndpointFlux.config.endpoints_namespace
244
+ ::EndpointFlux.config.endpoints_namespace + '/' + namespace
245
+ else
246
+ namespace
247
+ end.camelize.constantize
248
+ end
249
+
250
+ def request_object(params)
251
+ ::EndpointFlux::Request.new(headers: {}, params: params.to_h.deep_symbolize_keys!)
252
+ end
253
+ end
254
+ ```
255
+
256
+
257
+ ### Controllers
258
+
259
+ Controllers are simple endpoints for HTTP. They don't have any business logic and just dispatch to an endpoint class.
260
+
261
+ ```ruby
262
+ class UsersController < ApplicationController
263
+ def index
264
+ present 'users/index' # it dispatches to Endpoints::Users::Index endpoint class.
265
+ end
266
+ end
267
+ ```
268
+ Finally `present` method renders `response.body` in JSON format (`render json: response.body`).
269
+
270
+
271
+ ### Endpoints
272
+
273
+ Endpoints encapsulate business logic and it's a central part of applications architecture. It can be used in any Ruby
274
+ application like Rails, Sinatra and etc.
275
+ It's a simple coordinator between all layers needed to get the job done. Endpoint needs for defining and implementing
276
+ steps for the processing data for response. It uses middlewares for data processing that receives the arguments from
277
+ the caller and returns the array `[request, response]` with `response` that contains `body` and `headers` for API.
278
+
279
+ ```ruby
280
+ # app/endpoint_flux/endpoints/users/comments/index.rb
281
+ module Endpoints
282
+ module Users
283
+ module Comments
284
+ module Index
285
+ include EndpointFlux::Endpoint
286
+
287
+ policy :user
288
+ policy :comments
289
+
290
+ validator :inline do
291
+ required(:user_id).value(:number?)
292
+ end
293
+
294
+ process do |request, response|
295
+ response.body[:comments] = request.scope
296
+
297
+ [request, response]
298
+ end
299
+
300
+ decorator :add_status, 200
301
+ decorator :representable, decorator: :comment, collection?: true, wrapped_in: :comments
302
+ end
303
+ end
304
+ end
305
+ end
306
+ ```
307
+
308
+
309
+
310
+ ### Middlewares
311
+
312
+ EndpointFlux has 6 types of predefined middlewares. They will be called in the strong defined order - `authenticator,
313
+ authorizator, validator, policy, process, decorator`. Where `process` should be defined inside the endpoint class for
314
+ the request processing.
315
+
316
+ Also you can add your own middleware class to this flow or change the order. It's possible in two ways:
317
+
318
+ * Inside the custom endpoint class, for example:
319
+ ```ruby
320
+ # app/endpoint_flux/endpoints/users/index.rb
321
+
322
+ module Endpoints
323
+ module Users
324
+ module Index
325
+ include EndpointFlux::Endpoint
326
+ # define new flow with `new_middleware` only for this endpoint
327
+ flow %i[authenticator authorizator validator policy process new_middleware decorator]
328
+
329
+ authorizator :skip
330
+ #...
331
+ process do |request, response|
332
+ # ... some actions
333
+ [request, response]
334
+ end
335
+
336
+ # define the middleware
337
+ new_middleware :default
338
+
339
+ decorator :add_status, 200
340
+ end
341
+ end
342
+ end
343
+ ```
344
+
345
+ * Globally in EndpointFlux config section that will affect all endpoints, for example:
346
+ ```ruby
347
+ # config/initializers/endpoint_flux.rb
348
+ # ...
349
+ # define default value for new middleware
350
+ EndpointFlux.config.default_middlewares :new_middleware, :default
351
+ # Global change the middlewares order flow by adding a new one `new_middleware`
352
+ EndpointFlux.config.flow(%i[authenticator authorizator validator policy process new_middleware decorator])
353
+ ```
354
+
355
+ Middleware class definition should contains `self.perform(*args)` method and returns the `[request, response]` as a result
356
+ ```ruby
357
+ # app/endpoint_flux/middlewares/new_middleware/default.rb
358
+ module Middlewares
359
+ module NewMiddleware
360
+ module Default
361
+ def self.perform(request, response, _)
362
+ # ... some actions
363
+ [request, response]
364
+ end
365
+ end
366
+ end
367
+ end
368
+ ```
369
+
370
+ We have implemented the default middlewares that could be used to skip it without any changes to data. It's located
371
+ [here](https://github.com/resolving/endpoint-flux/tree/master/lib/endpoint_flux/middlewares)
372
+
373
+
374
+ #### Authenticator
375
+
376
+ Here you can implement your authenticate system. For example you can user the [JWT gem](https://github.com/jwt/ruby-jwt)
377
+ Locate it in `app/endpoint_flux/middlewares/authenticator` folder.
378
+ Also you can skip this middleware in Endpoint class by `authenticator :skip` directive
379
+
380
+
381
+ #### Authorizator
382
+
383
+ Here you can implement your authorization system and check the user permissions according to the user role.
384
+ Locate it in `app/endpoint_flux/middlewares/authorizator` folder.
385
+ Also you can skip this middleware in the Endpoint class by `authorizator :skip` directive
386
+
387
+
388
+
389
+ #### Policy
390
+
391
+ Here you implement different policy scopes and use them inside the Endpoint class. And also you can chain it to each other by
392
+ calling in special order. Locate it in `app/endpoint_flux/middlewares/policy` folder.
393
+
394
+ For example:
395
+ * User policy
396
+ ```ruby
397
+ # app/endpoint_flux/middlewares/policy/user.rb
398
+ module Middlewares
399
+ module Policy
400
+ module User
401
+ def self.perform(request, response, _)
402
+ request.scope = ::User.find(request.params[:user_id])
403
+
404
+ [request, response]
405
+ end
406
+ end
407
+ end
408
+ end
409
+ ```
410
+
411
+ * Comments policy
412
+ ```ruby
413
+ # app/endpoint_flux/middlewares/policy/comments.rb
414
+ module Middlewares
415
+ module Policy
416
+ module Comments
417
+ def self.perform(request, response, _)
418
+ raise 'scope must be set' unless request.scope
419
+ raise 'scope must be User' unless request.scope.class.name == 'User'
420
+
421
+ request.scope = ::Comment.where(user_id: request.scope.id)
422
+
423
+ [request, response]
424
+ end
425
+ end
426
+ end
427
+ end
428
+ ```
429
+
430
+ And usage inside the Endpoint class:
431
+ ```ruby
432
+ # app/endpoint_flux/endpoints/users/comments/index.rb
433
+ module Endpoints
434
+ module Users
435
+ module Comments
436
+ module Index
437
+ include EndpointFlux::Endpoint
438
+
439
+ policy :user # get user scope
440
+ policy :comments # get users comments scope
441
+
442
+ validator :inline do
443
+ required(:user_id).value(:number?)
444
+ end
445
+
446
+ process do |request, response|
447
+ response.body[:comments] = request.scope
448
+
449
+ [request, response]
450
+ end
451
+
452
+ decorator :add_status, 200
453
+ decorator :representable, decorator: :comment, collection?: true, wrapped_in: :comments
454
+ end
455
+ end
456
+ end
457
+ end
458
+ ```
459
+
460
+
461
+ #### Validator
462
+
463
+ Here you can implement validation system for request params using the [Dry validation gem](http://dry-rb.org/gems/dry-validation)
464
+ or another libraries. Locate it in `app/endpoint_flux/middlewares/validator` folder.
465
+ Also you can skip this middleware in the Endpoint class by `validator :empty` directive
466
+
467
+ ```ruby
468
+ # app/endpoint_flux/middlewares/validator/inline.rb
469
+ module Middlewares
470
+ module Validator
471
+ module Inline
472
+ def self.perform(request, response, _options, &block)
473
+ validation = ::Services::Validation(&block).call(request.params)
474
+ unless validation.success?
475
+ raise ::EndpointFlux::Exceptions::Validation, validation.messages
476
+ end
477
+ request.params = validation.result
478
+
479
+ [request, response]
480
+ end
481
+ end
482
+ end
483
+ end
484
+ ```
485
+
486
+ Just declare the schema block inside the endpoint to provide it to middleware
487
+ ```ruby
488
+ # app/endpoint_flux/endpoints/users/create.rb
489
+ module Endpoints
490
+ module Users
491
+ module Create
492
+ include EndpointFlux::Endpoint
493
+
494
+ authenticator :skip
495
+ authorizator :skip
496
+
497
+ validator :inline do
498
+ required(:user).schema do
499
+ required(:email).value(:str?, :email?)
500
+ required(:password).value(:str?, :password?)
501
+ end
502
+ end
503
+
504
+ process do |request, response|
505
+ # some actions ... like calling checking for user uniqueness, Mailer Sidekiq workers, token generation and etc.
506
+
507
+ response.body[:user] = ::User.create(request.params[:user])
508
+
509
+ # ...
510
+
511
+ [request, response]
512
+ end
513
+
514
+ decorator :add_status, 200
515
+ decorator :representable, decorator: :user
516
+ end
517
+ end
518
+ end
519
+ ```
520
+
521
+
522
+ #### Decorator
523
+
524
+ Here you can implement a decorator system for representing the response.
525
+ Locate it in `app/endpoint_flux/middlewares/decorator` folder. You can call it inside the endpoint class by using
526
+ directive like this `decorator :representable, decorator: :user`, where `:representable` it's your decorators class name
527
+ and `decorator: :user` it's a custom params as you wish (in this situation specialising to use User decorator for
528
+ representing data).
529
+ For example
530
+
531
+ ```ruby
532
+ # app/endpoint_flux/middlewares/decorator/representable.rb
533
+ module Middlewares
534
+ module Decorator
535
+ module Representable
536
+ def self.perform(request, response, options)
537
+ resource_name = options[:decorator]
538
+ resource = response.body[resource_name]
539
+
540
+ response.body[resource_name] = ::Services::Decorator.call(resource, options) if resource
541
+
542
+ [request, response]
543
+ end
544
+ end
545
+ end
546
+ end
547
+ ```
548
+
549
+ You can add a custom status to the response body by using directive `decorator :add_status, {status_number}`,
550
+ for example `decorator :add_status, 200`.
551
+ Also you can skip this middleware in the Endpoint class by `decorator :skip` directive
552
+
553
+
554
+
555
+ ### Decorators
556
+
557
+ Endpoint can use representers from `app/endpoint_flux/decorators` to serialize and parse JSON and XML documents for APIs.
558
+ For example you can use
559
+ [Representable gem](http://trailblazer.to/gems/representable), it maps representation documents from and to Ruby objects
560
+ and includes JSON, XML and YAML support, plain properties and compositions.
561
+ You can define the decorator schema class in `app/endpoint_flux/decorators` folder and specify it inside of the
562
+ endpoint class by providing as params for `decorator` directive,
563
+ for example `decorator :representable, decorator: :user`
564
+
565
+ ```ruby
566
+ # app/endpoint_flux/decorators/user.rb
567
+ module Decorators
568
+ class User < Representable::Decorator
569
+ include Representable::JSON
570
+
571
+ property :id
572
+ property :name
573
+ property :email
574
+ property :role, exec_context: :decorator
575
+
576
+ property :updated_at
577
+ property :created_at
578
+
579
+ def role
580
+ represented.role.name
581
+ end
582
+ end
583
+ end
584
+ ```
585
+
586
+
587
+ ### Validations
588
+
589
+ In `app/endpoint_flux/validations` you can locate a custom validation classes and use them with Validator middleware.
590
+
591
+
592
+ ### Services
593
+
594
+ You can move some business logic from endpoints to service object and locate it here `app/endpoint_flux/services`.
595
+
596
+
597
+ ### Exceptions
598
+
599
+ You can use EndpointFlux predefined Exceptions for you business logic, for example
600
+ `raise ::EndpointFlux::Exceptions::Validation`.
601
+ They defined in
602
+ [lib/endpoint_flux/exceptions](https://github.com/resolving/endpoint-flux/tree/master/lib/endpoint_flux/exceptions)
603
+
604
+ The list of exceptions:
605
+ * `Forbidden`
606
+ * `NotFound`
607
+ * `ServiceUnavailable`
608
+ * `Unauthorized`
609
+ * `Validation`
610
+
611
+
612
+ ### Response helpers
613
+
614
+ If needs you can use the response helpers to check the response body status such as `success?`, `invalid?` or
615
+ you can define your own helpers in that way. You can use it with an instance of the `EndpointFlux::Response` class.
616
+ They defined in
617
+ [lib/endpoint_flux/response.rb](https://github.com/resolving/endpoint-flux/blob/master/lib/endpoint_flux/response.rb)
618
+
619
+ The list of helpers:
620
+ * `success?`
621
+ * `invalid?`
622
+ * `forbidden?`
623
+ * `unauthorized?`
624
+ * `not_found?`
625
+
626
+
627
+ ## [Contributing](CONTRIBUTING.md)
628
+
629
+ ### [Maintainers](https://github.com/resolving/endpoint-flux/graphs/contributors)
630
+
631
+
632
+ ## License
633
+
634
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).