json-rest-api 1.0.14 → 1.0.16

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.
Files changed (118) hide show
  1. package/connectors_ideas/fastify.js +66 -68
  2. package/connectors_ideas/koa-plugin.js +50 -51
  3. package/eslint.config.js +11 -2
  4. package/examples/url-override-example.js +63 -63
  5. package/index.js +13 -13
  6. package/lib/enhanced-logger.js +51 -51
  7. package/lib/error-formatter.js +61 -61
  8. package/lib/rest-api-errors.js +28 -28
  9. package/package.json +1 -1
  10. package/plugins/core/bulk-operations-plugin.js +142 -145
  11. package/plugins/core/connectors/express-plugin.js +210 -217
  12. package/plugins/core/connectors/lib/busboy-detector.js +84 -84
  13. package/plugins/core/connectors/lib/formidable-detector.js +50 -50
  14. package/plugins/core/connectors/lib/request-helpers.js +74 -74
  15. package/plugins/core/file-handling-plugin.js +125 -125
  16. package/plugins/core/lib/anyapi/anyapi-registry.js +254 -254
  17. package/plugins/core/lib/anyapi/query/anyapi-query-adapter.js +287 -287
  18. package/plugins/core/lib/anyapi/schema-utils.js +101 -101
  19. package/plugins/core/lib/anyapi/utils/descriptor-helpers.js +41 -41
  20. package/plugins/core/lib/dbTablesOperations.js +134 -135
  21. package/plugins/core/lib/fractional-positioning.js +74 -76
  22. package/plugins/core/lib/querying/knex-cross-table-search.js +320 -320
  23. package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +144 -144
  24. package/plugins/core/lib/querying/knex-pagination-helpers.js +164 -164
  25. package/plugins/core/lib/querying/knex-process-includes.js +50 -50
  26. package/plugins/core/lib/querying/knex-query-helpers-base.js +31 -31
  27. package/plugins/core/lib/querying/knex-query-helpers.js +451 -452
  28. package/plugins/core/lib/querying/knex-relationship-includes.js +1160 -1170
  29. package/plugins/core/lib/querying/knex-window-queries.js +89 -89
  30. package/plugins/core/lib/querying/url-helpers.js +35 -35
  31. package/plugins/core/lib/querying-writing/compile-schemas.js +99 -99
  32. package/plugins/core/lib/querying-writing/connectors-query-parser.js +31 -31
  33. package/plugins/core/lib/querying-writing/database-capabilities.js +94 -94
  34. package/plugins/core/lib/querying-writing/database-value-normalizers.js +76 -76
  35. package/plugins/core/lib/querying-writing/default-data-helpers.js +27 -27
  36. package/plugins/core/lib/querying-writing/field-utils.js +44 -42
  37. package/plugins/core/lib/querying-writing/knex-constants.js +15 -16
  38. package/plugins/core/lib/querying-writing/knex-field-helpers.js +117 -115
  39. package/plugins/core/lib/querying-writing/knex-json-api-transformers.js +41 -41
  40. package/plugins/core/lib/querying-writing/payload-validators.js +275 -275
  41. package/plugins/core/lib/querying-writing/schema-helpers.js +129 -129
  42. package/plugins/core/lib/querying-writing/scope-validations.js +143 -146
  43. package/plugins/core/lib/querying-writing/simplified-helpers.js +133 -129
  44. package/plugins/core/lib/storage/storage-adapter.js +68 -68
  45. package/plugins/core/lib/writing/knex-json-api-transformers-writing.js +31 -31
  46. package/plugins/core/lib/writing/many-to-many-manipulations.js +81 -81
  47. package/plugins/core/lib/writing/relationship-processor.js +58 -58
  48. package/plugins/core/rest-api-access.js +11 -15
  49. package/plugins/core/rest-api-anyapi-knex-plugin.js +920 -920
  50. package/plugins/core/rest-api-cors-plugin.js +170 -171
  51. package/plugins/core/rest-api-knex-plugin.js +482 -493
  52. package/plugins/core/rest-api-multihome-plugin.js +247 -251
  53. package/plugins/core/rest-api-plugin-hooks/compile-resource-schemas.js +5 -5
  54. package/plugins/core/rest-api-plugin-hooks/register-relationship-routes.js +20 -21
  55. package/plugins/core/rest-api-plugin-hooks/register-scope-routes.js +44 -44
  56. package/plugins/core/rest-api-plugin-hooks/turn-scope-init-into-vars.js +23 -23
  57. package/plugins/core/rest-api-plugin-hooks/validate-include-configurations.js +15 -15
  58. package/plugins/core/rest-api-plugin-methods/add-route.js +9 -9
  59. package/plugins/core/rest-api-plugin-methods/check-permissions.js +5 -6
  60. package/plugins/core/rest-api-plugin-methods/common.js +295 -297
  61. package/plugins/core/rest-api-plugin-methods/delete-relationship.js +35 -37
  62. package/plugins/core/rest-api-plugin-methods/delete.js +57 -59
  63. package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +172 -171
  64. package/plugins/core/rest-api-plugin-methods/get-related.js +96 -96
  65. package/plugins/core/rest-api-plugin-methods/get-relationship.js +16 -18
  66. package/plugins/core/rest-api-plugin-methods/get.js +86 -86
  67. package/plugins/core/rest-api-plugin-methods/patch-relationship.js +16 -17
  68. package/plugins/core/rest-api-plugin-methods/patch.js +63 -64
  69. package/plugins/core/rest-api-plugin-methods/post-relationship.js +54 -55
  70. package/plugins/core/rest-api-plugin-methods/post.js +61 -62
  71. package/plugins/core/rest-api-plugin-methods/put.js +86 -87
  72. package/plugins/core/rest-api-plugin-methods/query.js +88 -88
  73. package/plugins/core/rest-api-plugin-methods/release.js +5 -6
  74. package/plugins/core/rest-api-plugin.js +76 -78
  75. package/plugins/core/rest-api-positioning-plugin.js +251 -252
  76. package/plugins/core/socketio-plugin.js +240 -236
  77. package/plugins/storage/local-storage.js +103 -103
  78. package/plugins/storage/s3-storage.js +41 -42
  79. package/quickTest.js +37 -37
  80. package/scripts/debug-anyapi-review-filter.mjs +18 -18
  81. package/scripts/inspect-anyapi-descriptor-country.mjs +10 -10
  82. package/scripts/inspect-anyapi-descriptor.mjs +10 -10
  83. package/scripts/run-docs.js +112 -113
  84. package/test-debug.js +28 -28
  85. package/tests/TEST_TEMPLATE.test.js +51 -51
  86. package/tests/anyapi-basic.test.js +42 -42
  87. package/tests/anyapi-cursor-pagination.test.js +48 -48
  88. package/tests/bulk-operations.test.js +208 -208
  89. package/tests/computed-fields.test.js +204 -204
  90. package/tests/cors.test.js +412 -413
  91. package/tests/curl.test.js +275 -276
  92. package/tests/custom-idproperty-relationships.test.js +266 -266
  93. package/tests/field-getters.test.js +132 -132
  94. package/tests/field-setters.test.js +110 -110
  95. package/tests/fixtures/api-configs.js +699 -699
  96. package/tests/helpers/storage-mode.js +32 -32
  97. package/tests/helpers/test-utils.js +76 -76
  98. package/tests/include-depth-validation.test.js +76 -76
  99. package/tests/includes.test.js +145 -145
  100. package/tests/multihome.test.js +175 -175
  101. package/tests/nested-includes.test.js +255 -255
  102. package/tests/pagination-cursor-multifield.test.js +164 -164
  103. package/tests/pagination-enhanced.test.js +225 -225
  104. package/tests/polymorphic-relationships.test.js +96 -96
  105. package/tests/polymorphic-simple.test.js +44 -44
  106. package/tests/positioning-advanced.test.js +226 -226
  107. package/tests/positioning-extended.test.js +399 -399
  108. package/tests/positioning-multifilter.test.js +204 -204
  109. package/tests/positioning.test.js +266 -266
  110. package/tests/queries.test.js +184 -184
  111. package/tests/query-limits.test.js +154 -155
  112. package/tests/relationship-endpoints.test.js +127 -127
  113. package/tests/relationships.test.js +178 -179
  114. package/tests/rest-api-access.test.js +86 -86
  115. package/tests/rest-api.test.js +103 -103
  116. package/tests/searchschema-merge.test.js +93 -93
  117. package/tests/socketio.test.js +326 -326
  118. package/tests/virtual-fields.test.js +164 -164
