jsonapi-home 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 601793a236d6fba997f95f5da8d3ee6ae7db8621078b5a0ad23004718d42d52e
4
+ data.tar.gz: eef20492884e0a429b1b48a678ce310fd7d9f404ffc4ec5a8984929918b62eb7
5
+ SHA512:
6
+ metadata.gz: 89cd7ba9430afb7b818a6d0a0310349ede9d0803b88f29597b065cad632a667ac5d1b0afb61c3de8377e9381ac744dda17f7b5f32b933db1cae72ef2eafa68a1
7
+ data.tar.gz: 469784ae1fd60ff93c62144aa93c04b77b08eddc6a09600022e244dbcdbf357061a16e389c9d252de6f653b1b3a00efebd887c56869c27a6bf91772383d2d581
data/README.md ADDED
@@ -0,0 +1,754 @@
1
+ # jsonapi-home
2
+
3
+ - [![Build](http://img.shields.io/travis-ci/krainboltgreene/jsonapi-home.svg?style=flat-square)](https://travis-ci.org/krainboltgreene/jsonapi-home)
4
+ - [![Downloads](http://img.shields.io/gem/dtv/jsonapi-home.svg?style=flat-square)](https://rubygems.org/gems/jsonapi-home)
5
+ - [![Version](http://img.shields.io/gem/v/jsonapi-home.svg?style=flat-square)](https://rubygems.org/gems/jsonapi-home)
6
+
7
+ An implementation of an experimental JSON:API-Home specification, which is a combination of the [JSONHome](https://tools.ietf.org/html/draft-nottingham-json-home-06) and [json:api](https://www.jsonapi.org).
8
+
9
+
10
+ ## Using
11
+
12
+ To start lets mount the engine:
13
+
14
+ ``` ruby
15
+ Rails.application.routes.draw do
16
+ # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
17
+
18
+ mount JSONAPI::Home::Engine, at: "/"
19
+
20
+ namespace :v1 do
21
+ resources :accounts
22
+ end
23
+
24
+ root to: "pages#landing"
25
+ end
26
+ ```
27
+
28
+ This will setup the basic set of home routes and with the following request:
29
+
30
+ ```
31
+ * Preparing request to http://localhost:3000/v1/jsonapi-home-resources
32
+ * Using libcurl/7.54.0 SecureTransport zlib/1.2.8
33
+ * Enable automatic URL encoding
34
+ * Enable SSL validation
35
+ * Enable cookie sending with jar of 0 cookies
36
+ * Connection 68 seems to be dead!
37
+ * Closing connection 68
38
+ * Trying ::1...
39
+ * TCP_NODELAY set
40
+ * Connected to localhost (::1) port 3000 (#69)
41
+ > GET /v1/jsonapi-home-resources HTTP/1.1
42
+ > Host: localhost:3000
43
+ > User-Agent: insomnia/5.14.9
44
+ > Accept: application/vnd.api+json
45
+ < HTTP/1.1 200 OK
46
+ < Content-Type: application/json; charset=utf-8
47
+ < Etag: W/"dfafe86e832bea875149e878c0616b96"
48
+ < Cache-Control: max-age=0, private, must-revalidate
49
+ < X-Request-Id: 942ba1cd-2bbc-4902-a89a-8706da7d5533
50
+ < X-Runtime: 0.037835
51
+ < Server: WEBrick/1.4.2 (Ruby/2.5.0/2017-12-25)
52
+ < Date: Sun, 25 Mar 2018 23:07:05 GMT
53
+ < Content-Length: 1194
54
+ < Connection: Keep-Alive
55
+
56
+ * Received 1194 B chunk
57
+ * Connection #69 to host localhost left intact
58
+ ```
59
+
60
+ You'll get this payload:
61
+
62
+ ``` json
63
+ {
64
+ "data": [
65
+ {
66
+ "type": "jsonapi-home-resources",
67
+ "id": "jsonapi-home-resources-v1-index",
68
+ "attributes": {
69
+ "namespace": "jsonapi-home-resources",
70
+ "version": "v1",
71
+ "intent": "index",
72
+ "description": "All discoverable HTTP JSON:API endpoints that this server knows about",
73
+ "verb": "GET",
74
+ "href": "/v1/jsonapi-home-resources",
75
+ "mediatype": "application/vnd.api+json",
76
+ "created-at": "2018-03-25T16:07:03.039-07:00",
77
+ "updated-at": "2018-03-25T16:07:05.000-07:00"
78
+ },
79
+ "links": {
80
+ "self": "/jsonapi-home-resources/jsonapi-home-resources-v1-index"
81
+ },
82
+ "jsonapi": {
83
+ "version": "1.0"
84
+ }
85
+ },
86
+ {
87
+ "type": "jsonapi-home-resources",
88
+ "id": "jsonapi-home-resources-v1-show",
89
+ "attributes": {
90
+ "namespace": "jsonapi-home-resources",
91
+ "version": "v1",
92
+ "intent": "show",
93
+ "description": "All discoverable HTTP JSON:API endpoints that this server knows about",
94
+ "verb": "GET",
95
+ "href": "/v1/jsonapi-home-resources/{id}",
96
+ "mediatype": "application/vnd.api+json",
97
+ "created-at": "2018-03-25T16:07:03.039-07:00",
98
+ "updated-at": "2018-03-25T16:07:05.003-07:00"
99
+ },
100
+ "links": {
101
+ "self": "/jsonapi-home-resources/jsonapi-home-resources-v1-show"
102
+ },
103
+ "jsonapi": {
104
+ "version": "1.0"
105
+ }
106
+ }
107
+ ],
108
+ "jsonapi": {
109
+ "version": "1.0"
110
+ },
111
+ "meta": {
112
+ "endpoint": {
113
+ "version": "1"
114
+ }
115
+ }
116
+ }
117
+ ```
118
+
119
+ You'll notice that we only show our own home routes, we're self-referential! Now we've got to setup your other endpoints:
120
+
121
+ ``` ruby
122
+ module V1
123
+ class AccountsController < V1::ApplicationController
124
+ discoverable(
125
+ version: "v1",
126
+ namespace: "accounts"
127
+ )
128
+
129
+ def index
130
+ # ...
131
+ end
132
+
133
+ def show
134
+ # ...
135
+ end
136
+
137
+ def create
138
+ # ...
139
+ end
140
+
141
+ def update
142
+ # ...
143
+ end
144
+
145
+ def destroy
146
+ # ...
147
+ end
148
+ end
149
+ end
150
+ ```
151
+
152
+ Which results in this payload:
153
+
154
+ ```
155
+ * Preparing request to http://localhost:3000/v1/jsonapi-home-resources
156
+ * Using libcurl/7.54.0 SecureTransport zlib/1.2.8
157
+ * Enable automatic URL encoding
158
+ * Enable SSL validation
159
+ * Enable cookie sending with jar of 0 cookies
160
+ * Connection 69 seems to be dead!
161
+ * Closing connection 69
162
+ * Trying ::1...
163
+ * TCP_NODELAY set
164
+ * Connected to localhost (::1) port 3000 (#70)
165
+ > GET /v1/jsonapi-home-resources HTTP/1.1
166
+ > Host: localhost:3000
167
+ > User-Agent: insomnia/5.14.9
168
+ > Accept: application/vnd.api+json
169
+ < HTTP/1.1 200 OK
170
+ < Content-Type: application/json; charset=utf-8
171
+ < Etag: W/"4a0ff42059f174ee886ec63b3edeac30"
172
+ < Cache-Control: max-age=0, private, must-revalidate
173
+ < X-Request-Id: 3afadc55-ed06-4811-8500-939dee3271bd
174
+ < X-Runtime: 0.125346
175
+ < Server: WEBrick/1.4.2 (Ruby/2.5.0/2017-12-25)
176
+ < Date: Mon, 26 Mar 2018 01:28:41 GMT
177
+ < Content-Length: 5591
178
+ < Connection: Keep-Alive
179
+
180
+ * Received 5.5 KB chunk
181
+ * Connection #70 to host localhost left intact
182
+ ```
183
+
184
+ ``` json
185
+ {
186
+ "data": [
187
+ {
188
+ "type": "jsonapi-home-resources",
189
+ "id": "accounts-v1-index",
190
+ "attributes": {
191
+ "namespace": "accounts",
192
+ "version": "v1",
193
+ "intent": "index",
194
+ "description": "A JSON:API resource as defined at https://www.jsonapi.org",
195
+ "deprecated": null,
196
+ "verb": "GET",
197
+ "href": "/v1/accounts",
198
+ "mediatype": "application/vnd.api+json",
199
+ "created-at": "2018-03-26T00:17:28.693-07:00",
200
+ "updated-at": "2018-03-26T00:17:31.023-07:00"
201
+ },
202
+ "links": {
203
+ "self": "/jsonapi-home-resources/accounts-v1-index"
204
+ },
205
+ "jsonapi": {
206
+ "version": "v1"
207
+ }
208
+ },
209
+ {
210
+ "type": "jsonapi-home-resources",
211
+ "id": "accounts-v1-create",
212
+ "attributes": {
213
+ "namespace": "accounts",
214
+ "version": "v1",
215
+ "intent": "create",
216
+ "description": "A JSON:API resource as defined at https://www.jsonapi.org",
217
+ "deprecated": null,
218
+ "verb": "POST",
219
+ "href": "/v1/accounts",
220
+ "mediatype": "application/vnd.api+json",
221
+ "created-at": "2018-03-26T00:17:28.693-07:00",
222
+ "updated-at": "2018-03-26T00:17:31.038-07:00"
223
+ },
224
+ "links": {
225
+ "self": "/jsonapi-home-resources/accounts-v1-create"
226
+ },
227
+ "jsonapi": {
228
+ "version": "v1"
229
+ }
230
+ },
231
+ {
232
+ "type": "jsonapi-home-resources",
233
+ "id": "accounts-v1-new",
234
+ "attributes": {
235
+ "namespace": "accounts",
236
+ "version": "v1",
237
+ "intent": "new",
238
+ "description": "A JSON:API resource as defined at https://www.jsonapi.org",
239
+ "deprecated": null,
240
+ "verb": "GET",
241
+ "href": "/v1/accounts/new",
242
+ "mediatype": "application/vnd.api+json",
243
+ "created-at": "2018-03-26T00:17:28.693-07:00",
244
+ "updated-at": "2018-03-26T00:17:31.056-07:00"
245
+ },
246
+ "links": {
247
+ "self": "/jsonapi-home-resources/accounts-v1-new"
248
+ },
249
+ "jsonapi": {
250
+ "version": "v1"
251
+ }
252
+ },
253
+ {
254
+ "type": "jsonapi-home-resources",
255
+ "id": "accounts-v1-edit",
256
+ "attributes": {
257
+ "namespace": "accounts",
258
+ "version": "v1",
259
+ "intent": "edit",
260
+ "description": "A JSON:API resource as defined at https://www.jsonapi.org",
261
+ "deprecated": null,
262
+ "verb": "GET",
263
+ "href": "/v1/accounts/{id}/edit",
264
+ "mediatype": "application/vnd.api+json",
265
+ "created-at": "2018-03-26T00:17:28.693-07:00",
266
+ "updated-at": "2018-03-26T00:17:31.067-07:00"
267
+ },
268
+ "links": {
269
+ "self": "/jsonapi-home-resources/accounts-v1-edit"
270
+ },
271
+ "jsonapi": {
272
+ "version": "v1"
273
+ }
274
+ },
275
+ {
276
+ "type": "jsonapi-home-resources",
277
+ "id": "accounts-v1-show",
278
+ "attributes": {
279
+ "namespace": "accounts",
280
+ "version": "v1",
281
+ "intent": "show",
282
+ "description": "A JSON:API resource as defined at https://www.jsonapi.org",
283
+ "deprecated": null,
284
+ "verb": "GET",
285
+ "href": "/v1/accounts/{id}",
286
+ "mediatype": "application/vnd.api+json",
287
+ "created-at": "2018-03-26T00:17:28.693-07:00",
288
+ "updated-at": "2018-03-26T00:17:31.073-07:00"
289
+ },
290
+ "links": {
291
+ "self": "/jsonapi-home-resources/accounts-v1-show"
292
+ },
293
+ "jsonapi": {
294
+ "version": "v1"
295
+ }
296
+ },
297
+ {
298
+ "type": "jsonapi-home-resources",
299
+ "id": "accounts-v1-update",
300
+ "attributes": {
301
+ "namespace": "accounts",
302
+ "version": "v1",
303
+ "intent": "update",
304
+ "description": "A JSON:API resource as defined at https://www.jsonapi.org",
305
+ "deprecated": null,
306
+ "verb": "PATCH",
307
+ "href": "/v1/accounts/{id}",
308
+ "mediatype": "application/vnd.api+json",
309
+ "created-at": "2018-03-26T00:17:28.693-07:00",
310
+ "updated-at": "2018-03-26T00:17:31.076-07:00"
311
+ },
312
+ "links": {
313
+ "self": "/jsonapi-home-resources/accounts-v1-update"
314
+ },
315
+ "jsonapi": {
316
+ "version": "v1"
317
+ }
318
+ },
319
+ {
320
+ "type": "jsonapi-home-resources",
321
+ "id": "accounts-v1-update",
322
+ "attributes": {
323
+ "namespace": "accounts",
324
+ "version": "v1",
325
+ "intent": "update",
326
+ "description": "A JSON:API resource as defined at https://www.jsonapi.org",
327
+ "deprecated": null,
328
+ "verb": "PUT",
329
+ "href": "/v1/accounts/{id}",
330
+ "mediatype": "application/vnd.api+json",
331
+ "created-at": "2018-03-26T00:17:28.693-07:00",
332
+ "updated-at": "2018-03-26T00:17:31.080-07:00"
333
+ },
334
+ "links": {
335
+ "self": "/jsonapi-home-resources/accounts-v1-update"
336
+ },
337
+ "jsonapi": {
338
+ "version": "v1"
339
+ }
340
+ },
341
+ {
342
+ "type": "jsonapi-home-resources",
343
+ "id": "accounts-v1-destroy",
344
+ "attributes": {
345
+ "namespace": "accounts",
346
+ "version": "v1",
347
+ "intent": "destroy",
348
+ "description": "A JSON:API resource as defined at https://www.jsonapi.org",
349
+ "deprecated": null,
350
+ "verb": "DELETE",
351
+ "href": "/v1/accounts/{id}",
352
+ "mediatype": "application/vnd.api+json",
353
+ "created-at": "2018-03-26T00:17:28.693-07:00",
354
+ "updated-at": "2018-03-26T00:17:31.083-07:00"
355
+ },
356
+ "links": {
357
+ "self": "/jsonapi-home-resources/accounts-v1-destroy"
358
+ },
359
+ "jsonapi": {
360
+ "version": "v1"
361
+ }
362
+ },
363
+ {
364
+ "type": "jsonapi-home-resources",
365
+ "id": "posts-v1-index",
366
+ "attributes": {
367
+ "namespace": "posts",
368
+ "version": "v1",
369
+ "intent": "index",
370
+ "description": "Oh hi, mark",
371
+ "deprecated": false,
372
+ "verb": "GET",
373
+ "href": "https://www.example.com/v1/posts",
374
+ "mediatype": "application/vnd.api+json",
375
+ "created-at": "2018-03-26T00:17:28.693-07:00",
376
+ "updated-at": "2018-03-26T00:17:31.088-07:00"
377
+ },
378
+ "links": {
379
+ "self": "/jsonapi-home-resources/posts-v1-index"
380
+ },
381
+ "jsonapi": {
382
+ "version": "v1"
383
+ },
384
+ "meta": {
385
+ "documentation": {
386
+ "href": "https://www.schema.org"
387
+ }
388
+ }
389
+ },
390
+ {
391
+ "type": "jsonapi-home-resources",
392
+ "id": "posts-v1-update",
393
+ "attributes": {
394
+ "namespace": "posts",
395
+ "version": "v1",
396
+ "intent": "update",
397
+ "description": "Oh hi, mark",
398
+ "deprecated": false,
399
+ "verb": "PATCH",
400
+ "href": "https://www.example.com/v1/posts/{id}",
401
+ "mediatype": "application/vnd.api+json",
402
+ "created-at": "2018-03-26T00:17:28.693-07:00",
403
+ "updated-at": "2018-03-26T00:17:31.093-07:00"
404
+ },
405
+ "links": {
406
+ "self": "/jsonapi-home-resources/posts-v1-update"
407
+ },
408
+ "jsonapi": {
409
+ "version": "v1"
410
+ },
411
+ "meta": {
412
+ "documentation": {
413
+ "href": "https://www.schema.org"
414
+ }
415
+ }
416
+ },
417
+ {
418
+ "type": "jsonapi-home-resources",
419
+ "id": "posts-v1-update",
420
+ "attributes": {
421
+ "namespace": "posts",
422
+ "version": "v1",
423
+ "intent": "update",
424
+ "description": "Oh hi, mark",
425
+ "deprecated": false,
426
+ "verb": "PUT",
427
+ "href": "https://www.example.com/v1/posts/{id}",
428
+ "mediatype": "application/vnd.api+json",
429
+ "created-at": "2018-03-26T00:17:28.693-07:00",
430
+ "updated-at": "2018-03-26T00:17:31.097-07:00"
431
+ },
432
+ "links": {
433
+ "self": "/jsonapi-home-resources/posts-v1-update"
434
+ },
435
+ "jsonapi": {
436
+ "version": "v1"
437
+ },
438
+ "meta": {
439
+ "documentation": {
440
+ "href": "https://www.schema.org"
441
+ }
442
+ }
443
+ },
444
+ {
445
+ "type": "jsonapi-home-resources",
446
+ "id": "posts-v1-destroy",
447
+ "attributes": {
448
+ "namespace": "posts",
449
+ "version": "v1",
450
+ "intent": "destroy",
451
+ "description": "Oh hi, mark",
452
+ "deprecated": false,
453
+ "verb": "DELETE",
454
+ "href": "https://www.example.com/v1/posts/{id}",
455
+ "mediatype": "application/vnd.api+json",
456
+ "created-at": "2018-03-26T00:17:28.693-07:00",
457
+ "updated-at": "2018-03-26T00:17:31.101-07:00"
458
+ },
459
+ "links": {
460
+ "self": "/jsonapi-home-resources/posts-v1-destroy"
461
+ },
462
+ "jsonapi": {
463
+ "version": "v1"
464
+ },
465
+ "meta": {
466
+ "documentation": {
467
+ "href": "https://www.schema.org"
468
+ }
469
+ }
470
+ },
471
+ {
472
+ "type": "jsonapi-home-resources",
473
+ "id": "accounts-v1-index",
474
+ "attributes": {
475
+ "namespace": "accounts",
476
+ "version": "v1",
477
+ "intent": "index",
478
+ "description": "A JSON:API resource as defined at https://www.jsonapi.org",
479
+ "deprecated": null,
480
+ "verb": "GET",
481
+ "href": "/",
482
+ "mediatype": "application/vnd.api+json",
483
+ "created-at": "2018-03-26T00:17:28.693-07:00",
484
+ "updated-at": "2018-03-26T00:17:31.108-07:00"
485
+ },
486
+ "links": {
487
+ "self": "/jsonapi-home-resources/accounts-v1-index"
488
+ },
489
+ "jsonapi": {
490
+ "version": "v1"
491
+ }
492
+ },
493
+ {
494
+ "type": "jsonapi-home-resources",
495
+ "id": "jsonapi-home-resources-v1-index",
496
+ "attributes": {
497
+ "namespace": "jsonapi-home-resources",
498
+ "version": "v1",
499
+ "intent": "index",
500
+ "description": "All discoverable HTTP JSON:API endpoints that this server knows about",
501
+ "deprecated": null,
502
+ "verb": "GET",
503
+ "href": "/v1/jsonapi-home-resources",
504
+ "mediatype": "application/vnd.api+json",
505
+ "created-at": "2018-03-26T00:17:28.693-07:00",
506
+ "updated-at": "2018-03-26T00:17:31.111-07:00"
507
+ },
508
+ "links": {
509
+ "self": "/jsonapi-home-resources/jsonapi-home-resources-v1-index"
510
+ },
511
+ "jsonapi": {
512
+ "version": "v1"
513
+ },
514
+ "meta": {
515
+ "documentation": {
516
+ "href": "https://github.com/krainboltgreene/jsonapi-home.rb"
517
+ }
518
+ }
519
+ },
520
+ {
521
+ "type": "jsonapi-home-resources",
522
+ "id": "jsonapi-home-resources-v1-show",
523
+ "attributes": {
524
+ "namespace": "jsonapi-home-resources",
525
+ "version": "v1",
526
+ "intent": "show",
527
+ "description": "All discoverable HTTP JSON:API endpoints that this server knows about",
528
+ "deprecated": null,
529
+ "verb": "GET",
530
+ "href": "/v1/jsonapi-home-resources/{id}",
531
+ "mediatype": "application/vnd.api+json",
532
+ "created-at": "2018-03-26T00:17:28.693-07:00",
533
+ "updated-at": "2018-03-26T00:17:31.115-07:00"
534
+ },
535
+ "links": {
536
+ "self": "/jsonapi-home-resources/jsonapi-home-resources-v1-show"
537
+ },
538
+ "jsonapi": {
539
+ "version": "v1"
540
+ },
541
+ "meta": {
542
+ "documentation": {
543
+ "href": "https://github.com/krainboltgreene/jsonapi-home.rb"
544
+ }
545
+ }
546
+ }
547
+ ],
548
+ "jsonapi": {
549
+ "version": "1.0"
550
+ },
551
+ "meta": {
552
+ "endpoint": {
553
+ "version": "1"
554
+ }
555
+ }
556
+ }
557
+ ```
558
+
559
+ You can also inquire about individual endpoints:
560
+
561
+ ```
562
+ * Preparing request to http://localhost:3000/v1/jsonapi-home-resources/accounts-v1-destroy
563
+ * Using libcurl/7.54.0 SecureTransport zlib/1.2.8
564
+ * Enable automatic URL encoding
565
+ * Enable SSL validation
566
+ * Enable cookie sending with jar of 0 cookies
567
+ * Connection 70 seems to be dead!
568
+ * Closing connection 70
569
+ * Trying ::1...
570
+ * TCP_NODELAY set
571
+ * Connected to localhost (::1) port 3000 (#71)
572
+ > GET /v1/jsonapi-home-resources/accounts-v1-destroy HTTP/1.1
573
+ > Host: localhost:3000
574
+ > User-Agent: insomnia/5.14.9
575
+ > Accept: application/vnd.api+json
576
+ < HTTP/1.1 200 OK
577
+ < Content-Type: application/json; charset=utf-8
578
+ < Etag: W/"ea14613f3daa0a8e2edfff922d88ef95"
579
+ < Cache-Control: max-age=0, private, must-revalidate
580
+ < X-Request-Id: d16732df-3f7f-434b-a4da-d08b7ab27ee6
581
+ < X-Runtime: 0.022813
582
+ < Server: WEBrick/1.4.2 (Ruby/2.5.0/2017-12-25)
583
+ < Date: Mon, 26 Mar 2018 01:31:12 GMT
584
+ < Content-Length: 571
585
+ < Connection: Keep-Alive
586
+
587
+ * Received 571 B chunk
588
+ * Connection #71 to host localhost left intact
589
+ ```
590
+
591
+ ``` json
592
+ {
593
+ "data": {
594
+ "type": "jsonapi-home-resources",
595
+ "id": "accounts-v1-destroy",
596
+ "attributes": {
597
+ "namespace": "accounts",
598
+ "version": "v1",
599
+ "intent": "destroy",
600
+ "description": "A JSON:API resource as defined at https://www.jsonapi.org",
601
+ "verb": "DELETE",
602
+ "href": "/v1/accounts/{id}",
603
+ "mediatype": "application/vnd.api+json",
604
+ "created-at": "2018-03-25T18:28:37.776-07:00",
605
+ "updated-at": "2018-03-25T18:31:12.294-07:00"
606
+ },
607
+ "links": {
608
+ "self": "/jsonapi-home-resources/accounts-v1-destroy"
609
+ },
610
+ "jsonapi": {
611
+ "version": "1.0"
612
+ }
613
+ },
614
+ "jsonapi": {
615
+ "version": "1.0"
616
+ },
617
+ "meta": {
618
+ "endpoint": {
619
+ "version": "1"
620
+ }
621
+ }
622
+ }
623
+ ```
624
+
625
+ Because it's jsonapi.org you can use all the normal interfaces.
626
+
627
+ ### Custom URL Location
628
+
629
+ **By default you will see resources have a root url of whatever returns from `root_path`.**
630
+
631
+ If you need a different value you can do one of two things:
632
+
633
+ - You can set up a `HOME_LOCATION` ENV variable which is a protocol+hostname[+suffix] combination where your endpoints exist:
634
+ ```
635
+ HOME_LOCATION=https://origin.example.com
636
+ ```
637
+ - If you need an individual endpoint to have this value, try:
638
+ ``` ruby
639
+ module V1
640
+ class AccountsController < V1::ApplicationController
641
+ discoverable(
642
+ version: "v1",
643
+ namespace: "accounts",
644
+ location: "http://special.example.com"
645
+ )
646
+ end
647
+ end
648
+ ```
649
+
650
+ ### Custom Description
651
+
652
+ If you want you can overwrite the description that comes with every endpoint to provide context:
653
+
654
+ ``` ruby
655
+ module V1
656
+ class AccountsController < V1::ApplicationController
657
+ discoverable(
658
+ version: "v1",
659
+ namespace: "accounts",
660
+ description: "The accounts resource is being removed on the 5th of march"
661
+ )
662
+ end
663
+ end
664
+ ```
665
+
666
+ ### Deprecated
667
+
668
+ To provide a hint to clients you can also set the entire endpoint as deprecated:
669
+
670
+ ``` ruby
671
+ module V1
672
+ class AccountsController < V1::ApplicationController
673
+ discoverable(
674
+ version: "v1",
675
+ namespace: "accounts",
676
+ deprecated: true,
677
+ )
678
+ end
679
+ end
680
+ ```
681
+
682
+ Or specific endpoints:
683
+
684
+ ``` ruby
685
+ module V1
686
+ class AccountsController < V1::ApplicationController
687
+ discoverable(
688
+ version: "v1",
689
+ namespace: "accounts",
690
+ deprecated: {
691
+ index: true
692
+ },
693
+ )
694
+ end
695
+ end
696
+ ```
697
+
698
+ ### Documentation HREF
699
+
700
+ Every endpoint can link to the human documentation for that endpoint:
701
+
702
+ ``` ruby
703
+ module V1
704
+ class AccountsController < V1::ApplicationController
705
+ discoverable(
706
+ version: "v1",
707
+ namespace: "accounts",
708
+ documentation: "https://documentation.example.com"
709
+ )
710
+ end
711
+ end
712
+ ```
713
+
714
+ ### JSONAPI Version
715
+
716
+ Finally you can specify the specific version of JSON:API this endpoint uses:
717
+
718
+ ``` ruby
719
+ module V1
720
+ class AccountsController < V1::ApplicationController
721
+ discoverable(
722
+ version: "v1",
723
+ namespace: "accounts",
724
+ jsonapi_version: "1.1"
725
+ )
726
+ end
727
+ end
728
+ ```
729
+
730
+ Of course, these are all just descriptive. jsonapi-home does not enforce these configurations.
731
+
732
+ ## Installing
733
+
734
+ Add this line to your application's Gemfile:
735
+
736
+ gem "jsonapi-home", "1.0.0"
737
+
738
+ And then execute:
739
+
740
+ $ bundle
741
+
742
+ Or install it yourself with:
743
+
744
+ $ gem install jsonapi-home
745
+
746
+
747
+ ## Contributing
748
+
749
+ 1. Read the [Code of Conduct](/CONDUCT.md)
750
+ 2. Fork it
751
+ 3. Create your feature branch (`git checkout -b my-new-feature`)
752
+ 4. Commit your changes (`git commit -am 'Add some feature'`)
753
+ 5. Push to the branch (`git push origin my-new-feature`)
754
+ 6. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ desc "Run all the tests in spec"
7
+ RSpec::Core::RakeTask.new(:spec) do |let|
8
+ let.pattern = "lib/**{,/*/**}/*_spec.rb"
9
+ end
10
+
11
+ desc "Default: run tests"
12
+ task default: :spec
@@ -0,0 +1,81 @@
1
+ module JSONAPI
2
+ module Home
3
+ module V1
4
+ class ResourcesController < ::ApplicationController
5
+ include JSONAPI::Home
6
+
7
+ discoverable(
8
+ version: "v1",
9
+ namespace: "jsonapi-home-resources",
10
+ description: "All discoverable HTTP JSON:API endpoints that this server knows about",
11
+ documentation: "https://github.com/krainboltgreene/jsonapi-home.rb"
12
+ )
13
+
14
+ def index
15
+ realization = JSONAPI::Realizer.index(
16
+ params,
17
+ headers: request.headers,
18
+ type: :jsonapi_home_resources
19
+ )
20
+
21
+ render json: serialize(realization)
22
+ end
23
+
24
+ def show
25
+ realization = JSONAPI::Realizer.show(
26
+ params,
27
+ headers: request.headers,
28
+ type: :jsonapi_home_resources
29
+ )
30
+
31
+ render json: serialize(realization)
32
+ end
33
+
34
+ private def serialize(realization)
35
+ JSONAPI::Serializer.serialize(
36
+ if realization.respond_to?(:models) then realization.models else realization.model end,
37
+ is_collection: realization.respond_to?(:models),
38
+ meta: serialized_metadata,
39
+ links: serialized_links,
40
+ jsonapi: serialized_jsonapi,
41
+ fields: if realization.fields.any? then realization.fields end,
42
+ include: if realization.includes.any? then realization.includes end
43
+ )
44
+ end
45
+
46
+ private def serialized_metadata
47
+ {
48
+ endpoint: {
49
+ version: "1"
50
+ }
51
+ }
52
+ end
53
+
54
+ private def serialized_links
55
+ [
56
+ if instance_variable_get(:@jsonapi_home_location)
57
+ {
58
+ home: {
59
+ href: "#{instance_variable_get(:@jsonapi_home_location)}/jsonapi-home-resources"
60
+ }
61
+ }
62
+ end,
63
+ if ENV.key?("HOME_DOCUMENTATION_HREF")
64
+ {
65
+ documentation: {
66
+ href: "#{ENV.fetch("HOME_DOCUMENTATION_HREF")}"
67
+ }
68
+ }
69
+ end,
70
+ ].compact.reduce(&:merge)
71
+ end
72
+
73
+ private def serialized_jsonapi
74
+ {
75
+ version: "1.0"
76
+ }
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,134 @@
1
+ module JSONAPI
2
+ module Home
3
+ module V1
4
+ class Resource
5
+ include ActiveModel::Model
6
+
7
+ CREATED_AT = Time.now
8
+ private_constant :CREATED_AT
9
+
10
+ attr_reader :route
11
+ private :route
12
+
13
+ def self.all
14
+ routes.map(&method(:new)).select(&:valid?)
15
+ end
16
+
17
+ def self.where(attributes)
18
+ all.where(attributes)
19
+ end
20
+
21
+ def self.fetch(id)
22
+ all.index_by(&:id).fetch(id)
23
+ end
24
+
25
+ private_class_method def self.routes
26
+ [
27
+ *Rails.application.routes.routes.to_a,
28
+ *Rails::Engine.subclasses.map(&:instance).map(&:routes).map(&:routes).map(&:to_a).flatten
29
+ ]
30
+ end
31
+
32
+ def initialize(route)
33
+ @route = route
34
+ end
35
+
36
+ def id
37
+ "#{namespace}-#{version}-#{intent}"
38
+ end
39
+
40
+ def intent
41
+ defaults.fetch(:action)
42
+ end
43
+
44
+ def namespace
45
+ configuration.fetch(:namespace)
46
+ end
47
+
48
+ def version
49
+ configuration.fetch(:version)
50
+ end
51
+
52
+ def description
53
+ configuration.fetch(:description)
54
+ end
55
+
56
+ def deprecated
57
+ if configuration.fetch(:deprecated).respond_to?(:fetch)
58
+ configuration.fetch(:deprecated).fetch(action, nil)
59
+ else
60
+ configuration.fetch(:deprecated)
61
+ end
62
+ end
63
+
64
+ def documentation
65
+ configuration.fetch(:documentation)
66
+ end
67
+
68
+ def jsonapi_version
69
+ configuration.fetch(:version)
70
+ end
71
+
72
+ def verb
73
+ route.verb
74
+ end
75
+
76
+ def href
77
+ File.join(location, path)
78
+ end
79
+
80
+ def location
81
+ configuration.fetch(:location) ||
82
+ ENV.fetch("HOME_LOCATION", nil) ||
83
+ Rails.application.routes.url_helpers.root_path
84
+ end
85
+
86
+ def mediatype
87
+ JSONAPI::MEDIA_TYPE
88
+ end
89
+
90
+ def created_at
91
+ CREATED_AT
92
+ end
93
+
94
+ def updated_at
95
+ Time.now
96
+ end
97
+
98
+ def valid?
99
+ !route.internal && defaults.any? && controller.present? && configuration
100
+ end
101
+
102
+ private def payload
103
+ route.parts.without(:format).map {|part| {part => "{#{part}}"}}.reduce(:merge) || {}
104
+ end
105
+
106
+ private def path
107
+ URI.decode(route.format(payload))
108
+ end
109
+
110
+ private def controller
111
+ controller_name.constantize
112
+ rescue NameError => exception
113
+ Rails.logger.debug("jsonapi-home saw a route and tried to find #{controller_name}")
114
+ end
115
+
116
+ private def action
117
+ defaults.fetch(:action)
118
+ end
119
+
120
+ private def controller_name
121
+ "#{defaults.fetch(:controller).classify.pluralize}Controller"
122
+ end
123
+
124
+ private def defaults
125
+ route.defaults
126
+ end
127
+
128
+ private def configuration
129
+ controller.instance_variable_get(:@jsonapi_home_endpoint)
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,22 @@
1
+ module JSONAPI
2
+ module Home
3
+ module V1
4
+ class ResourceRealizer
5
+ include JSONAPI::Realizer::Resource
6
+
7
+ register :jsonapi_home_resources, class_name: "JSONAPI::Home::V1::Resource", adapter: :memory
8
+
9
+ has :namespace
10
+ has :version
11
+ has :intent
12
+ has :verb
13
+ has :href
14
+ has :deprecated
15
+ has :mediatype
16
+ has :description
17
+ has :created_at
18
+ has :updated_at
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,42 @@
1
+ module JSONAPI
2
+ module Home
3
+ module V1
4
+ class ResourceSerializer
5
+ include JSONAPI::Serializer
6
+
7
+ attribute :namespace
8
+ attribute :version
9
+ attribute :intent
10
+ attribute :description
11
+ attribute :deprecated
12
+ attribute :verb
13
+ attribute :href
14
+ attribute :mediatype
15
+ attribute :created_at
16
+ attribute :updated_at
17
+
18
+ def type
19
+ "jsonapi-home-resources"
20
+ end
21
+
22
+ def jsonapi
23
+ {
24
+ version: object.jsonapi_version
25
+ }
26
+ end
27
+
28
+ def meta
29
+ [
30
+ if object.documentation
31
+ {
32
+ documentation: {
33
+ href: object.documentation
34
+ }
35
+ }
36
+ end,
37
+ ].compact.reduce(&:merge)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,7 @@
1
+ JSONAPI::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 :jsonapi_home_resources, controller: :resources, path: "jsonapi-home-resources", only: [:index, :show]
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module JSONAPI
2
+ require_relative "jsonapi/home"
3
+ end
@@ -0,0 +1,30 @@
1
+ require "jsonapi-realizer"
2
+ require "jsonapi-serializers"
3
+ require "array-where"
4
+
5
+ module JSONAPI
6
+ MEDIA_TYPE = "application/vnd.api+json" unless const_defined?("MEDIA_TYPE")
7
+
8
+ module Home
9
+ extend ActiveSupport::Concern
10
+
11
+ DEFAULT_DESCRIPTION = "A JSON:API resource as defined at https://www.jsonapi.org"
12
+
13
+ require_relative "home/inflector"
14
+ require_relative "home/engine"
15
+
16
+ class_methods do
17
+ def discoverable(version:, namespace:, deprecated: nil, description: DEFAULT_DESCRIPTION, documentation: nil, location: nil, jsonapi_version: "1.0")
18
+ instance_variable_set(:@jsonapi_home_endpoint, {
19
+ location: location,
20
+ description: description,
21
+ deprecated: deprecated,
22
+ documentation: documentation,
23
+ jsonapi_version: jsonapi_version,
24
+ version: version,
25
+ namespace: namespace
26
+ })
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,7 @@
1
+ module JSONAPI
2
+ module Home
3
+ class Engine < Rails::Engine
4
+ isolate_namespace JSONAPI::Home
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module JSONAPI
2
+ module Home
3
+ ActiveSupport::Inflector.inflections do |inflect|
4
+ inflect.acronym 'JSONAPI'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ module JSONAPI
2
+ module Home
3
+ VERSION = "1.0.0"
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe JSONAPI::Home do
4
+
5
+ end
metadata ADDED
@@ -0,0 +1,197 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jsonapi-home
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Kurtis Rainbolt-Greene
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-03-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.16.1
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.16.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 3.7.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 3.7.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 12.3.1
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 12.3.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 0.11.3
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 0.11.3
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry-doc
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '='
74
+ - !ruby/object:Gem::Version
75
+ version: 0.13.3
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '='
81
+ - !ruby/object:Gem::Version
82
+ version: 0.13.3
83
+ - !ruby/object:Gem::Dependency
84
+ name: sqlite3
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '='
88
+ - !ruby/object:Gem::Version
89
+ version: 1.3.13
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '='
95
+ - !ruby/object:Gem::Version
96
+ version: 1.3.13
97
+ - !ruby/object:Gem::Dependency
98
+ name: rails
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '='
102
+ - !ruby/object:Gem::Version
103
+ version: 5.1.5
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '='
109
+ - !ruby/object:Gem::Version
110
+ version: 5.1.5
111
+ - !ruby/object:Gem::Dependency
112
+ name: jsonapi-realizer
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '='
116
+ - !ruby/object:Gem::Version
117
+ version: 4.1.0
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '='
123
+ - !ruby/object:Gem::Version
124
+ version: 4.1.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: jsonapi-serializers
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '='
130
+ - !ruby/object:Gem::Version
131
+ version: 1.0.0
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '='
137
+ - !ruby/object:Gem::Version
138
+ version: 1.0.0
139
+ - !ruby/object:Gem::Dependency
140
+ name: array-where
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - '='
144
+ - !ruby/object:Gem::Version
145
+ version: 2.0.0
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '='
151
+ - !ruby/object:Gem::Version
152
+ version: 2.0.0
153
+ description: An early implementation of JSONAPIHome, a fork of JSONHome
154
+ email:
155
+ - kurtis@rainbolt-greene.online
156
+ executables: []
157
+ extensions: []
158
+ extra_rdoc_files: []
159
+ files:
160
+ - README.md
161
+ - Rakefile
162
+ - app/controllers/jsonapi/home/v1/resources_controller.rb
163
+ - app/models/jsonapi/home/v1/resource.rb
164
+ - app/realizers/jsonapi/home/v1/resource_realizer.rb
165
+ - app/serializers/jsonapi/home/v1/resource_serializer.rb
166
+ - config/routes.rb
167
+ - lib/jsonapi-home.rb
168
+ - lib/jsonapi/home.rb
169
+ - lib/jsonapi/home/engine.rb
170
+ - lib/jsonapi/home/inflector.rb
171
+ - lib/jsonapi/home/version.rb
172
+ - lib/jsonapi/home_spec.rb
173
+ homepage: http://krainboltgreene.github.io/jsonapi-home
174
+ licenses:
175
+ - ISC
176
+ metadata: {}
177
+ post_install_message:
178
+ rdoc_options: []
179
+ require_paths:
180
+ - lib
181
+ required_ruby_version: !ruby/object:Gem::Requirement
182
+ requirements:
183
+ - - ">="
184
+ - !ruby/object:Gem::Version
185
+ version: '0'
186
+ required_rubygems_version: !ruby/object:Gem::Requirement
187
+ requirements:
188
+ - - ">="
189
+ - !ruby/object:Gem::Version
190
+ version: '0'
191
+ requirements: []
192
+ rubyforge_project:
193
+ rubygems_version: 2.7.6
194
+ signing_key:
195
+ specification_version: 4
196
+ summary: An early implementation of JSONAPIHome, a fork of JSONHome
197
+ test_files: []