Skip to content

Commit aec46ef

Browse files
committed
feat: add request data callbacks
This removes the non-conforming type case wrangling from the library. Uses where this is needed may still add it in later as a request data processing callback. The request callbacks receive all request info in reverse doAction order, meaning callback(data, parameters, url, method). url is only the path given to one of the method helpers, not yet the fully build url if a base url is set on the api object.
1 parent 57c4627 commit aec46ef

File tree

4 files changed

+47
-83
lines changed

4 files changed

+47
-83
lines changed

Changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# next version
22

3+
- **BREAKING**: Requests no longer get automatic type name fixing.
4+
This feature did not conform to the spec as there is no requirement
5+
for types to always be upper camel cased. If you need to perform
6+
this case fixing in your use case, you may re-add it via `ResourcefulApi`'s
7+
new `requestCallback`s.
38
- **BREAKING**: Success and error callbacks can no longer modify the response data,
49
to act on the parsed response data for all requests you **MUST** use
510
`ResourcefulApi`'s new `responseCallback`s.

src/api/ResourcefulApi.js

Lines changed: 23 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@ import { Api } from './Api'
44
import { ApiError, NotFoundApiError } from '../errors/ApiError'
55
import { ModuleBuilder } from '../module/ModuleBuilder'
66
import { ResourceProxy } from './ResourceProxy'
7-
import { deref, hasOwn } from '../shared/utils'
7+
import { hasOwn } from '../shared/utils'
88
import { Performance } from '../shared/Performance'
99

1010
export class ResourcefulApi extends Api {
1111
constructor () {
1212
super()
1313

14+
/** @var {Function[]} */
15+
this.requestCallbacks = []
16+
1417
/** @var {Function[]} */
1518
this.responseCallbacks = []
1619
}
@@ -20,6 +23,23 @@ export class ResourcefulApi extends Api {
2023
*
2124
* @param {Function[]} callbacks
2225
*/
26+
setRequestCallbacks (callbacks) {
27+
this.requestCallbacks = callbacks
28+
}
29+
30+
addRequestCallback (cb) {
31+
this.requestCallbacks.push(cb)
32+
}
33+
34+
resetRequestCallbacks () {
35+
this.requestCallbacks = []
36+
}
37+
38+
/**
39+
* Functions to be called with the parsed response data.
40+
*
41+
* @param {Function[]} callbacks
42+
*/
2343
setResponseCallbacks (callbacks) {
2444
this.responseCallbacks = callbacks
2545
}
@@ -45,8 +65,8 @@ export class ResourcefulApi extends Api {
4565
* @param {Object} data
4666
*/
4767
async _doRequest (method, url, params, data) {
48-
if (data) {
49-
data = this.preprocessData(data)
68+
for (const cb of this.requestCallbacks) {
69+
data = cb(data, params, url, method)
5070
}
5171

5272
return super._doRequest(method, url, params, data)
@@ -119,67 +139,6 @@ export class ResourcefulApi extends Api {
119139
}
120140
}
121141

122-
/**
123-
* convert ResourceTypes to uppercase
124-
* to follow the json:api spects even if the incoming data is not correct
125-
*
126-
* this is just a safety net
127-
*
128-
* @param data
129-
*
130-
* @return {*}
131-
*/
132-
preprocessData (data) {
133-
data = deref(data)
134-
data.data.type = data.data.type.charAt(0).toUpperCase() + data.data.type.slice(1)
135-
136-
if (data.data.relationships) {
137-
const relationships = {}
138-
const casingWarning = (type) => {
139-
console.warn(`The Resource with type '${type}' is sent in lower camel case. Please send as upper camel case.`)
140-
}
141-
142-
for (const [name, relationship] of Object.entries(data.data.relationships)) {
143-
if (Array.isArray(relationship.data)) {
144-
relationships[name] = {
145-
data: relationship.data.map(itemData => {
146-
const startChar = itemData.type.charAt(0)
147-
148-
if (startChar === startChar.toLocaleLowerCase()) {
149-
casingWarning(itemData.type)
150-
}
151-
152-
return {
153-
id: itemData.id,
154-
type: startChar.toUpperCase() + itemData.type.slice(1)
155-
}
156-
})
157-
}
158-
} else if (relationship.data !== null) {
159-
const startChar = relationship.data.type.charAt(0)
160-
161-
if (startChar === startChar.toLocaleLowerCase()) {
162-
casingWarning(relationship.data.type)
163-
}
164-
165-
relationships[name] = {
166-
data: {
167-
id: relationship.data.id,
168-
type: startChar.charAt(0).toUpperCase() + relationship.data.type.slice(1)
169-
}
170-
}
171-
} else if (relationship.data === null) {
172-
relationships[name] = {
173-
data: null
174-
}
175-
}
176-
}
177-
data.data.relationships = relationships
178-
}
179-
180-
return data
181-
}
182-
183142
/**
184143
* Prepare the routable requests
185144
*

src/init/initJsonApiPlugin.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ export function initJsonApiPlugin (config) {
2929
api.setErrorCallbacks(config.errorCallbacks)
3030
}
3131

32+
if (checkConfigProperty(config, 'requestCallbacks', false)) {
33+
api.setRequestCallbacks(config.requestCallbacks)
34+
}
35+
3236
if (checkConfigProperty(config, 'responseCallbacks', false)) {
3337
api.setResponseCallbacks(config.responseCallbacks)
3438
}

test/api/ResourcefulApi.spec.js

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -56,25 +56,6 @@ test('reads the initial module list', () => {
5656
expect(registerModuleMock.mock.calls.length).toBe(3)
5757
})
5858

59-
test('keeps null relationships after preprocessing', () => {
60-
const testResource = {
61-
data: {
62-
id: 1,
63-
type: 'User',
64-
relationships: {
65-
hobbies: {
66-
data: null
67-
}
68-
}
69-
}
70-
}
71-
72-
const api = new ResourcefulApi()
73-
74-
const preprocessedData = api.preprocessData(testResource)
75-
expect(preprocessedData.data.relationships.hobbies.data).toBe(null)
76-
})
77-
7859
test('runs response callbacks', async () => {
7960
const api = new ResourcefulApi()
8061
api.setBaseUrl('http://api/')
@@ -101,3 +82,18 @@ test('runs response callbacks', async () => {
10182
status_on_response: 200
10283
})
10384
})
85+
86+
test('runs request callbacks', async () => {
87+
const api = new ResourcefulApi()
88+
api.setBaseUrl('http://api/')
89+
90+
const cb = jest.fn(data => {
91+
return data
92+
})
93+
94+
api.addRequestCallback(cb)
95+
96+
await api.get('/book/1')
97+
98+
expect(cb.mock.calls.length).toBe(1)
99+
})

0 commit comments

Comments
 (0)