@@ -1,16 +1,16 @@
1
- import { describe, it, before, after, beforeEach } from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import knexLib from 'knex';
4
- import {
5
- validateJsonApiStructure,
6
- cleanTables,
7
- createJsonApiDocument,
1
+ import { describe, it, before, after, beforeEach } from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+ import knexLib from 'knex'
4
+ import {
5
+ validateJsonApiStructure,
6
+ cleanTables,
7
+ createJsonApiDocument,
8
8
  createRelationship,
9
9
  createToManyRelationship,
10
10
  resourceIdentifier,
11
11
  countRecords
12
- } from './helpers/test-utils.js';
13
- import { createBasicApi } from './fixtures/api-configs.js';
12
+ } from './helpers/test-utils.js'
13
+ import { createBasicApi } from './fixtures/api-configs.js'
14
14
 
15
15
  // Create Knex instance for tests
16
16
  const knex = knexLib({
@@ -19,10 +19,10 @@ const knex = knexLib({
19
19
  filename: ':memory:'
20
20
  },
21
21
  useNullAsDefault: true
22
- });
22
+ })
23
23
 
24
24
  // API instance that persists across tests
25
- let api;
25
+ let api
26
26
 
27
27
  describe('Relationship Endpoints Plugin', () => {
28
28
  before(async () => {
@@ -32,80 +32,80 @@ describe('Relationship Endpoints Plugin', () => {
32
32
  mountPath: '' // No mount path for this test
33
33
  },
34
34
  includeExpress: true
35
- });
36
- });
35
+ })
36
+ })
37
37
 
