@weapnl/js-junction 0.0.1

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 (43) hide show
  1. package/CHANGELOG.md +128 -0
  2. package/README.md +348 -0
  3. package/babel.config.json +5 -0
  4. package/dist/index.js +4369 -0
  5. package/docker-compose.yml +14 -0
  6. package/index.d.ts +150 -0
  7. package/package.json +34 -0
  8. package/src/api.js +226 -0
  9. package/src/batch.js +39 -0
  10. package/src/builder/caster.js +67 -0
  11. package/src/builder/model.js +259 -0
  12. package/src/builder/properties/accessors.js +116 -0
  13. package/src/builder/properties/attributes.js +118 -0
  14. package/src/builder/properties/counts.js +79 -0
  15. package/src/builder/properties/property.js +37 -0
  16. package/src/builder/properties/relations.js +124 -0
  17. package/src/connection.js +83 -0
  18. package/src/filters/count.js +27 -0
  19. package/src/filters/filter.js +9 -0
  20. package/src/filters/filters.js +33 -0
  21. package/src/filters/limit.js +27 -0
  22. package/src/filters/order.js +30 -0
  23. package/src/filters/pluck.js +28 -0
  24. package/src/filters/relations.js +27 -0
  25. package/src/filters/scopes.js +30 -0
  26. package/src/filters/search.js +34 -0
  27. package/src/filters/whereIn.js +31 -0
  28. package/src/filters/wheres.js +32 -0
  29. package/src/index.js +12 -0
  30. package/src/mixins/actionMixin.js +20 -0
  31. package/src/mixins/filterMixin.js +104 -0
  32. package/src/mixins/modifierMixin.js +22 -0
  33. package/src/mixins/paginationMixin.js +20 -0
  34. package/src/modifiers/appends.js +28 -0
  35. package/src/modifiers/hiddenFields.js +27 -0
  36. package/src/modifiers/modifier.js +9 -0
  37. package/src/modifiers/modifiers.js +19 -0
  38. package/src/request/action.js +29 -0
  39. package/src/request/pagination.js +35 -0
  40. package/src/request.js +317 -0
  41. package/src/response.js +33 -0
  42. package/src/utilities/format.js +11 -0
  43. package/webpack.config.js +28 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,128 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ ## v3.3.5
