jsonapi-resources-home 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +6 -0
  3. data/README.md +251 -0
  4. data/Rakefile +15 -0
  5. data/app/controllers/jsonapi/resources/home/v1/resources_controller.rb +13 -0
  6. data/app/models/jsonapi/resources/home/v1/resource.rb +110 -0
  7. data/app/resources/jsonapi/resources/home/v1/resource_resource.rb +30 -0
  8. data/config/routes.rb +7 -0
  9. data/lib/jsonapi/resources/home.rb +21 -0
  10. data/lib/jsonapi/resources/home/engine.rb +9 -0
  11. data/lib/jsonapi/resources/home/inflector.rb +9 -0
  12. data/lib/jsonapi/resources/home/version.rb +7 -0
  13. data/spec/dummy/Rakefile +6 -0
  14. data/spec/dummy/app/controllers/application_controller.rb +2 -0
  15. data/spec/dummy/app/controllers/v1/accounts_controller.rb +5 -0
  16. data/spec/dummy/app/controllers/v1/application_controller.rb +5 -0
  17. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  18. data/spec/dummy/app/jobs/application_job.rb +2 -0
  19. data/spec/dummy/app/mailers/application_mailer.rb +4 -0
  20. data/spec/dummy/app/models/application_record.rb +3 -0
  21. data/spec/dummy/app/resources/application_resource.rb +4 -0
  22. data/spec/dummy/app/resources/v1/account_resource.rb +5 -0
  23. data/spec/dummy/app/resources/v1/application_resource.rb +6 -0
  24. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  25. data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
  26. data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
  27. data/spec/dummy/bin/bundle +3 -0
  28. data/spec/dummy/bin/rails +4 -0
  29. data/spec/dummy/bin/rake +4 -0
  30. data/spec/dummy/bin/setup +38 -0
  31. data/spec/dummy/bin/update +29 -0
  32. data/spec/dummy/bin/yarn +11 -0
  33. data/spec/dummy/config.ru +5 -0
  34. data/spec/dummy/config/application.rb +18 -0
  35. data/spec/dummy/config/boot.rb +5 -0
  36. data/spec/dummy/config/cable.yml +10 -0
  37. data/spec/dummy/config/database.yml +25 -0
  38. data/spec/dummy/config/environment.rb +5 -0
  39. data/spec/dummy/config/environments/development.rb +54 -0
  40. data/spec/dummy/config/environments/production.rb +91 -0
  41. data/spec/dummy/config/environments/test.rb +42 -0
  42. data/spec/dummy/config/initializers/application_controller_renderer.rb +8 -0
  43. data/spec/dummy/config/initializers/assets.rb +14 -0
  44. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  45. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  46. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  47. data/spec/dummy/config/initializers/inflections.rb +16 -0
  48. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  49. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  50. data/spec/dummy/config/locales/en.yml +33 -0
  51. data/spec/dummy/config/puma.rb +56 -0
  52. data/spec/dummy/config/routes.rb +9 -0
  53. data/spec/dummy/config/secrets.yml +32 -0
  54. data/spec/dummy/config/spring.rb +6 -0
  55. data/spec/dummy/log/development.log +5436 -0
  56. data/spec/dummy/public/404.html +67 -0
  57. data/spec/dummy/public/422.html +67 -0
  58. data/spec/dummy/public/500.html +66 -0
  59. data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
  60. data/spec/dummy/public/apple-touch-icon.png +0 -0
  61. data/spec/dummy/public/favicon.ico +0 -0
  62. data/spec/jsonapi/resources/home_test.rb +0 -0
  63. data/spec/test_helper.rb +17 -0
  64. metadata +283 -0
@@ -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.
@@ -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
@@ -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
@@ -0,0 +1,7 @@
1
+ JSONAPI::Resources::Home::Engine.routes.draw do
2
+ # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
3
+
4
+ namespace :v1 do
5
+ resources :resources, only: [:index, :show]
6
+ end
7
+ end