38
38
  after(async () => {
39
39
  // Close database connection
40
- await knex.destroy();
41
- });
40
+ await knex.destroy()
41
+ })
42
42
 
43
43
  describe('Many-to-Many Relationship Endpoints', () => {
44
- let countryId;
45
- let book1Id;
46
- let author1Id;
47
- let author2Id;
48
- let author3Id;
44
+ let countryId
45
+ let book1Id
46
+ let author1Id
47
+ let author2Id
48
+ let author3Id
49
49
 
50
50
  beforeEach(async () => {
51
51
  await cleanTables(knex, [
52
52
  'basic_countries', 'basic_publishers', 'basic_authors', 'basic_books', 'basic_book_authors'
53
- ]);
53
+ ])
54
54
 
55
55
  // Create test data
56
- const countryDoc = createJsonApiDocument('countries', { name: 'USA', code: 'US' });
56
+ const countryDoc = createJsonApiDocument('countries', { name: 'USA', code: 'US' })
57
57
  const countryResult = await api.resources.countries.post({
58
58
  inputRecord: countryDoc,
59
59
  simplified: false
60
- });
61
- countryId = countryResult.data.id;
60
+ })
61
+ countryId = countryResult.data.id
62
62
 
63
63
  // Create a book
64
64
  const bookDoc = createJsonApiDocument('books',
65
65
  { title: 'Test Book' },
66
66
  { country: createRelationship(resourceIdentifier('countries', countryId)) }
67
- );
67
+ )
68
68
  const bookResult = await api.resources.books.post({
69
69
  inputRecord: bookDoc,
70
70
  simplified: false
71
- });
72
- book1Id = bookResult.data.id;
71
+ })
72
+ book1Id = bookResult.data.id
73
73
 