6
+ - Lodash is now globally available.
7
+
8
+ ## v3.3.4
9
+ - Changed how empty array/object is sent to API through form-data. Previously a key with a `null` value would be sent, now a key with an empty string value will be sent.
10
+
11
+ ## v3.3.3
12
+ - Changed how empty array/object is sent to API through form-data. Previously no key or value would be sent, now a key with a `null` value will be sent.
13
+
14
+ ## v3.3.2
15
+ - Added new option to `attribute, relation or accessor` called `jsonKey` which specifies the key to use when parsing from/to json.
16
+
17
+ ## v3.3.1
18
+ - Now using *signal* instead of the deprecated *cancel token* to cancel requests.
19
+ - Updated `axios` to `1.3`.
20
+ - Fixed dependency vulnerabilities (`npm audit fix`).
21
+
22
+ ## v3.3.0
23
+ - Added ability to set global headers.
24
+
25
+ ## v3.2.0
26
+ - Added ability to set response interceptors.
27
+
28
+ ## v3.1.0
29
+ - Fixed bug where `null` values were omitted when using a FormData request.
30
+
31
+ ## v3.0.5
32
+ - Fixed the bug where the given data was merged into the files object in the `storeFiles` method.
33
+
34
+ ## v3.0.4
35
+ - Added build service in docker-compose.
36
+ - Booleans are now cast to `'0'` or `'1'` in form data.
37
+
38
+ ## v3.0.3
39
+ - Fixed bug where `model.show()` would allow an empty parameter, effectively causing an `index` request to be executed.
40
+ - When type of `attribute, relation or accessor` is Object, and the json value is an Array, convert it to an Object.
41
+
42
+ ## v3.0.2
43
+ - Improvement to some JSDoc's for better autocomplete.
44
+ - Made data of FormData recursive when using the `storeFiles` method on the `Request` model.
45
+
46
+ ## v3.0.1
47
+ - Fixed bug where `false` values would be parsed as `null`.
48
+
49
+ ## v3.0.0
50
+ - Added docker-compose file.
51
+ - Now using `/src/index.js` as main file instead of `/dist/index.js`.
52
+ - Added a pluck method.
53
+
54
+ ## v2.7.5
55
+ - Added `toJson` and `fromJson` options for accessors.
56
+
57
+ ## v2.7.4
58
+ - Fixed a bug where the default value for Accessor's was not used properly.
59
+
60
+ ## v2.7.3
61
+ - Fixed a bug where query params would contain empty or null values.
62
+
63
+ ## v2.7.2
64
+ - Fixed a bug in `Caster.js` where Array type would be cast to an array inside an array (for example `[["test@email.com"]]`).
65
+
66
+ ## v2.7.1
67
+ - Fixed a bug in `Caster.js` where an error was thrown if an accessor value of type `Model` was null/undefined.
68
+ - Added `storeFiles()` to the `batch` class.
69
+
70
+ ## v2.7.0
71
+ - Added `counts` to count relations (#3).
72
+ - Added ability to perform an action using the `action()` method in the Request class.
73
+ - **BREAKING:** `save()` method on Model class doesn't accept `identifier` parameter anymore.
74
+
75
+ ## v2.6.0
76
+ - Added ability to store files through the `storeFiles()` method in the request class.
77
+ - Added method (`customParameters`) to add custom parameters to a request.
78
+ - Now handling any status code between 200-300 as a successful request.
79
+ - Fixed a bug where the `Caster` class tried to cast an `undefined` value and crashed. Added extra check which returns `null` when the value to be cast is `undefined`
80
+
81
+ ## v2.5.1
82
+ - Fixed bug where the `whereIn` filter set the wrong variable for the column.
83
+
84
+ ## v2.5.0
85
+ - Added `save()` method to Model and Batch classes.
86
+ - Now setting properties on model instead of using getters/setters.
87
+ - Fixed bug where default attribute/relation values weren't set when creating a new model.
88
+ - Added ability to set type for `accessors` so they can be cast.
89
+
90
+ ## v2.4.0
91
+ - Fixed bug where having 2 models with relations to each other would result in an infinite loop.
92
+ - Added `extraData` parameter to the `store()` and `update()` methods on a `Model`.
93
+ - Added function (`batch`) to run multiple requests at the same time (#2).
94
+ - Added ability to set default values in constructor of models.
95
+ - Response events are now async safe.
96
+ - Changed how casting is done and the caster doesn't try to cast `null` values anymore.
97
+ - Now formatting error messages so nested errors are returned as objects.
98
+
99
+ ## v2.3.1
100
+ - Fixed bug where converting to snake case would break when using dot notation.
101
+
102
+ ## v2.3.0
103
+ - **BREAKING:** Removed the `defaults()` and `casts()` methods in favor of a new `attributes()` method for better expandability of the package.
104
+ - Added `relations()` and `accessors()` methods to the Model class.
105
+ - **BREAKING:** Removed the `getAttribute()` and `setAttribute()` methods of the Model class.
106
+ - **BREAKING:** `toJson()` now returns the attributes, accessors and relations instead of just the attributes.
107
+
108
+ ## v2.2.0
109
+ - Now converting columns to snake case in `order`, `search`, `whereIn` and `wheres`.
110
+ - Moved `pagination` from modifiers to separate class (in accordance with https://repo.weap.nl/packages/laravel/restapi/-/merge_requests/8).
111
+ - Added optional `findPageById` parameter to `pagination` to find the page the given id is on.
112
+
113
+ ## v2.1.0
114
+ - Added `casts()` method to the `Model` class so specific casts can be done on incoming json.
115
+ - Fixed a bug where in some filters the wrong separator was used to generate the url.
116
+
117
+ ## v2.0.0
118
+ - Added `Model` class with included query builder for an easier syntax than the existing requests.
119
+ - Changed entry file from `api.js` to a new file `index.js`.
120
+ - Moved some code from `Request` to new class `Connection` to support the new `Model` class.
121
+ - Moved `filter` and `modifier` methods to mixins.
122
+ - **BREAKING:** Changed how the `api` is initialized and configured. Read `README.md` for more info.
123
+
124
+ ## v1.1.0
125
+ - Added custom callbacks `onSuccess`, `onError`, `onValidationError`, `onUnauthorized`, `onForbidden`.
126
+
127
+ ## v1.0.0
128
+ - Initial version
package/README.md ADDED
@@ -0,0 +1,348 @@
1
+ # JS-Junction
2
+
3
+ This project allows you to easily consume API's built with [Laravel-Junction](https://github.com/weapnl/Laravel-Junction).
4
+
5
+ This package has support for Typescript (TS).
6
+
7
+ ## Table of Contents
8
+
9
+ - [Installation](#installation)
10
+ - [Quick Start](#quick-start)
11
+ - [Usage](#usage)
12
+ - [Creating Models](#creating-models)
13
+ - [Performing Requests](#performing-requests)
14
+ - [Applying Filters and Scopes](#applying-filters-and-scopes)
15
+
16
+ ## Installation
17
+ ```bash
18
+ npm install @weapnl/js-junction
19
+ ```
20
+
21
+ ## Quick Start
22
+ ```javascript
23
+ import api, { Model } from '@weapnl/js-junction';
24
+
25
+ api.host('YOUR API HOST URI HERE') // Optionally: add '.suffix('API SUFFIX HERE');'
26
+
27
+ // Define a model
28
+ class User extends Model {
29
+ static attributes () {
30
+ return {
31
+ id: {
32
+ type: Number,
33
+ },
34
+ name: {
35
+ type: String,
36
+ },
37
+ };
38
+ }
39
+
40
+ static get endpoint () {
41
+ return 'users';
42
+ }
43
+ }
44
+
45
+ // Create a new user.
46
+ const user = new User();
47
+ user.name = 'John';
48
+ user.store();
49
+
50
+ // Retrieve a user.
51
+ const user = User.show(1);
52
+
53
+ // Update the user.
54
+ user.name = 'Jane';
55
+ user.update();
56
+
57
+ // Delete the user.
58
+ user.destroy();
59
+
60
+ // List all users.
61
+ const users = User.index();
62
+ ```
63
+
64
+ ## Usage
65
+
66
+ ### Creating Models
67
+ ```javascript
68
+ // User.js
69
+ import { Model } from '@weapnl/js-junction';
70
+
71
+ export default class User extends Model {
72
+ // All the model properties which are fully readable and fillable on the API
73
+ static attributes () {
74
+ return {
75
+ // Note: id is ALWAYS required
76
+ id: {
77
+ // Default value to be assigned when creating the empty property.
78
+ default: 0,
79
+
80
+ // Will be used to cast from/to json. Has higher priority than the seperate 'fromJson' and 'toJson' methods.
81
+ type: Number, // Type will be used to cast from and to json
82
+
83
+ // Casts that will be performed when creating the model from json.
84
+ // Allows:
85
+ // - Functions
86
+ // - Array of functions, executed from left to right and each following function gets the return value of the previous.
87
+ // - Javascript types
88
+ // - Models that inherit from the Model class.
89
+ fromJson: _.toNumber,
90
+ toJson: [_.toString, _.trim],
91
+
92
+ // The key which is used when parsing the attribute from/to json. By default the snake_case version of the attribute name will be used.
93
+ jsonKey: 'id',
94
+ },
95
+
96
+ // All options are optional and if no options are given an empty object should be passed.
97
+ name: {},
98
+ email: {},
99
+ phone: {},
100
+ };
101
+ }
102
+
103
+ // Relations of the model which are defined in the API
104
+ static relations () {
105
+ return {
106
+ addresses: {
107
+ // Value(s) of the relation will be cast to the type. Same casts are allowed as the attributes.
108
+ // If a list of items is returned, the cast will be preformed on each item seperately.
109
+ type: Address,
110
+
111
+ // The key which is used when parsing the attribute from/to json. By default the snake_case version of the attribute name will be used.
112
+ jsonKey: 'id',
113
+ },
114
+ };
115
+ }
116
+
117
+ // Accessors of the model which are defined in the API.
118
+ static accessors () {
119
+ return {
120
+ fullName: {
121
+ // Default value to be assigned when creating the empty property.
122
+ default: '',
123
+
124
+ // Will be used to cast from/to json. Has higher priority than the seperate 'fromJson' and 'toJson' methods.
125
+ type: String,
126
+
127
+ // Casts that will be performed when creating the model from json.
128
+ // Allows:
129
+ // - Functions
130
+ // - Array of functions, executed from left to right and each following function gets the return value of the previous.
131
+ // - Javascript types
132
+ // - Models that inherit from the Model class.
133
+ fromJson: _.toNumber,
134
+ toJson: [_.toString, _.trim],
135
+
136
+ // The key which is used when parsing the attribute from/to json. By default the snake_case version of the attribute name will be used.
137
+ jsonKey: 'id',
138
+ },
139
+ }
140
+ }
141
+
142
+ // Counts of relations of the model which are defined in the API.
143
+ static counts () {
144
+ return {
145
+ posts: {
146
+ default: 0,
147
+ },
148
+ }
149
+ }
150
+
151
+ // Used to know what URL to send the request to.
152
+ static get endpoint () {
153
+ return 'users';
154
+ }
155
+ }
156
+ ```
157
+
158
+ ### Performing Requests
159
+
160
+ #### Model Requests
161
+ ```javascript
162
+ // Create a new user.
163
+ const user = new User();
164
+ user.name = 'John';
165
+ user.store();
166
+
167
+ // Retrieve a user.
168
+ const user = new User().show(1);
169
+
170
+ // Update the user.
171
+ user.name = 'Jane';
172
+ user.save(); // This will call store() or update() depending on the id of the model.
173
+
174
+ // Delete the user.
175
+ user.destroy();
176
+
177
+ // List all users.
178
+ const users = new User().index();
179
+ ```
180
+
181
+ #### Applying filters and scopes
182
+ ```javascript
183
+ // Get all users that match the filters
184
+ const request = await new User()
185
+ .limit(10) // Limit max 10 items
186
+ .order('id', 'asc') // Order by id ascending
187
+ .order([['id', 'asc'], ['name', 'desc']]) // Order by id ascending and name descending
188
+ .with('orders') // Load relation
189
+ .with(['orders']) // Load relations
190
+ .count('orders') // Add relation counts (will add a key `ordersCount` to the result)
191
+ .scope('hasOrders', 'extra params') // Apply scope
192
+ .search('john doe') // Search for 'john doe', on the searchable columns of the model (defined in the API)
193
+ .search('john doe', ['name', 'email']) // Search for 'john doe' in columns 'name' and 'email'
194
+ .whereIn('city', ['Gemert', 'Eindhoven', 'Amsterdam']) // Set where in clause
195
+ .where('name', '=', 'John') // Add where clause
196
+ .where('name', 'John') // If no operator is given, '=' is used
197
+ .appends('age') // Add accessor
198
+ .appends(['age']) // Add accessors
199
+ .hiddenFields('id') // Hide field
200
+ .hiddenFields(['id', 'comments']) // Hide fields
201
+ .pluck('name') // Only retrieve the given fields
202
+ .pluck(['name', 'company.name']) // Only retrieve the given fields
203
+ .pagination(1, 25) // Paginate 25 per page, page 1
204
+ .pagination(1, 25, 50) // The 3th parameter is a pageForId parameter. This is used to find the correct page for the given id. If the id can not be found, the given page will be used. It will now look for the user with id 50, and returns that page.
205
+ .get();
206
+ ```
207
+
208
+ #### Examples
209
+
210
+ **The `.save()` method.**
211
+
212
+ To create a new record or update an existing one, you can use the `.save()` method. This method is a convenient shortcut for `.store()` and `.update()`. It determines whether to create or update by checking if the model's `id` is set. If an `id` is present, `.update()` is called; otherwise, `.store()` is used to create a new record.
213
+
214
+ **Cloning a model's instance.**
215
+ ```javascript
216
+ // Return a clone of the model
217
+ const clonedUser = user.clone();
218
+ ```
219
+
220
+ **Batch requests**
221
+ ```javascript
222
+ const firstUser = new User().show(1);
223
+ firstUser.name = 'John';
224
+
225
+ const secondUser = new User().show(2);
226
+ secondUser.name = 'Jane';
227
+
228
+ const batch = await api.batch([
229
+ firstUser,
230
+ secondUser,
231
+ ]);
232
+
233
+ await batch.update();
234
+
235
+ if (batch.successful) {
236
+ // All requests executed successfully.
237
+ }
238
+ ```
239
+
240
+ **Regular requests**
241
+ ```javascript
242
+ // Get all users from a custom endpoint
243
+ const users = api.request('users').get();
244
+
245
+ // Custom POST request
246
+ await api.request('users')
247
+ .onSuccess((response) => {
248
+ // Handle success
249
+ })
250
+ .post({
251
+ name: 'John',
252
+ email: 'john@example.com'
253
+ });
254
+ ```
255
+ The request has support for GET, POST, PUT and DELETE requests.
256
+
257
+ **Custom actions**
258
+
259
+ This package also supports custom actions. These actions can be defined in the API and can be called on a model or a custom request.
260
+ ```javascript
261
+ const request = await api
262
+ .request('CUSTOM ENDPOINT')
263
+ .action('actionName', 1) // You can pass the id of the model here, or the id of the request. In this case it is 1.
264
+ .put({
265
+ // Extra data
266
+ });
267
+
268
+ const user = new User().show(1);
269
+
270
+ const request = await user
271
+ .action('actionName') // It will take the id of the user now, since it is a model. The id is 1 in this case.
272
+ .put({
273
+ // Extra data
274
+ });
275
+ ```
276
+ **Store files**
277
+
278
+ ```javascript
279
+ // First parameter is a file or array of files.
280
+ // Second parameter is an object with possible extra data to send to the backend. PLEASE NOTE: Be aware that it will be sent as FormData.
281
+
282
+ let request = await api.request('users/files')
283
+ .storeFiles(this.files, {
284
+ filePrefix: 'test_',
285
+ extraDataId: 123,
286
+ });
287
+ ```
288
+
289
+ **Custom callbacks**
290
+
291
+ ```javascript
292
+ let request = await api.request('users')
293
+ .onSuccess((data) => {
294
+ // Request successful
295
+ })
296
+ .onUnauthorized((response) => {
297
+ // Missing or invalid token
298
+ })
299
+ .onForbidden((response) => {
300
+ // Access not allowed
301
+ })
302
+ .onValidationError((validation) => {
303
+ // validation.message
304
+ // validation.errors
305
+ })
306
+ .onError((response) => {
307
+ // Any other status code not caught by other callbacks
308
+ })
309
+ .get();
310
+ ```
311
+
312
+ **Cancel requests**
313
+
314
+ If you want to cancel a pending request, you can do the following:
315
+ ```javascript
316
+ const request = api.request('users').get();
317
+ request.cancel();
318
+
319
+ api.cancelRequests(); // Cancel all currently pending requests.
320
+ ```
321
+
322
+ **Set a bearer token**
323
+
324
+ ```javascript
325
+ api.setBearer('YOUR TOKEN HERE');
326
+
327
+ api.resetBearer(); // Resets the bearer token.
328
+ ```
329
+
330
+ **Set a CSRF token**
331
+
332
+ ```javascript
333
+ api.setCsrf('YOUR TOKEN HERE');
334
+
335
+ api.resetCsrf(); // Resets the CSRF token.
336
+ ```
337
+
338
+ **Set a custom header**
339
+
340
+ ```javascript
341
+ api.setHeader('HEADER NAME HERE', 'YOUR VALUE HERE');
342
+
343
+ api.removeHeader('HEADER NAME HERE'); // Removes the header.
344
+ ```
345
+
346
+ **Sample response**
347
+
348
+ After executing a request, the property `response` contains a `Response` object, which has properties `statusCode`, `data` and `validation`.
@@ -0,0 +1,5 @@
1
+ {
2
+ "presets": [
3
+ "@babel/preset-env"
4
+ ]
5
+ }