rest_framework 0.0.1 → 0.0.7
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 +4 -4
- data/README.md +6 -3
- data/app/views/layouts/rest_framework.html.erb +38 -0
- data/app/views/rest_framework/_head.html.erb +19 -0
- data/app/views/rest_framework/_routes.html.erb +18 -0
- data/app/views/rest_framework/default.html.erb +0 -0
- data/lib/rest_framework.rb +1 -0
- data/lib/rest_framework/VERSION_STAMP +1 -1
- data/lib/rest_framework/controllers/base.rb +57 -18
- data/lib/rest_framework/controllers/models.rb +8 -10
- data/lib/rest_framework/engine.rb +2 -0
- data/lib/rest_framework/routers.rb +2 -2
- metadata +8 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5a70372b29a6a1f71c62ecfe54f87836c185986e0786be23c73d8da52c73e3d3
|
|
4
|
+
data.tar.gz: fa48c80ce2d183f31c3e9791a454462fd157f803bd3f77f620ebad13bb9b86a2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4c7819ea220f5a41890320d5f7c4667d9989d9a23a46c6d9e53b4c8fe558f187cbfa094616ade0013b2ed8a28732024403d416449589167d759eaa8f0df432b0
|
|
7
|
+
data.tar.gz: cf92ba584de58531b31ed33a1855270324559a4484c29a4ea953e4b2093080db3923e1ded3be6fedac867985febf11dbdfaf07600879b02ff6a17f5b87cef473
|
data/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# REST Framework
|
|
2
2
|
|
|
3
|
+
[](https://badge.fury.io/rb/rest_framework)
|
|
4
|
+
[](https://travis-ci.org/gregschmit/rails-rest-framework)
|
|
5
|
+
|
|
3
6
|
REST Framework helps you build awesome APIs in Ruby on Rails.
|
|
4
7
|
|
|
5
8
|
**The Problem**: Building controllers for APIs usually involves writing a lot of redundant CRUD
|
|
@@ -65,13 +68,13 @@ end
|
|
|
65
68
|
```
|
|
66
69
|
|
|
67
70
|
Note that you can also override `get_model` and `get_recordset` instance methods to override the API
|
|
68
|
-
behavior
|
|
71
|
+
behavior dynamically per-request.
|
|
69
72
|
|
|
70
73
|
### Routing
|
|
71
74
|
|
|
72
75
|
You can use Rails' `resource`/`resources` routers to route your API, however if you want
|
|
73
|
-
`@extra_actions
|
|
74
|
-
`rest_resource
|
|
76
|
+
`@extra_actions` / `@extra_member_actions` to be routed automatically, then you can use the
|
|
77
|
+
`rest_resource` / `rest_resources` routers provided by this gem. You can also use `rest_root` to route
|
|
75
78
|
the root of your API:
|
|
76
79
|
|
|
77
80
|
```
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title><%= @title %></title>
|
|
5
|
+
<%= render partial: 'rest_framework/head' %>
|
|
6
|
+
</head>
|
|
7
|
+
|
|
8
|
+
<body>
|
|
9
|
+
<div class="bg-dark">
|
|
10
|
+
<div class="w-100 m-0 p-0" style="height: .3em; background-color: #a00;"></div>
|
|
11
|
+
<nav class="navbar navbar-dark bg-dark">
|
|
12
|
+
<div class="container">
|
|
13
|
+
<span class="navbar-brand p-0">
|
|
14
|
+
<h1 class="text-light font-weight-light m-0 p-0" style="font-size: 1em"><%= @template_logo_text %></h1>
|
|
15
|
+
</span>
|
|
16
|
+
</div>
|
|
17
|
+
</nav>
|
|
18
|
+
</div>
|
|
19
|
+
<div class="container py-3">
|
|
20
|
+
<div class="container">
|
|
21
|
+
<div class="row">
|
|
22
|
+
<h1><%= @title %></h1>
|
|
23
|
+
</div>
|
|
24
|
+
<hr/>
|
|
25
|
+
<div class="row">
|
|
26
|
+
<h2>Payload</h2><br>
|
|
27
|
+
<div><pre><%= JSON.pretty_generate(JSON.parse(@serialized_payload)) unless @serialized_payload.blank? %></pre></div>
|
|
28
|
+
</div>
|
|
29
|
+
<% unless @routes.blank? %>
|
|
30
|
+
<div class="row">
|
|
31
|
+
<h2>Routes</h2>
|
|
32
|
+
<%= render partial: 'rest_framework/routes' %>
|
|
33
|
+
</div>
|
|
34
|
+
<% end %>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
</body>
|
|
38
|
+
</html>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<meta charset="utf-8">
|
|
2
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
3
|
+
<%= csrf_meta_tags %>
|
|
4
|
+
<%= csp_meta_tag rescue nil %>
|
|
5
|
+
|
|
6
|
+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
|
|
7
|
+
<style>
|
|
8
|
+
h1,h2,h3,h4,h5,h6 { width: 100%; }
|
|
9
|
+
h1 { font-size: 2rem; }
|
|
10
|
+
h2 { font-size: 1.7rem; }
|
|
11
|
+
h3 { font-size: 1.5rem; }
|
|
12
|
+
h4 { font-size: 1.3rem; }
|
|
13
|
+
h5 { font-size: 1.1rem; }
|
|
14
|
+
h6 { font-size: 1rem; }
|
|
15
|
+
</style>
|
|
16
|
+
|
|
17
|
+
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
|
|
18
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
|
|
19
|
+
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<table class="table">
|
|
2
|
+
<thead>
|
|
3
|
+
<tr>
|
|
4
|
+
<th scope="col">Verb</th>
|
|
5
|
+
<th scope="col">Path</th>
|
|
6
|
+
<th scope="col">Action</th>
|
|
7
|
+
</tr>
|
|
8
|
+
</thead>
|
|
9
|
+
<tbody>
|
|
10
|
+
<% @routes.each do |r| %>
|
|
11
|
+
<tr>
|
|
12
|
+
<td><%= r[:verb] %></td>
|
|
13
|
+
<td><%= r[:path] %></td>
|
|
14
|
+
<td><%= r[:action] %></td>
|
|
15
|
+
</tr>
|
|
16
|
+
<% end %>
|
|
17
|
+
</tbody>
|
|
18
|
+
</table>
|
|
File without changes
|
data/lib/rest_framework.rb
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.0.
|
|
1
|
+
0.0.7
|
|
@@ -2,7 +2,6 @@ module RESTFramework
|
|
|
2
2
|
|
|
3
3
|
# This module provides helpers for mixin `ClassMethods` submodules.
|
|
4
4
|
module ClassMethodHelpers
|
|
5
|
-
|
|
6
5
|
# This helper assists in providing reader interfaces for mixin properties.
|
|
7
6
|
def _restframework_attr_reader(property, default: nil)
|
|
8
7
|
method = <<~RUBY
|
|
@@ -22,9 +21,8 @@ module RESTFramework
|
|
|
22
21
|
# is defined.
|
|
23
22
|
module BaseControllerMixin
|
|
24
23
|
# Default action for API root.
|
|
25
|
-
# TODO: use api_response and show sub-routes.
|
|
26
24
|
def root
|
|
27
|
-
|
|
25
|
+
api_response({message: "This is the root of your awesome API!"})
|
|
28
26
|
end
|
|
29
27
|
|
|
30
28
|
protected
|
|
@@ -32,27 +30,25 @@ module RESTFramework
|
|
|
32
30
|
module ClassMethods
|
|
33
31
|
extend ClassMethodHelpers
|
|
34
32
|
|
|
35
|
-
# Interface for getting class-level instance/class variables.
|
|
33
|
+
# Interface for getting class-level instance/class variables. Note: we check if they are
|
|
34
|
+
# defined first rather than rescuing NameError to prevent uninitialized variable warnings.
|
|
36
35
|
private def _restframework_try_class_level_variable_get(name, default: nil)
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
instance_variable = "@#{name}"
|
|
37
|
+
if self.instance_variable_defined?(instance_variable)
|
|
38
|
+
v = self.instance_variable_get(instance_variable)
|
|
39
39
|
return v unless v.nil?
|
|
40
|
-
rescue NameError
|
|
41
40
|
end
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
class_variable = "@@#{name}"
|
|
42
|
+
if self.class_variable_defined?(class_variable)
|
|
43
|
+
v = self.class_variable_get(class_variable)
|
|
44
44
|
return v unless v.nil?
|
|
45
|
-
rescue NameError
|
|
46
45
|
end
|
|
47
46
|
return default
|
|
48
47
|
end
|
|
49
48
|
|
|
50
|
-
|
|
51
|
-
# private def _restframework_register_exception_handlers
|
|
52
|
-
# rescue_from
|
|
53
|
-
# end
|
|
54
|
-
|
|
49
|
+
_restframework_attr_reader(:singleton_controller)
|
|
55
50
|
_restframework_attr_reader(:extra_actions, default: {})
|
|
51
|
+
_restframework_attr_reader(:template_logo_text, default: 'Rails REST Framework')
|
|
56
52
|
|
|
57
53
|
def skip_actions(skip_undefined: true)
|
|
58
54
|
# first, skip explicitly skipped actions
|
|
@@ -73,11 +69,54 @@ module RESTFramework
|
|
|
73
69
|
base.extend ClassMethods
|
|
74
70
|
end
|
|
75
71
|
|
|
72
|
+
def _get_routes
|
|
73
|
+
begin
|
|
74
|
+
formatter = ActionDispatch::Routing::ConsoleFormatter::Sheet
|
|
75
|
+
rescue NameError
|
|
76
|
+
formatter = ActionDispatch::Routing::ConsoleFormatter
|
|
77
|
+
end
|
|
78
|
+
return ActionDispatch::Routing::RoutesInspector.new(Rails.application.routes.routes).format(
|
|
79
|
+
formatter.new
|
|
80
|
+
).lines[1..].map { |r| r.split.last(3) }.map { |r|
|
|
81
|
+
{verb: r[0], path: r[1], action: r[2]}
|
|
82
|
+
}.select { |r| r[:path].start_with?(request.path) }
|
|
83
|
+
end
|
|
84
|
+
|
|
76
85
|
# Helper alias for `respond_to`/`render`, and replace nil responses with blank ones.
|
|
77
|
-
def api_response(
|
|
86
|
+
def api_response(payload, html_kwargs: nil, json_kwargs: nil, **kwargs)
|
|
87
|
+
html_kwargs ||= {}
|
|
88
|
+
json_kwargs ||= {}
|
|
89
|
+
|
|
90
|
+
# serialize the payload if it's not blank
|
|
91
|
+
if payload.blank?
|
|
92
|
+
serialized_payload = ''
|
|
93
|
+
else
|
|
94
|
+
if self.respond_to?(:get_model_serializer_config, true)
|
|
95
|
+
serialized_payload = payload.to_json(self.get_model_serializer_config)
|
|
96
|
+
else
|
|
97
|
+
serialized_payload = payload.to_json
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
78
101
|
respond_to do |format|
|
|
79
|
-
format.html
|
|
80
|
-
|
|
102
|
+
format.html {
|
|
103
|
+
kwargs = kwargs.merge(html_kwargs)
|
|
104
|
+
@template_logo_text ||= self.class.template_logo_text
|
|
105
|
+
@title ||= self.controller_name.camelize
|
|
106
|
+
@routes ||= self._get_routes
|
|
107
|
+
@payload = payload
|
|
108
|
+
@serialized_payload = serialized_payload
|
|
109
|
+
begin
|
|
110
|
+
render(**kwargs)
|
|
111
|
+
rescue ActionView::MissingTemplate # fallback to rest_framework default view
|
|
112
|
+
kwargs[:template] = "rest_framework/default"
|
|
113
|
+
end
|
|
114
|
+
render(**kwargs)
|
|
115
|
+
}
|
|
116
|
+
format.json {
|
|
117
|
+
kwargs = kwargs.merge(json_kwargs)
|
|
118
|
+
render(json: serialized_payload || '', **kwargs)
|
|
119
|
+
}
|
|
81
120
|
end
|
|
82
121
|
end
|
|
83
122
|
end
|
|
@@ -21,7 +21,6 @@ module RESTFramework
|
|
|
21
21
|
|
|
22
22
|
_restframework_attr_reader(:model)
|
|
23
23
|
_restframework_attr_reader(:recordset)
|
|
24
|
-
_restframework_attr_reader(:singleton_controller)
|
|
25
24
|
|
|
26
25
|
_restframework_attr_reader(:fields)
|
|
27
26
|
_restframework_attr_reader(:list_fields)
|
|
@@ -51,7 +50,7 @@ module RESTFramework
|
|
|
51
50
|
|
|
52
51
|
# Get a list of fields for the current action.
|
|
53
52
|
def get_fields
|
|
54
|
-
return @fields if @fields
|
|
53
|
+
return @fields if instance_variable_defined?(:@fields) && @fields
|
|
55
54
|
|
|
56
55
|
# index action should use list_fields
|
|
57
56
|
name = (action_name == 'index') ? 'list' : action_name
|
|
@@ -60,9 +59,8 @@ module RESTFramework
|
|
|
60
59
|
@fields = self.class.send("#{name}_fields")
|
|
61
60
|
rescue NameError
|
|
62
61
|
end
|
|
63
|
-
@fields ||= self.class.fields || []
|
|
64
62
|
|
|
65
|
-
return @fields
|
|
63
|
+
return @fields ||= self.class.fields || []
|
|
66
64
|
end
|
|
67
65
|
|
|
68
66
|
# Get a configuration passable to `as_json` for the model.
|
|
@@ -113,7 +111,7 @@ module RESTFramework
|
|
|
113
111
|
|
|
114
112
|
# Internal interface for get_model, protecting against infinite recursion with get_recordset.
|
|
115
113
|
def _get_model(from_internal_get_recordset: false)
|
|
116
|
-
return @model if @model
|
|
114
|
+
return @model if instance_variable_defined?(:@model) && @model
|
|
117
115
|
return self.class.model if self.class.model
|
|
118
116
|
unless from_internal_get_recordset # prevent infinite recursion
|
|
119
117
|
recordset = self._get_recordset(from_internal_get_model: true)
|
|
@@ -128,7 +126,7 @@ module RESTFramework
|
|
|
128
126
|
|
|
129
127
|
# Internal interface for get_recordset, protecting against infinite recursion with get_model.
|
|
130
128
|
def _get_recordset(from_internal_get_model: false)
|
|
131
|
-
return @recordset if @recordset
|
|
129
|
+
return @recordset if instance_variable_defined?(:@recordset) && @recordset
|
|
132
130
|
return self.class.recordset if self.class.recordset
|
|
133
131
|
unless from_internal_get_model # prevent infinite recursion
|
|
134
132
|
model = self._get_model(from_internal_get_recordset: true)
|
|
@@ -152,14 +150,14 @@ module RESTFramework
|
|
|
152
150
|
# TODO: pagination classes like Django
|
|
153
151
|
def index
|
|
154
152
|
@records = self.get_filtered_recordset
|
|
155
|
-
api_response(@records
|
|
153
|
+
api_response(@records)
|
|
156
154
|
end
|
|
157
155
|
end
|
|
158
156
|
|
|
159
157
|
module ShowModelMixin
|
|
160
158
|
def show
|
|
161
159
|
@record = self.get_record
|
|
162
|
-
api_response(@record
|
|
160
|
+
api_response(@record)
|
|
163
161
|
end
|
|
164
162
|
end
|
|
165
163
|
|
|
@@ -170,7 +168,7 @@ module RESTFramework
|
|
|
170
168
|
rescue ActiveRecord::RecordInvalid => e
|
|
171
169
|
api_response(e.record.messages, status: 400)
|
|
172
170
|
end
|
|
173
|
-
api_response(@record
|
|
171
|
+
api_response(@record)
|
|
174
172
|
end
|
|
175
173
|
end
|
|
176
174
|
|
|
@@ -180,7 +178,7 @@ module RESTFramework
|
|
|
180
178
|
if @record
|
|
181
179
|
@record.attributes(self.get_update_params)
|
|
182
180
|
@record.save!
|
|
183
|
-
api_response(@record
|
|
181
|
+
api_response(@record)
|
|
184
182
|
else
|
|
185
183
|
api_response({detail: "Record not found."}, status: 404)
|
|
186
184
|
end
|
|
@@ -25,10 +25,10 @@ module ActionDispatch::Routing
|
|
|
25
25
|
|
|
26
26
|
# convert class name to class
|
|
27
27
|
begin
|
|
28
|
-
controller = mod.const_get(name
|
|
28
|
+
controller = mod.const_get(name)
|
|
29
29
|
rescue NameError
|
|
30
30
|
if fallback_reverse_pluralization
|
|
31
|
-
controller = mod.const_get(name_reverse
|
|
31
|
+
controller = mod.const_get(name_reverse)
|
|
32
32
|
else
|
|
33
33
|
raise
|
|
34
34
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rest_framework
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gregory N. Schmit
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2020-09-
|
|
11
|
+
date: 2020-09-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -33,11 +33,16 @@ extra_rdoc_files: []
|
|
|
33
33
|
files:
|
|
34
34
|
- LICENSE
|
|
35
35
|
- README.md
|
|
36
|
+
- app/views/layouts/rest_framework.html.erb
|
|
37
|
+
- app/views/rest_framework/_head.html.erb
|
|
38
|
+
- app/views/rest_framework/_routes.html.erb
|
|
39
|
+
- app/views/rest_framework/default.html.erb
|
|
36
40
|
- lib/rest_framework.rb
|
|
37
41
|
- lib/rest_framework/VERSION_STAMP
|
|
38
42
|
- lib/rest_framework/controllers.rb
|
|
39
43
|
- lib/rest_framework/controllers/base.rb
|
|
40
44
|
- lib/rest_framework/controllers/models.rb
|
|
45
|
+
- lib/rest_framework/engine.rb
|
|
41
46
|
- lib/rest_framework/routers.rb
|
|
42
47
|
- lib/rest_framework/version.rb
|
|
43
48
|
homepage: https://github.com/gregschmit/rails-rest-framework
|
|
@@ -50,6 +55,7 @@ post_install_message:
|
|
|
50
55
|
rdoc_options: []
|
|
51
56
|
require_paths:
|
|
52
57
|
- lib
|
|
58
|
+
- app
|
|
53
59
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
54
60
|
requirements:
|
|
55
61
|
- - ">="
|