74
74
  // Create authors
75
- const author1Doc = createJsonApiDocument('authors', { name: 'Author One' });
75
+ const author1Doc = createJsonApiDocument('authors', { name: 'Author One' })
76
76
  const author1Result = await api.resources.authors.post({
77
77
  inputRecord: author1Doc,
78
78
  simplified: false
79
- });
80
- author1Id = author1Result.data.id;
79
+ })
80
+ author1Id = author1Result.data.id
81
81
 
82
- const author2Doc = createJsonApiDocument('authors', { name: 'Author Two' });
82
+ const author2Doc = createJsonApiDocument('authors', { name: 'Author Two' })
83
83
  const author2Result = await api.resources.authors.post({
84
84
  inputRecord: author2Doc,
85
85
  simplified: false
86
- });
87
- author2Id = author2Result.data.id;
86
+ })
87
+ author2Id = author2Result.data.id
88
88
 
89
- const author3Doc = createJsonApiDocument('authors', { name: 'Author Three' });
89
+ const author3Doc = createJsonApiDocument('authors', { name: 'Author Three' })
90
90
  const author3Result = await api.resources.authors.post({
91
91
  inputRecord: author3Doc,
92
92
  simplified: false
93
- });
94
- author3Id = author3Result.data.id;
95
- });
93
+ })
94
+ author3Id = author3Result.data.id
95
+ })
96
96
 
97
97
  it('should get empty relationship data for new book', async () => {
98
98
  const result = await api.resources.books.getRelationship({
99
99
  id: book1Id,
100
100
  relationshipName: 'authors'
101
- });
101
+ })
102
102
 
103
- assert(result.links, 'Should have links');
104
- assert.equal(result.links.self, `/books/${book1Id}/relationships/authors`);
105
- assert.equal(result.links.related, `/books/${book1Id}/authors`);
106
- assert(Array.isArray(result.data), 'Data should be an array');
107
- assert.equal(result.data.length, 0, 'Should have no authors');
108
- });
103
+ assert(result.links, 'Should have links')
104
+ assert.equal(result.links.self, `/books/${book1Id}/relationships/authors`)
105
+ assert.equal(result.links.related, `/books/${book1Id}/authors`)
106
+ assert(Array.isArray(result.data), 'Data should be an array')
107
+ assert.equal(result.data.length, 0, 'Should have no authors')
108
+ })
109
109
 
110
110
  it('should add authors to book via POST relationship endpoint', async () => {
111
111
  // Add authors via relationship endpoint
@@ -116,21 +116,21 @@ describe('Relationship Endpoints Plugin', () => {
116
116
  resourceIdentifier('authors', author1Id),
117
117
  resourceIdentifier('authors', author2Id)
118
118
  ]
119
- });
119
+ })
120
120
 
121
121
  // Verify authors were added via getRelationship
122
122
  const relResult = await api.resources.books.getRelationship({
123
123
  id: book1Id,
124
124
  relationshipName: 'authors'
125
- });
125
+ })
126
126
 
127
- assert.equal(relResult.data.length, 2, 'Should have 2 authors');
128
- assert.deepEqual(relResult.data[0], resourceIdentifier('authors', author1Id));
129
- assert.deepEqual(relResult.data[1], resourceIdentifier('authors', author2Id));
127
+ assert.equal(relResult.data.length, 2, 'Should have 2 authors')
128
+ assert.deepEqual(relResult.data[0], resourceIdentifier('authors', author1Id))
129
+ assert.deepEqual(relResult.data[1], resourceIdentifier('authors', author2Id))
130
130
 
131
131
  // Verify pivot table records
132
- const pivotCount = await countRecords(knex, 'basic_book_authors');
133
- assert.equal(pivotCount, 2, 'Should have 2 pivot records');
132
+ const pivotCount = await countRecords(knex, 'basic_book_authors')
133
+ assert.equal(pivotCount, 2, 'Should have 2 pivot records')
134
134
 
