rest_framework 0.0.1 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/rest_framework.svg)](https://badge.fury.io/rb/rest_framework)
|
4
|
+
[![Build Status](https://travis-ci.org/gregschmit/rails-rest-framework.svg?branch=master)](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
|
- - ">="
|