tramway-api 1.1.0.1 → 1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +272 -11
- data/app/controllers/tramway/api/v1/records_controller.rb +25 -2
- data/app/controllers/tramway/api/v1/users_controller.rb +1 -0
- data/lib/tramway/api/version.rb +1 -1
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 875752ec80bea3a12cdac3f2a3424f777fc0bcf4a94b6c28a5f1c4f98e5a6e34
|
4
|
+
data.tar.gz: ce5f8b2cb550ad0d1a5495ae622152119dc4253dd045fa348fa6921a88751691
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8b629b1c487b02b054885db26d4e49b97ed652cda40cb4d53e11d25cca170d8d0d876619b13df307cb0a19290d9f7447196dc4f24b5c7962edfad26092a194ff
|
7
|
+
data.tar.gz: 37241c50fc18e27b16fb2c4a2c7eb10ec611b163a046c92cca128a95ca9127950e0e739ddc5ff468890cc40da59bca2d569c04b1d7a8cfac7c24d3baba6fcc86
|
data/README.md
CHANGED
@@ -1,26 +1,287 @@
|
|
1
1
|
# Tramway::Api
|
2
|
-
|
2
|
+
|
3
|
+
## English Readme
|
4
|
+
|
5
|
+
coming soon...
|
6
|
+
|
7
|
+
## Russian Readme
|
8
|
+
|
9
|
+
Простой в использовании, легко устанавливаемый и плохо кастомизируемый Rails-engine с готовым CRUD через API.
|
10
|
+
|
11
|
+
Принцип работы. В приложении заранее указывается для каких моделей создаётся API CRUD. Идея проекта - возможность быстрой выкатки API, с возможностью в последствии избавиться от Tramway API, когда ваш проект становится сложнее.
|
12
|
+
|
13
|
+
Гем НЕ манкипатчит стандартные классы и поведение Rails! Именно по этой причине было решено реализовать как Rails-engine, который в последствии можно просто и легко удалить из проекта.
|
14
|
+
|
15
|
+
Фичи:
|
16
|
+
|
17
|
+
* готовый CRUD для определённых разработчиком моделей
|
18
|
+
* сохранение истории изменений записей (используется гем `audited`)
|
19
|
+
* поддержка загрузки файлов (используется `carrierwave`)
|
20
|
+
* аутентификация пользователя через JWT (используется `knock`)
|
21
|
+
* поддержка по умолчанию JSON API спецификации (через гем `active_model_serializers`)
|
22
|
+
* мягкое удаление записей по умолчанию
|
23
|
+
* поддержка коммуникации по уникальному uid объектов, чтобы не публиковать ID в базе
|
24
|
+
|
25
|
+
Ограничения:
|
26
|
+
|
27
|
+
* только с ActiveRecord
|
28
|
+
* только с версией Rails 5.1.* (поддержка 5.2 вскоре будет реализована автором гема, поддержка автором Rails 6 начнётся с версии 6.1. По религиозным автор не использует Rails версий *.0.*
|
29
|
+
* Ruby >= 2.3
|
30
|
+
* все модели, которые будут использованы гемом должны наследоваться от `Tramway::Core::ApplicationRecord`
|
31
|
+
* все модели, которые будут использованы гемом должны иметь атрибут `state`, типа `string` или `text`. Этот атрибут нужен для реализации мягкого удаления. Полное удаление записей из базы не поддерживается
|
32
|
+
* все модели, которые будут использованы гемом должны иметь атрибут
|
33
|
+
|
34
|
+
Недостатки, которые будут вскоре ликвидированы:
|
35
|
+
|
36
|
+
* ядро `tramway-core` подгружает в себя ненужных для API гемов (недостаток не имеет смысла в случае использования вместе с этим решением гема `tramway-admin`):
|
37
|
+
* bootstrap
|
38
|
+
* font_awesome5_rails
|
39
|
+
* haml
|
40
|
+
* требуется ручное добавление требуемых для работы гемов
|
41
|
+
```ruby
|
42
|
+
gem 'active_model_serializers', '0.10.5'
|
43
|
+
gem 'tramway-core'
|
44
|
+
gem 'state_machine', github: 'seuros/state_machine'
|
45
|
+
gem 'knock'
|
46
|
+
```
|
3
47
|
|
4
48
|
## Usage
|
5
|
-
How to use my plugin.
|
6
49
|
|
7
|
-
|
8
|
-
|
50
|
+
```
|
51
|
+
rails new tramway_api_sample
|
52
|
+
```
|
53
|
+
|
54
|
+
*Gemfile*
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
gem 'tramway-api', '>= 1.1.0.1'
|
58
|
+
gem 'active_model_serializers', '0.10.5'
|
59
|
+
gem 'tramway-core'
|
60
|
+
gem 'state_machine', github: 'seuros/state_machine'
|
61
|
+
gem 'knock'
|
62
|
+
```
|
63
|
+
|
64
|
+
Run `bundle install`
|
65
|
+
|
66
|
+
Then generate User (you use another name, it's just an example) model
|
67
|
+
|
68
|
+
```
|
69
|
+
rails g model user email:text password_digest:text username:text state:text uid:text
|
70
|
+
```
|
71
|
+
|
72
|
+
Add generating uid by default
|
73
|
+
|
74
|
+
*db/migrate/create_users_*.rb
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
t.uuid :uid, default: 'uuid_generate_v4()'
|
78
|
+
```
|
79
|
+
|
80
|
+
*app/models/user.rb*
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
class User < Tramway::Core::ApplicationRecord
|
84
|
+
has_secure_password
|
85
|
+
end
|
86
|
+
```
|
87
|
+
|
88
|
+
Create file `config/initializers/tramway.rb`
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
::Tramway::Api.auth_config = { user_model: User, auth_attributes: %i[email username] }
|
92
|
+
::Tramway::Api.set_available_models user: %i[create update]
|
93
|
+
```
|
94
|
+
|
95
|
+
Run `rails g tramway:core:install`
|
96
|
+
|
97
|
+
Run `rails db:create db:migrate`
|
98
|
+
|
99
|
+
*config/routes.rb*
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
Rails.application.routes.draw do
|
103
|
+
mount Tramway::Api::Engine, at: '/api'
|
104
|
+
end
|
105
|
+
```
|
106
|
+
|
107
|
+
Create file *app/forms/user_sign_up_form.rb*
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
class UserSignUpForm < Tramway::Core::ApplicationForm
|
111
|
+
properties :username, :email, :password
|
112
|
+
end
|
113
|
+
```
|
114
|
+
|
115
|
+
**DONE!**
|
116
|
+
|
117
|
+
## Testing
|
118
|
+
|
119
|
+
# Preparation (optional)
|
120
|
+
|
121
|
+
Let's write RSpec test to check what we have:
|
122
|
+
|
123
|
+
*Gemfile*
|
9
124
|
|
10
125
|
```ruby
|
11
|
-
|
126
|
+
group :test do
|
127
|
+
gem 'rspec-rails', '~> 3.5'
|
128
|
+
gem 'rspec-json_expectations', '2.2.0'
|
129
|
+
gem 'factory_bot_rails', '~> 4.0'
|
130
|
+
gem 'json_matchers'
|
131
|
+
gem 'json_api_test_helpers', '1.1.1'
|
132
|
+
end
|
12
133
|
```
|
13
134
|
|
14
|
-
|
15
|
-
|
16
|
-
|
135
|
+
Run `bundle install`
|
136
|
+
|
137
|
+
Run `RAILS_ENV=test rails db:create db:migrate`
|
138
|
+
|
139
|
+
Run `mkdir spec`
|
140
|
+
|
141
|
+
Create file `spec/spec_helper.rb` with:
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
ENV['RAILS_ENV'] ||= 'test'
|
145
|
+
require File.expand_path('../config/environment', __dir__)
|
146
|
+
require 'rspec/rails'
|
147
|
+
require 'rspec/autorun'
|
148
|
+
require 'rspec/expectations'
|
149
|
+
require 'rspec/json_expectations'
|
150
|
+
|
151
|
+
RSpec.configure do |config|
|
152
|
+
config.expect_with :rspec do |expectations|
|
153
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
154
|
+
end
|
155
|
+
config.mock_with :rspec do |mocks|
|
156
|
+
mocks.verify_partial_doubles = true
|
157
|
+
end
|
158
|
+
end
|
17
159
|
```
|
18
160
|
|
19
|
-
|
20
|
-
|
21
|
-
|
161
|
+
Create file `spec/rails_helper.rb` with:
|
162
|
+
|
163
|
+
```ruby
|
164
|
+
require 'spec_helper'
|
165
|
+
require 'factory_bot'
|
166
|
+
require 'rspec/rails'
|
167
|
+
require 'rspec/json_expectations'
|
168
|
+
require 'json_matchers/rspec'
|
169
|
+
require 'json_api_test_helpers'
|
170
|
+
require 'rake'
|
171
|
+
|
172
|
+
RSpec.configure do |config|
|
173
|
+
config.include FactoryBot::Syntax::Methods
|
174
|
+
config.include RSpec::Rails::RequestExampleGroup, type: :feature
|
175
|
+
config.include JsonApiTestHelpers
|
176
|
+
end
|
22
177
|
```
|
23
178
|
|
179
|
+
# SignUp user
|
180
|
+
|
181
|
+
Create file `spec/tramway_api_spec.rb` with:
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
require 'rails_helper'
|
185
|
+
|
186
|
+
RSpec.describe 'Post creating user', type: :feature do
|
187
|
+
describe 'POST /api/v1/user with model User' do
|
188
|
+
let(:attributes) { attributes_for :user }
|
189
|
+
|
190
|
+
it 'returns created status' do
|
191
|
+
post '/api/v1/user', params: { user: attributes }
|
192
|
+
expect(response.status).to eq 201
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'returns no errors' do
|
196
|
+
post '/api/v1/user', params: { user: attributes }
|
197
|
+
|
198
|
+
expect(json_response[:response]). to be_nil
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
```
|
203
|
+
|
204
|
+
# SignIn User
|
205
|
+
|
206
|
+
```ruby
|
207
|
+
require 'rails_helper'
|
208
|
+
|
209
|
+
RSpec.describe 'Post generate token', type: :feature do
|
210
|
+
describe 'POST /api/v1/user_token' do
|
211
|
+
let(:user) { create :user, password: '123456789' }
|
212
|
+
|
213
|
+
it 'returns created status' do
|
214
|
+
post '/api/v1/user_token', params: { auth: { login: user.email, password: '123456789' } }
|
215
|
+
|
216
|
+
expect(response.status).to eq 201
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'returns token' do
|
220
|
+
post '/api/v1/user_token', params: { auth: { login: user.email, password: '123456789' } }
|
221
|
+
|
222
|
+
expect(json_response[:auth_token].present?).to be_truthy
|
223
|
+
expect(json_response[:user]).to include_json({ email: user.email, uid: user.uid })
|
224
|
+
end
|
225
|
+
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
```
|
230
|
+
|
231
|
+
Run `rspec` to test
|
232
|
+
|
233
|
+
We have route `user`, which create new authenticable user.
|
234
|
+
|
235
|
+
For other models we have route `records`.
|
236
|
+
|
237
|
+
```
|
238
|
+
~: rails routes
|
239
|
+
Prefix Verb URI Pattern Controller#Action
|
240
|
+
tramway_api /api Tramway::Api::Engine
|
241
|
+
|
242
|
+
Routes for Tramway::Api::Engine:
|
243
|
+
v1_user_token POST /v1/user_token(.:format) tramway/api/v1/user_tokens#create
|
244
|
+
v1_user GET /v1/user(.:format) tramway/api/v1/users#show
|
245
|
+
POST /v1/user(.:format) tramway/api/v1/users#create
|
246
|
+
v1_records GET /v1/records(.:format) tramway/api/v1/records#index
|
247
|
+
POST /v1/records(.:format) tramway/api/v1/records#create
|
248
|
+
new_v1_record GET /v1/records/new(.:format) tramway/api/v1/records#new
|
249
|
+
edit_v1_record GET /v1/records/:id/edit(.:format) tramway/api/v1/records#edit
|
250
|
+
v1_record GET /v1/records/:id(.:format) tramway/api/v1/records#show
|
251
|
+
PATCH /v1/records/:id(.:format) tramway/api/v1/records#update
|
252
|
+
PUT /v1/records/:id(.:format) tramway/api/v1/records#update
|
253
|
+
DELETE /v1/records/:id(.:format) tramway/api/v1/records#destroy
|
254
|
+
|
255
|
+
```
|
256
|
+
|
257
|
+
## Methods
|
258
|
+
|
259
|
+
### Initializer methods
|
260
|
+
|
261
|
+
#### auth_config
|
262
|
+
|
263
|
+
Sets default ActiveRecord model, which used as main user to be authenticated with JWT.
|
264
|
+
|
265
|
+
`user_model` - model name
|
266
|
+
`auth_attributes` - array of available attributes used as login.
|
267
|
+
|
268
|
+
this model must have field `password_digest`, because we use `bcrypt` gem for authentication (providing other name of password attribute instead of `password` is coming soon)
|
269
|
+
|
270
|
+
### set_available_models
|
271
|
+
|
272
|
+
Sets ActiveRecord models which will be used in API
|
273
|
+
|
274
|
+
Argument is a hash. Keys are underscored models names, values are arrays of available methods for every model.
|
275
|
+
|
276
|
+
Enabled methods:
|
277
|
+
|
278
|
+
* create
|
279
|
+
* update
|
280
|
+
* show
|
281
|
+
* index
|
282
|
+
* destroy
|
283
|
+
|
284
|
+
|
24
285
|
## Contributing
|
25
286
|
Contribution directions go here.
|
26
287
|
|
@@ -2,6 +2,7 @@ module Tramway::Api::V1
|
|
2
2
|
class RecordsController < ::Tramway::Api::V1::ApplicationController
|
3
3
|
before_action :check_available_model_class
|
4
4
|
before_action :check_available_model_action
|
5
|
+
before_action :authenticate_user_if_needed
|
5
6
|
|
6
7
|
def index
|
7
8
|
records = model_class.active.order(id: :desc).send params[:scope] || :all
|
@@ -22,7 +23,7 @@ module Tramway::Api::V1
|
|
22
23
|
end
|
23
24
|
|
24
25
|
def update
|
25
|
-
record_form = form_class.new model_class.find params[:id]
|
26
|
+
record_form = form_class.new model_class.active.find params[:id]
|
26
27
|
if record_form.submit params[:data][:attributes]
|
27
28
|
render json: record_form.model,
|
28
29
|
serializer: serializer_class,
|
@@ -32,6 +33,21 @@ module Tramway::Api::V1
|
|
32
33
|
end
|
33
34
|
end
|
34
35
|
|
36
|
+
def show
|
37
|
+
record = model_class.active.find params[:id]
|
38
|
+
render json: record,
|
39
|
+
serializer: serializer_class,
|
40
|
+
status: :ok
|
41
|
+
end
|
42
|
+
|
43
|
+
def destroy
|
44
|
+
record = model_class.active.find params[:id]
|
45
|
+
record.remove
|
46
|
+
render json: record,
|
47
|
+
serializer: serializer_class,
|
48
|
+
status: :no_content
|
49
|
+
end
|
50
|
+
|
35
51
|
private
|
36
52
|
|
37
53
|
def check_available_model_class
|
@@ -39,7 +55,14 @@ module Tramway::Api::V1
|
|
39
55
|
end
|
40
56
|
|
41
57
|
def check_available_model_action
|
42
|
-
|
58
|
+
actions = Tramway::Api.available_models[model_class.to_s][:open]&.map(&:to_s) || [] + Tramway::Api.available_models[model_class.to_s][:closed]&.map(&:to_s) || []
|
59
|
+
head :unprocessable_entity and return unless action_name.in? actions
|
60
|
+
end
|
61
|
+
|
62
|
+
def authenticate_user_if_needed
|
63
|
+
if action_name.in? Tramway::Api::available_models[model_class.to_s][:closed]&.map(&:to_s) || []
|
64
|
+
authenticate_user
|
65
|
+
end
|
43
66
|
end
|
44
67
|
|
45
68
|
def model_class
|
@@ -6,6 +6,7 @@ class Tramway::Api::V1::UsersController < ::Tramway::Api::V1::ApplicationControl
|
|
6
6
|
|
7
7
|
def create
|
8
8
|
user_form = sign_up_form_class_name(Tramway::Api.user_based_model).new Tramway::Api.user_based_model.new
|
9
|
+
# Implement JSON API spec here
|
9
10
|
if user_form.submit params[Tramway::Api.user_based_model.name.underscore]
|
10
11
|
token = ::Knock::AuthToken.new(payload: { sub: user_form.model.id }).token
|
11
12
|
# FIXME refactor this bullshit
|
data/lib/tramway/api/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tramway-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: '1.4'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pavel Kalashnikov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-09-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: knock
|
@@ -99,8 +99,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
99
99
|
- !ruby/object:Gem::Version
|
100
100
|
version: '0'
|
101
101
|
requirements: []
|
102
|
-
|
103
|
-
rubygems_version: 2.7.6
|
102
|
+
rubygems_version: 3.0.3
|
104
103
|
signing_key:
|
105
104
|
specification_version: 4
|
106
105
|
summary: Engine for api
|