135
135
  // Verify through GET with include
136
136
  const getResult = await api.resources.books.get({
@@ -139,13 +139,13 @@ describe('Relationship Endpoints Plugin', () => {
139
139
  include: ['authors']
140
140
  },
141
141
  simplified: false
142
- });
142
+ })
143
143
 
144
- assert(getResult.included, 'Should have included data');
145
- assert.equal(getResult.included.length, 2, 'Should include 2 authors');
146
- assert(getResult.data.relationships.authors, 'Should have authors relationship');
147
- assert.equal(getResult.data.relationships.authors.data.length, 2);
148
- });
144
+ assert(getResult.included, 'Should have included data')
145
+ assert.equal(getResult.included.length, 2, 'Should include 2 authors')
146
+ assert(getResult.data.relationships.authors, 'Should have authors relationship')
147
+ assert.equal(getResult.data.relationships.authors.data.length, 2)
148
+ })
149
149
 
150
150
  it('should get related resources via GET related endpoint', async () => {
151
151
  // Add authors first
@@ -156,23 +156,23 @@ describe('Relationship Endpoints Plugin', () => {
156
156
  resourceIdentifier('authors', author1Id),
157
157
  resourceIdentifier('authors', author2Id)
158
158
  ]
159
- });
159
+ })
160
160
 
161
161
  // Get related resources
162
162
  const result = await api.resources.books.getRelated({
163
163
  id: book1Id,
164
164
  relationshipName: 'authors'
165
- });
165
+ })
166
166
 
167
167
  // Verify response
168
- validateJsonApiStructure(result, true); // true for collection
169
- assert.equal(result.data.length, 2, 'Should have 2 authors');
170
- assert.equal(result.data[0].type, 'authors');
171
- assert.equal(result.data[1].type, 'authors');
172
-
173
- const authorNames = result.data.map(a => a.attributes.name).sort();
174
- assert.deepEqual(authorNames, ['Author One', 'Author Two']);
175
- });
168
+ validateJsonApiStructure(result, true) // true for collection
169
+ assert.equal(result.data.length, 2, 'Should have 2 authors')
170
+ assert.equal(result.data[0].type, 'authors')
171
+ assert.equal(result.data[1].type, 'authors')
172
+
173
+ const authorNames = result.data.map(a => a.attributes.name).sort()
174
+ assert.deepEqual(authorNames, ['Author One', 'Author Two'])
175
+ })
176
176
 
177
177
  it('should remove specific authors via DELETE relationship endpoint', async () => {
178
178
  // Add all authors first
@@ -184,11 +184,11 @@ describe('Relationship Endpoints Plugin', () => {
184
184
  resourceIdentifier('authors', author2Id),
185
185
  resourceIdentifier('authors', author3Id)
186
186
  ]
187
- });
187
+ })
188
188
 
189
189
  // Verify all were added
190
- let pivotCount = await countRecords(knex, 'basic_book_authors');
191
- assert.equal(pivotCount, 3, 'Should have 3 pivot records');
190
+ let pivotCount = await countRecords(knex, 'basic_book_authors')
191
+ assert.equal(pivotCount, 3, 'Should have 3 pivot records')
192
192
 
193
193
  // Remove one author
194
194
  await api.resources.books.deleteRelationship({
@@ -197,22 +197,22 @@ describe('Relationship Endpoints Plugin', () => {
197
197
  relationshipData: [
198
198
  resourceIdentifier('authors', author2Id)
199
199
  ]
200
- });
200
+ })
201
201
 
202
202
  // Verify only two authors remain
203
203
  const relResult = await api.resources.books.getRelationship({
204
204
  id: book1Id,
205
205
  relationshipName: 'authors'
206
- });
206
+ })
207
207
 
