jsonapi-resources-home 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +6 -0
- data/README.md +251 -0
- data/Rakefile +15 -0
- data/app/controllers/jsonapi/resources/home/v1/resources_controller.rb +13 -0
- data/app/models/jsonapi/resources/home/v1/resource.rb +110 -0
- data/app/resources/jsonapi/resources/home/v1/resource_resource.rb +30 -0
- data/config/routes.rb +7 -0
- data/lib/jsonapi/resources/home.rb +21 -0
- data/lib/jsonapi/resources/home/engine.rb +9 -0
- data/lib/jsonapi/resources/home/inflector.rb +9 -0
- data/lib/jsonapi/resources/home/version.rb +7 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/controllers/application_controller.rb +2 -0
- data/spec/dummy/app/controllers/v1/accounts_controller.rb +5 -0
- data/spec/dummy/app/controllers/v1/application_controller.rb +5 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/jobs/application_job.rb +2 -0
- data/spec/dummy/app/mailers/application_mailer.rb +4 -0
- data/spec/dummy/app/models/application_record.rb +3 -0
- data/spec/dummy/app/resources/application_resource.rb +4 -0
- data/spec/dummy/app/resources/v1/account_resource.rb +5 -0
- data/spec/dummy/app/resources/v1/application_resource.rb +6 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/bin/setup +38 -0
- data/spec/dummy/bin/update +29 -0
- data/spec/dummy/bin/yarn +11 -0
- data/spec/dummy/config.ru +5 -0
- data/spec/dummy/config/application.rb +18 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/cable.yml +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +54 -0
- data/spec/dummy/config/environments/production.rb +91 -0
- data/spec/dummy/config/environments/test.rb +42 -0
- data/spec/dummy/config/initializers/application_controller_renderer.rb +8 -0
- data/spec/dummy/config/initializers/assets.rb +14 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +33 -0
- data/spec/dummy/config/puma.rb +56 -0
- data/spec/dummy/config/routes.rb +9 -0
- data/spec/dummy/config/secrets.yml +32 -0
- data/spec/dummy/config/spring.rb +6 -0
- data/spec/dummy/log/development.log +5436 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
- data/spec/dummy/public/apple-touch-icon.png +0 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/jsonapi/resources/home_test.rb +0 -0
- data/spec/test_helper.rb +17 -0
- metadata +283 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cff29ba2ac131709adc8c382e99439761195f3c8
|
4
|
+
data.tar.gz: c605fc66880b4926dd8ffc6375e8d3a9c907f588
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f2d4c7d8dbd83f16ef17d861d4bdac0f33c17518730e273fd29a3bf1fc18f823dbcef5970ec1c01e8eb9571a7e8dd03a5f3d8f2d2b32aad65f82e4458ab4f46c
|
7
|
+
data.tar.gz: e7e289f4cac855522c1bbf048f0ac7eb6e45ffd7134624257057e41f6bd5c42f3e9ac6565a7e8e1e7dd6e1fdfac7d55e23b883989e39ee94ea3916cb2f904e4e
|
data/LICENSE
ADDED
@@ -0,0 +1,6 @@
|
|
1
|
+
ISC License (ISC)
|
2
|
+
Copyright 2017 Kurtis Rainbolt-Greene
|
3
|
+
|
4
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
|
5
|
+
|
6
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,251 @@
|
|
1
|
+
# jsonapi-resources-home
|
2
|
+
|
3
|
+
- [![Build](http://img.shields.io/travis-ci/krainboltgreene/blankgem.gem.svg?style=flat-square)](https://travis-ci.org/krainboltgreene/blankgem.gem)
|
4
|
+
- [![License](http://img.shields.io/badge/license-ISC-brightgreen.svg?style=flat-square)](http://opensource.org/licenses/ISC)
|
5
|
+
- [![Version](http://img.shields.io/gem/v/blankgem.svg?style=flat-square)](https://rubygems.org/gems/blankgem)
|
6
|
+
|
7
|
+
An implementation of JSONAPIHome (which is a fork of JSONHome).
|
8
|
+
|
9
|
+
|
10
|
+
## Using
|
11
|
+
|
12
|
+
First, set yourself up with a `HOME_LOCATION`, this is the protocol+hostname[+suffix] combination where your api exists:
|
13
|
+
|
14
|
+
```
|
15
|
+
HOME_LOCATION=https://origin.example.com
|
16
|
+
``
|
17
|
+
|
18
|
+
To have this all work you just need to mount the engine:
|
19
|
+
|
20
|
+
``` ruby
|
21
|
+
Rails.application.routes.draw do
|
22
|
+
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
|
23
|
+
|
24
|
+
mount JSONAPI::Resources::Home::Engine, at: "/"
|
25
|
+
|
26
|
+
namespace :v1 do
|
27
|
+
jsonapi_resources :accounts
|
28
|
+
end
|
29
|
+
end
|
30
|
+
```
|
31
|
+
|
32
|
+
This will setup the basic set of home routes, and with this request:
|
33
|
+
|
34
|
+
```
|
35
|
+
* Preparing request to http://localhost:3000/v1/resources
|
36
|
+
* Enable automatic URL encoding
|
37
|
+
* Enable SSL validation
|
38
|
+
* Enable cookie sending with jar of 0 cookies
|
39
|
+
* Found bundle for host localhost: 0x7fe522cdb340 [can pipeline]
|
40
|
+
* Re-using existing connection! (#29) with host localhost
|
41
|
+
* Connected to localhost (::1) port 3000 (#29)
|
42
|
+
> GET /v1/resources HTTP/1.1
|
43
|
+
> Host: localhost:3000
|
44
|
+
> User-Agent: insomnia/5.9.6
|
45
|
+
> Accept: */*
|
46
|
+
> Accept-Encoding: deflate, gzip
|
47
|
+
```
|
48
|
+
|
49
|
+
You'll get this payload:
|
50
|
+
|
51
|
+
``` json
|
52
|
+
{
|
53
|
+
"data": []
|
54
|
+
}
|
55
|
+
```
|
56
|
+
|
57
|
+
The reason nothing shows up is because we need to opt-in to the jsonapi home endpoint:
|
58
|
+
|
59
|
+
``` ruby
|
60
|
+
module V1
|
61
|
+
class AccountsController < V1::ApplicationController
|
62
|
+
home_discoverable description: "The accounts resource"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
```
|
67
|
+
|
68
|
+
Which results in this payload:
|
69
|
+
|
70
|
+
``` json
|
71
|
+
{
|
72
|
+
"data": [
|
73
|
+
{
|
74
|
+
"id": "accounts-v1-list",
|
75
|
+
"type": "resources",
|
76
|
+
"links": {
|
77
|
+
"self": "http://localhost:3000/jsonapi/resources/home/v1/resources/accounts-v1-list"
|
78
|
+
},
|
79
|
+
"attributes": {
|
80
|
+
"namespace": "accounts",
|
81
|
+
"version": "v1",
|
82
|
+
"intent": "list",
|
83
|
+
"verb": "GET",
|
84
|
+
"href": "http://home.example.com/v1/accounts",
|
85
|
+
"allowed": null,
|
86
|
+
"mediatype": "application/vnd.api+json",
|
87
|
+
"description": "The accounts resource",
|
88
|
+
"created-at": "2017-11-10T00:27:39.039-08:00",
|
89
|
+
"updated-at": "2017-11-10T00:27:39.043-08:00"
|
90
|
+
}
|
91
|
+
},
|
92
|
+
{
|
93
|
+
"id": "accounts-v1-create",
|
94
|
+
"type": "resources",
|
95
|
+
"links": {
|
96
|
+
"self": "http://localhost:3000/jsonapi/resources/home/v1/resources/accounts-v1-create"
|
97
|
+
},
|
98
|
+
"attributes": {
|
99
|
+
"namespace": "accounts",
|
100
|
+
"version": "v1",
|
101
|
+
"intent": "create",
|
102
|
+
"verb": "POST",
|
103
|
+
"href": "http://home.example.com/v1/accounts",
|
104
|
+
"allowed": null,
|
105
|
+
"mediatype": "application/vnd.api+json",
|
106
|
+
"description": "The accounts resource",
|
107
|
+
"created-at": "2017-11-10T00:27:39.039-08:00",
|
108
|
+
"updated-at": "2017-11-10T00:27:39.044-08:00"
|
109
|
+
}
|
110
|
+
},
|
111
|
+
{
|
112
|
+
"id": "accounts-v1-show",
|
113
|
+
"type": "resources",
|
114
|
+
"links": {
|
115
|
+
"self": "http://localhost:3000/jsonapi/resources/home/v1/resources/accounts-v1-show"
|
116
|
+
},
|
117
|
+
"attributes": {
|
118
|
+
"namespace": "accounts",
|
119
|
+
"version": "v1",
|
120
|
+
"intent": "show",
|
121
|
+
"verb": "GET",
|
122
|
+
"href": "http://home.example.com/v1/accounts/{id}",
|
123
|
+
"allowed": null,
|
124
|
+
"mediatype": "application/vnd.api+json",
|
125
|
+
"description": "The accounts resource",
|
126
|
+
"created-at": "2017-11-10T00:27:39.039-08:00",
|
127
|
+
"updated-at": "2017-11-10T00:27:39.044-08:00"
|
128
|
+
}
|
129
|
+
},
|
130
|
+
{
|
131
|
+
"id": "accounts-v1-update",
|
132
|
+
"type": "resources",
|
133
|
+
"links": {
|
134
|
+
"self": "http://localhost:3000/jsonapi/resources/home/v1/resources/accounts-v1-update"
|
135
|
+
},
|
136
|
+
"attributes": {
|
137
|
+
"namespace": "accounts",
|
138
|
+
"version": "v1",
|
139
|
+
"intent": "update",
|
140
|
+
"verb": "PATCH",
|
141
|
+
"href": "http://home.example.com/v1/accounts/{id}",
|
142
|
+
"allowed": null,
|
143
|
+
"mediatype": "application/vnd.api+json",
|
144
|
+
"description": "The accounts resource",
|
145
|
+
"created-at": "2017-11-10T00:27:39.039-08:00",
|
146
|
+
"updated-at": "2017-11-10T00:27:39.045-08:00"
|
147
|
+
}
|
148
|
+
},
|
149
|
+
{
|
150
|
+
"id": "accounts-v1-update",
|
151
|
+
"type": "resources",
|
152
|
+
"links": {
|
153
|
+
"self": "http://localhost:3000/jsonapi/resources/home/v1/resources/accounts-v1-update"
|
154
|
+
},
|
155
|
+
"attributes": {
|
156
|
+
"namespace": "accounts",
|
157
|
+
"version": "v1",
|
158
|
+
"intent": "update",
|
159
|
+
"verb": "PATCH",
|
160
|
+
"href": "http://home.example.com/v1/accounts/{id}",
|
161
|
+
"allowed": null,
|
162
|
+
"mediatype": "application/vnd.api+json",
|
163
|
+
"description": "The accounts resource",
|
164
|
+
"created-at": "2017-11-10T00:27:39.039-08:00",
|
165
|
+
"updated-at": "2017-11-10T00:27:39.045-08:00"
|
166
|
+
}
|
167
|
+
},
|
168
|
+
{
|
169
|
+
"id": "accounts-v1-destroy",
|
170
|
+
"type": "resources",
|
171
|
+
"links": {
|
172
|
+
"self": "http://localhost:3000/jsonapi/resources/home/v1/resources/accounts-v1-destroy"
|
173
|
+
},
|
174
|
+
"attributes": {
|
175
|
+
"namespace": "accounts",
|
176
|
+
"version": "v1",
|
177
|
+
"intent": "destroy",
|
178
|
+
"verb": "DELETE",
|
179
|
+
"href": "http://home.example.com/v1/accounts/{id}",
|
180
|
+
"allowed": null,
|
181
|
+
"mediatype": "application/vnd.api+json",
|
182
|
+
"description": "The accounts resource",
|
183
|
+
"created-at": "2017-11-10T00:27:39.039-08:00",
|
184
|
+
"updated-at": "2017-11-10T00:27:39.046-08:00"
|
185
|
+
}
|
186
|
+
}
|
187
|
+
]
|
188
|
+
}
|
189
|
+
```
|
190
|
+
|
191
|
+
You can also inquire about individual endpoints:
|
192
|
+
|
193
|
+
```
|
194
|
+
* Preparing request to http://localhost:3000/v1/resources/accounts-v1-list
|
195
|
+
* Enable automatic URL encoding
|
196
|
+
* Enable SSL validation
|
197
|
+
* Enable cookie sending with jar of 0 cookies
|
198
|
+
* Connection 65 seems to be dead!
|
199
|
+
* Closing connection 65
|
200
|
+
* Trying ::1...
|
201
|
+
* TCP_NODELAY set
|
202
|
+
* Connected to localhost (::1) port 3000 (#66)
|
203
|
+
> GET /v1/resources/accounts-v1-list HTTP/1.1
|
204
|
+
> Host: localhost:3000
|
205
|
+
> User-Agent: insomnia/5.9.6
|
206
|
+
> Accept: */*
|
207
|
+
> Accept-Encoding: deflate, gzip
|
208
|
+
```
|
209
|
+
|
210
|
+
``` json
|
211
|
+
{
|
212
|
+
"data": {
|
213
|
+
"id": "accounts-v1-list",
|
214
|
+
"type": "resources",
|
215
|
+
"links": {
|
216
|
+
"self": "http://localhost:3000/jsonapi/resources/home/v1/resources/accounts-v1-list"
|
217
|
+
},
|
218
|
+
"attributes": {
|
219
|
+
"namespace": "accounts",
|
220
|
+
"version": "v1",
|
221
|
+
"intent": "list",
|
222
|
+
"verb": "GET",
|
223
|
+
"href": "http://home.example.com/v1/accounts",
|
224
|
+
"allowed": null,
|
225
|
+
"mediatype": "application/vnd.api+json",
|
226
|
+
"description": "The accounts resource",
|
227
|
+
"created-at": "2017-11-10T01:01:28.576-08:00",
|
228
|
+
"updated-at": "2017-11-10T01:01:28.582-08:00"
|
229
|
+
}
|
230
|
+
}
|
231
|
+
}
|
232
|
+
```
|
233
|
+
|
234
|
+
Because it's jsonapi.org you can use all the normal interfaces.
|
235
|
+
|
236
|
+
|
237
|
+
## Installing
|
238
|
+
|
239
|
+
Install with gemrat:
|
240
|
+
|
241
|
+
$ gemrat jsonapi-resources-home
|
242
|
+
|
243
|
+
|
244
|
+
## Contributing
|
245
|
+
|
246
|
+
1. Read the [Code of Conduct](/CONDUCT.md)
|
247
|
+
2. Fork it
|
248
|
+
3. Create your feature branch (`git checkout -b my-new-feature`)
|
249
|
+
4. Commit your changes (`git commit -am 'Add some feature'`)
|
250
|
+
5. Push to the branch (`git push origin my-new-feature`)
|
251
|
+
6. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
|
3
|
+
begin
|
4
|
+
require "bundler/setup"
|
5
|
+
require "bundler/gem_tasks"
|
6
|
+
rescue LoadError
|
7
|
+
puts "You must `gem install bundler` and `bundle install` to run rake tasks"
|
8
|
+
end
|
9
|
+
require "rspec/core/rake_task"
|
10
|
+
|
11
|
+
desc "Run all the tests in spec"
|
12
|
+
RSpec::Core::RakeTask.new(:spec)
|
13
|
+
|
14
|
+
desc "Default: run tests"
|
15
|
+
task default: :spec
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module JSONAPI
|
2
|
+
module Resources
|
3
|
+
module Home
|
4
|
+
module V1
|
5
|
+
class ResourcesController < ::ApplicationController
|
6
|
+
include JSONAPI::ActsAsResourceController
|
7
|
+
|
8
|
+
home_discoverable description: "All discoverable HTTP API endpoints"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module JSONAPI
|
2
|
+
module Resources
|
3
|
+
module Home
|
4
|
+
module V1
|
5
|
+
class Resource
|
6
|
+
include ActiveModel::Model
|
7
|
+
|
8
|
+
MEDIATYPE = "application/vnd.api+json"
|
9
|
+
private_constant :MEDIATYPE
|
10
|
+
CREATED_AT = Time.now
|
11
|
+
private_constant :CREATED_AT
|
12
|
+
|
13
|
+
attr_accessor :namespace
|
14
|
+
attr_accessor :version
|
15
|
+
attr_accessor :intent
|
16
|
+
attr_accessor :verb
|
17
|
+
attr_accessor :href
|
18
|
+
attr_accessor :allowed
|
19
|
+
attr_accessor :mediatype
|
20
|
+
attr_accessor :description
|
21
|
+
attr_reader :route
|
22
|
+
private :route
|
23
|
+
|
24
|
+
def self.all
|
25
|
+
routes.map(&method(:new)).select(&:valid?)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.where(attributes)
|
29
|
+
all.where(attributes)
|
30
|
+
end
|
31
|
+
|
32
|
+
private_class_method def self.routes
|
33
|
+
Rails.
|
34
|
+
application.
|
35
|
+
routes.routes.
|
36
|
+
to_a
|
37
|
+
end
|
38
|
+
|
39
|
+
def initialize(route)
|
40
|
+
@route = route
|
41
|
+
end
|
42
|
+
|
43
|
+
def id
|
44
|
+
"#{namespace}-#{version}-#{intent}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def intent
|
48
|
+
if defaults.fetch(:action) == "index"
|
49
|
+
"list"
|
50
|
+
else
|
51
|
+
defaults.fetch(:action)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def version
|
56
|
+
defaults.fetch(:controller).split("/").first
|
57
|
+
end
|
58
|
+
|
59
|
+
def namespace
|
60
|
+
defaults.fetch(:controller).split("/").last
|
61
|
+
end
|
62
|
+
|
63
|
+
def description
|
64
|
+
controller.instance_variable_get(:@jsonapi_resources_home_description)
|
65
|
+
end
|
66
|
+
|
67
|
+
def verb
|
68
|
+
route.verb
|
69
|
+
end
|
70
|
+
|
71
|
+
def href
|
72
|
+
File.join(controller.instance_variable_get(:@json_api_home_location) || ENV.fetch("HOME_LOCATION"), path)
|
73
|
+
end
|
74
|
+
|
75
|
+
def mediatype
|
76
|
+
MEDIATYPE
|
77
|
+
end
|
78
|
+
|
79
|
+
def created_at
|
80
|
+
CREATED_AT
|
81
|
+
end
|
82
|
+
|
83
|
+
def updated_at
|
84
|
+
Time.now
|
85
|
+
end
|
86
|
+
|
87
|
+
def valid?
|
88
|
+
!route.internal && defaults.any? && controller.instance_variable_get(:@jsonapi_resources_home)
|
89
|
+
end
|
90
|
+
|
91
|
+
private def payload
|
92
|
+
route.parts.without(:format).map {|part| {part => "{#{part}}"}}.reduce(:merge) || {}
|
93
|
+
end
|
94
|
+
|
95
|
+
private def path
|
96
|
+
URI.decode(route.format(payload))
|
97
|
+
end
|
98
|
+
|
99
|
+
private def controller
|
100
|
+
"#{defaults.fetch(:controller).classify.pluralize}Controller".constantize
|
101
|
+
end
|
102
|
+
|
103
|
+
private def defaults
|
104
|
+
route.defaults
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module JSONAPI
|
2
|
+
module Resources
|
3
|
+
module Home
|
4
|
+
module V1
|
5
|
+
class ResourceResource < ::ApplicationResource
|
6
|
+
key_type :string
|
7
|
+
|
8
|
+
immutable
|
9
|
+
|
10
|
+
model_name "JSONAPI::Resources::Home::V1::Resource"
|
11
|
+
|
12
|
+
attribute :namespace
|
13
|
+
attribute :version
|
14
|
+
attribute :intent
|
15
|
+
attribute :verb
|
16
|
+
attribute :href
|
17
|
+
attribute :allowed
|
18
|
+
attribute :mediatype
|
19
|
+
attribute :description
|
20
|
+
attribute :created_at
|
21
|
+
attribute :updated_at
|
22
|
+
|
23
|
+
def self.default_sort
|
24
|
+
[]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|