208
- assert.equal(relResult.data.length, 2, 'Should have 2 authors remaining');
209
- assert.deepEqual(relResult.data[0], resourceIdentifier('authors', author1Id));
210
- assert.deepEqual(relResult.data[1], resourceIdentifier('authors', author3Id));
208
+ assert.equal(relResult.data.length, 2, 'Should have 2 authors remaining')
209
+ assert.deepEqual(relResult.data[0], resourceIdentifier('authors', author1Id))
210
+ assert.deepEqual(relResult.data[1], resourceIdentifier('authors', author3Id))
211
211
 
212
212
  // Verify pivot table
213
- pivotCount = await countRecords(knex, 'basic_book_authors');
214
- assert.equal(pivotCount, 2, 'Should have 2 pivot records');
215
- });
213
+ pivotCount = await countRecords(knex, 'basic_book_authors')
214
+ assert.equal(pivotCount, 2, 'Should have 2 pivot records')
215
+ })
216
216
 
217
217
  it('should handle errors when relationship does not exist', async () => {
218
218
  await assert.rejects(
@@ -223,8 +223,8 @@ describe('Relationship Endpoints Plugin', () => {
223
223
  {
224
224
  message: /Relationship 'nonexistent' not found/
225
225
  }
226
- );
227
- });
226
+ )
227
+ })
228
228
 
229
229
  it('should handle errors when posting to belongsTo relationship', async () => {
230
230
  await assert.rejects(
@@ -238,8 +238,8 @@ describe('Relationship Endpoints Plugin', () => {
238
238
  {
239
239
  message: /Cannot POST to to-one relationship/
240
240
  }
241
- );
242
- });
241
+ )
242
+ })
243
243
 
244
244
  it('should work with inverse relationship (authors to books)', async () => {
245
245
  // First add the relationship from book side
@@ -249,113 +249,113 @@ describe('Relationship Endpoints Plugin', () => {
249
249
  relationshipData: [
250
250
  resourceIdentifier('authors', author1Id)
251
251
  ]
252
- });
252
+ })
253
253
 
254
254
  // Now check from author side
255
255
  const relResult = await api.resources.authors.getRelationship({
256
256
  id: author1Id,
257
257
  relationshipName: 'books'
258
- });
258
+ })
259
259
 
260
- assert.equal(relResult.data.length, 1, 'Author should have 1 book');
261
- assert.deepEqual(relResult.data[0], resourceIdentifier('books', book1Id));
260
+ assert.equal(relResult.data.length, 1, 'Author should have 1 book')
261
+ assert.deepEqual(relResult.data[0], resourceIdentifier('books', book1Id))
262
262
 
263
263
  // Get related books
264
264
  const booksResult = await api.resources.authors.getRelated({
265
265
  id: author1Id,
266
266
  relationshipName: 'books'
267
- });
267
+ })
268
268
 
269
- validateJsonApiStructure(booksResult, true);
270
- assert.equal(booksResult.data.length, 1);
271
- assert.equal(booksResult.data[0].attributes.title, 'Test Book');
272
- });
273
- });
269
+ validateJsonApiStructure(booksResult, true)
270
+ assert.equal(booksResult.data.length, 1)
271
+ assert.equal(booksResult.data[0].attributes.title, 'Test Book')
272
+ })
273
+ })
274
274
 
275
275
  describe('One-to-Many Relationship Endpoints', () => {
276
- let countryId;
277
- let publisherId;
278
- let book1Id;
279
- let book2Id;
276
+ let countryId
277
+ let publisherId
278
+ let book1Id
279
+ let book2Id
280
280
 
281
281
  beforeEach(async () => {
282
282
  await cleanTables(knex, [
283
283
  'basic_countries', 'basic_publishers', 'basic_authors', 'basic_books', 'basic_book_authors'
284
- ]);
284
+ ])
285
285
 
286
286
  // Create test data
287
- const countryDoc = createJsonApiDocument('countries', { name: 'USA', code: 'US' });
287
+ const countryDoc = createJsonApiDocument('countries', { name: 'USA', code: 'US' })
288
288
  const countryResult = await api.resources.countries.post({
289
289
  inputRecord: countryDoc,
290
290
  simplified: false
291
- });
292
- countryId = countryResult.data.id;
291
+ })
292
+ countryId = countryResult.data.id
293
293
 
294
294
  // Create a publisher
295
295
  const publisherDoc = createJsonApiDocument('publishers',
296
296
  { name: 'Test Publisher' },
297
297
  { country: createRelationship(resourceIdentifier('countries', countryId)) }
298
- );
298
+ )
299
299
  const publisherResult = await api.resources.publishers.post({
300
300
  inputRecord: publisherDoc,
301
301
  simplified: false
302
- });
303
- publisherId = publisherResult.data.id;
302
+ })
303
+ publisherId = publisherResult.data.id
304
304
 
305
305
  // Create books
306
306
  const book1Doc = createJsonApiDocument('books',
307
307
  { title: 'Book One' },
308
- {
308
+ {
309
309
  country: createRelationship(resourceIdentifier('countries', countryId)),
310
310
  publisher: createRelationship(resourceIdentifier('publishers', publisherId))
311
311
  }
312
- );
312
+ )
313
313
  const book1Result = await api.resources.books.post({
314
314
  inputRecord: book1Doc,
315
315
  simplified: false
316
- });
317
- book1Id = book1Result.data.id;
316
+ })
317
+ book1Id = book1Result.data.id
318
318
 
319
319
  const book2Doc = createJsonApiDocument('books',
320
320
  { title: 'Book Two' },
321
- {
321
+ {
322
322
  country: createRelationship(resourceIdentifier('countries', countryId)),
323
323
  publisher: createRelationship(resourceIdentifier('publishers', publisherId))
324
324
  }
325
- );
325
+ )
326
326
  const book2Result = await api.resources.books.post({
327
327
  inputRecord: book2Doc,
328
328
  simplified: false
329
- });
330
- book2Id = book2Result.data.id;
331
- });
329
+ })
330
+ book2Id = book2Result.data.id
331
+ })
332
332
 
333
333
  it('should get one-to-many relationship data', async () => {
334
334
  const result = await api.resources.publishers.getRelationship({
335
335
  id: publisherId,
336
336
  relationshipName: 'books'
337
- });
337
+ })
338
338
 
339
- assert(result.links, 'Should have links');
340
- assert.equal(result.links.self, `/publishers/${publisherId}/relationships/books`);
341
- assert.equal(result.links.related, `/publishers/${publisherId}/books`);
342
- assert(Array.isArray(result.data), 'Data should be an array');
343
- assert.equal(result.data.length, 2, 'Should have 2 books');
344
- });
339
+ assert(result.links, 'Should have links')
340
+ assert.equal(result.links.self, `/publishers/${publisherId}/relationships/books`)
341
+ assert.equal(result.links.related, `/publishers/${publisherId}/books`)
342
+ assert(Array.isArray(result.data), 'Data should be an array')
343
+ assert.equal(result.data.length, 2, 'Should have 2 books')
344
+ })
345
345
 
346
346
  it('should get related resources for one-to-many', async () => {
347
347
  const result = await api.resources.publishers.getRelated({
348
348
  id: publisherId,
349
349
  relationshipName: 'books'
350
- });
350
+ })
351
351
 
352
- validateJsonApiStructure(result, true);
353
- assert.equal(result.data.length, 2);
354
- const titles = result.data.map(b => b.attributes.title).sort();
355
- assert.deepEqual(titles, ['Book One', 'Book Two']);
356
- });
352
+ validateJsonApiStructure(result, true)
353
+ assert.equal(result.data.length, 2)
354
+ const titles = result.data.map(b => b.attributes.title).sort()
355
+ assert.deepEqual(titles, ['Book One', 'Book Two'])
356
+ })
357
357
 
358
358
  // Note: belongsTo relationships (like 'publisher') are not accessible via relationship endpoints
359
359
  // They are foreign key fields, not true JSON:API relationships
360
- });
361
- });
360
+ })
361
+ })