make-service 1.0.0 → 1.1.0-next.0
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.
- package/README.md +46 -3
- package/dist/index.d.ts +58 -12
- package/dist/index.js +60 -0
- package/dist/index.mjs +54 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,9 +8,10 @@ It adds a set of little features and allows you to parse responses with [zod](ht
|
|
|
8
8
|
- 🤩 Type-safe return of `response.json()` and `response.text()`. Defaults to `unknown` instead of `any`.
|
|
9
9
|
- 🚦 Easily setup an API with a `baseURL` and common `headers` for every request.
|
|
10
10
|
- 🏗️ Compose URL from the base by just calling the endpoints and an object-like `query`.
|
|
11
|
-
- 🐾 Replaces URL wildcards with
|
|
11
|
+
- 🐾 Replaces URL wildcards with a **strongly-typed** object of `params`.
|
|
12
12
|
- 🧙♀️ Automatically stringifies the `body` of a request so you can give it a JSON-like structure.
|
|
13
13
|
- 🐛 Accepts a `trace` function for debugging.
|
|
14
|
+
- 🔥 Transforms responses and payloads back and forth to support interchangeability of casing styles (kebab-case -> camelCase -> snake_case -> kebab-case).
|
|
14
15
|
|
|
15
16
|
## Example
|
|
16
17
|
|
|
@@ -48,7 +49,7 @@ const users = await response.json(usersSchema);
|
|
|
48
49
|
- [makeGetApiURL](#makegetapiurl)
|
|
49
50
|
- [mergeHeaders](#mergeheaders)
|
|
50
51
|
- [replaceURLParams](#replaceurlparams)
|
|
51
|
-
|
|
52
|
+
- [Acknowledgements](#acknowledgements)
|
|
52
53
|
|
|
53
54
|
# Installation
|
|
54
55
|
|
|
@@ -274,6 +275,12 @@ const response = await service.get("/users/:id/article/:articleId", {
|
|
|
274
275
|
|
|
275
276
|
// It will call "https://example.com/api/users/2/article/3"
|
|
276
277
|
```
|
|
278
|
+
The `params` object will not type-check if the given object doesn't follow the path structure.
|
|
279
|
+
```ts
|
|
280
|
+
// @ts-expect-error
|
|
281
|
+
service.get("/users/:id", { params: { id: "2", foobar: "foo" } })
|
|
282
|
+
```
|
|
283
|
+
|
|
277
284
|
This is achieved by using the [`replaceURLParams`](#replaceurlparams) function internally.
|
|
278
285
|
|
|
279
286
|
### Trace
|
|
@@ -384,6 +391,34 @@ const text = await response.text(z.string().email())
|
|
|
384
391
|
// ^? string
|
|
385
392
|
```
|
|
386
393
|
|
|
394
|
+
# Payload transformers
|
|
395
|
+
The `make-service` library has a few payload transformers that you can use to transform the request body before sending it or the response body after returning from the server.
|
|
396
|
+
The resulting type will be **properly typed** 🤩.
|
|
397
|
+
```ts
|
|
398
|
+
import { makeService, kebabToCamel, camelToKebab } from 'make-service'
|
|
399
|
+
|
|
400
|
+
const service = makeService("https://example.com/api")
|
|
401
|
+
const response = service.get("/users")
|
|
402
|
+
const users = await response.json(
|
|
403
|
+
z
|
|
404
|
+
.array(z.object({ "first-name": z.string(), contact: z.object({ "home-address": z.string() }) }))
|
|
405
|
+
.transform(kebabToCamel)
|
|
406
|
+
)
|
|
407
|
+
console.log(users)
|
|
408
|
+
// ^? { firstName: string, contact: { homeAddress: string } }[]
|
|
409
|
+
|
|
410
|
+
const body = camelToKebab({ firstName: "John", contact: { homeAddress: "123 Main St" } })
|
|
411
|
+
// ^? { "first-name": string, contact: { "home-address": string } }
|
|
412
|
+
service.patch("/users/:id", { body, params: { id: "1" } })
|
|
413
|
+
```
|
|
414
|
+
The available transformations are:
|
|
415
|
+
- `camelToKebab`: `"someProp" -> "some-prop"`
|
|
416
|
+
- `camelToSnake`: `"someProp" -> "some_prop"`
|
|
417
|
+
- `kebabToCamel`: `"some-prop" -> "someProp"`
|
|
418
|
+
- `kebabToSnake`: `"some-prop" -> "some_prop"`
|
|
419
|
+
- `snakeToCamel`: `"some_prop" -> "someProp"`
|
|
420
|
+
- `snakeToKebab`: `"some_prop" -> "some-prop"`
|
|
421
|
+
|
|
387
422
|
# Other available primitives
|
|
388
423
|
This little library has plenty of other useful functions that you can use to build your own services and interactions with external APIs.
|
|
389
424
|
|
|
@@ -503,5 +538,13 @@ const url = replaceURLParams(
|
|
|
503
538
|
// It will return: "https://example.com/users/2/posts/3"
|
|
504
539
|
```
|
|
505
540
|
|
|
506
|
-
|
|
541
|
+
The params will be **strongly-typed** which means they will be validated against the URL structure and will not type-check if the given object does not match that structure.
|
|
542
|
+
|
|
543
|
+
# Acknowledgements
|
|
544
|
+
This library is part of a code I've been carrying around for a while through many projects.
|
|
545
|
+
|
|
546
|
+
- [croods](https://github.com/seasonedcc/croods) by [@danielweinmann](https://github.com/danielweinmann) - a react data-layer library from pre-ReactQuery/pre-SWR era - gave me ideas and experience dealing with APIs after spending a lot of time in that codebase.
|
|
547
|
+
- [zod](https://zod.dev/) by [@colinhacks](https://github.com/colinhacks) changed my mindset about how to deal with external data.
|
|
548
|
+
- [zod-fetch](https://github.com/mattpocock/zod-fetch) by [@mattpocock](https://github.com/mattpocock) for the inspiration, when I realized I had a similar solution that could be extracted and be available for everyone to use.
|
|
549
|
+
|
|
507
550
|
I really appreciate your feedback and contributions. If you have any questions, feel free to open an issue or contact me on [Twitter](https://twitter.com/gugaguichard).
|
package/dist/index.d.ts
CHANGED
|
@@ -23,26 +23,26 @@ type TypedResponse = Omit<Response, 'json' | 'text'> & {
|
|
|
23
23
|
json: TypedResponseJson;
|
|
24
24
|
text: TypedResponseText;
|
|
25
25
|
};
|
|
26
|
-
type
|
|
26
|
+
type PathParams<T> = T extends string ? ExtractPathParams<T> extends Record<string, unknown> ? ExtractPathParams<T> : Record<string, string> : Record<string, string>;
|
|
27
|
+
type EnhancedRequestInit<T = string> = Omit<RequestInit, 'body' | 'method'> & {
|
|
27
28
|
method?: HTTPMethod | Lowercase<HTTPMethod>;
|
|
28
29
|
body?: JSONValue | BodyInit | null;
|
|
29
30
|
query?: SearchParams;
|
|
30
|
-
params?:
|
|
31
|
+
params?: PathParams<T>;
|
|
31
32
|
trace?: (...args: Parameters<typeof fetch>) => void;
|
|
32
33
|
};
|
|
33
|
-
type ServiceRequestInit = Omit<EnhancedRequestInit
|
|
34
|
+
type ServiceRequestInit<T = string> = Omit<EnhancedRequestInit<T>, 'method'>;
|
|
34
35
|
type HTTPMethod = (typeof HTTP_METHODS)[number];
|
|
35
36
|
type TypedResponseJson = ReturnType<typeof getJson>;
|
|
36
37
|
type TypedResponseText = ReturnType<typeof getText>;
|
|
37
38
|
type Prettify<T> = {
|
|
38
39
|
[K in keyof T]: T[K];
|
|
39
40
|
} & {};
|
|
40
|
-
type
|
|
41
|
-
type PathParams<T extends string> = NoEmpty<T extends `${infer _}:${infer Param}/${infer Rest}` ? Prettify<{
|
|
41
|
+
type ExtractPathParams<T extends string> = T extends `${infer _}:${infer Param}/${infer Rest}` ? Prettify<Omit<{
|
|
42
42
|
[K in Param]: string;
|
|
43
|
-
} &
|
|
43
|
+
} & ExtractPathParams<Rest>, ''>> : T extends `${infer _}:${infer Param}` ? {
|
|
44
44
|
[K in Param]: string;
|
|
45
|
-
} : {}
|
|
45
|
+
} : {};
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
48
|
* It hacks the Response object to add typed json and text methods
|
|
@@ -73,7 +73,7 @@ declare function typedResponse(response: Response): TypedResponse;
|
|
|
73
73
|
* const untyped = await response.json();
|
|
74
74
|
* // ^? unknown
|
|
75
75
|
*/
|
|
76
|
-
declare function enhancedFetch
|
|
76
|
+
declare function enhancedFetch<T extends string | URL>(url: T, requestInit?: EnhancedRequestInit<T>): Promise<TypedResponse>;
|
|
77
77
|
/**
|
|
78
78
|
*
|
|
79
79
|
* @param baseURL the base URL to be fetched in every request
|
|
@@ -85,7 +85,7 @@ declare function enhancedFetch(url: string | URL, requestInit?: EnhancedRequestI
|
|
|
85
85
|
* const users = await response.json(userSchema);
|
|
86
86
|
* // ^? User[]
|
|
87
87
|
*/
|
|
88
|
-
declare function makeFetcher(baseURL: string | URL, baseHeaders?: HeadersInit | (() => HeadersInit | Promise<HeadersInit>)): (path:
|
|
88
|
+
declare function makeFetcher(baseURL: string | URL, baseHeaders?: HeadersInit | (() => HeadersInit | Promise<HeadersInit>)): <T extends string>(path: T, requestInit?: EnhancedRequestInit<T>) => Promise<TypedResponse>;
|
|
89
89
|
/**
|
|
90
90
|
*
|
|
91
91
|
* @param baseURL the base URL to the API
|
|
@@ -97,7 +97,7 @@ declare function makeFetcher(baseURL: string | URL, baseHeaders?: HeadersInit |
|
|
|
97
97
|
* const users = await response.json(userSchema);
|
|
98
98
|
* // ^? User[]
|
|
99
99
|
*/
|
|
100
|
-
declare function makeService(baseURL: string | URL, baseHeaders?: HeadersInit | (() => HeadersInit | Promise<HeadersInit>)): Record<"get" | "post" | "put" | "delete" | "patch" | "options" | "head" | "connect", (path:
|
|
100
|
+
declare function makeService(baseURL: string | URL, baseHeaders?: HeadersInit | (() => HeadersInit | Promise<HeadersInit>)): Record<"get" | "post" | "put" | "delete" | "patch" | "options" | "head" | "connect", <T extends string>(path: T, requestInit?: ServiceRequestInit<T>) => Promise<TypedResponse>>;
|
|
101
101
|
|
|
102
102
|
/**
|
|
103
103
|
* @param url a string or URL to which the query parameters will be added
|
|
@@ -127,6 +127,52 @@ declare function mergeHeaders(...entries: (HeadersInit | [string, undefined][] |
|
|
|
127
127
|
* @param params the params map to be replaced in the url
|
|
128
128
|
* @returns the url with the params replaced and with the same type as the given url
|
|
129
129
|
*/
|
|
130
|
-
declare function replaceURLParams<T extends string | URL>(url:
|
|
130
|
+
declare function replaceURLParams<T extends string | URL>(url: T, params: PathParams<T>): T;
|
|
131
131
|
|
|
132
|
-
|
|
132
|
+
type KebabToCamel<Str> = Str extends `${infer First}-${infer Rest}` ? `${First}${Capitalize<KebabToCamel<Rest>>}` : Str;
|
|
133
|
+
type SnakeToCamel<Str> = Str extends `${infer First}_${infer Rest}` ? `${First}${Capitalize<SnakeToCamel<Rest>>}` : Str;
|
|
134
|
+
type KebabToSnake<Str> = Str extends `${infer First}-${infer Rest}` ? `${First}_${KebabToSnake<Rest>}` : Str;
|
|
135
|
+
type SnakeToKebab<Str> = Str extends `${infer First}_${infer Rest}` ? `${First}-${SnakeToKebab<Rest>}` : Str;
|
|
136
|
+
type HandleFirstChar<Str> = Str extends `${infer First}${infer Rest}` ? `${Lowercase<First>}${Rest}` : Str;
|
|
137
|
+
type CamelToSnakeFn<Str> = Str extends `${infer First}${infer Rest}` ? `${First extends Capitalize<First> ? '_' : ''}${Lowercase<First>}${CamelToSnakeFn<Rest>}` : Str;
|
|
138
|
+
type CamelToSnake<Str> = CamelToSnakeFn<HandleFirstChar<Str>>;
|
|
139
|
+
type CamelToKebabFn<Str> = Str extends `${infer First}${infer Rest}` ? `${First extends Capitalize<First> ? '-' : ''}${Lowercase<First>}${CamelToKebabFn<Rest>}` : Str;
|
|
140
|
+
type CamelToKebab<Str> = CamelToKebabFn<HandleFirstChar<Str>>;
|
|
141
|
+
type DeepKebabToCamel<T> = T extends [any, ...any] ? {
|
|
142
|
+
[I in keyof T]: DeepKebabToCamel<T[I]>;
|
|
143
|
+
} : T extends (infer V)[] ? DeepKebabToCamel<V>[] : {
|
|
144
|
+
[K in keyof T as KebabToCamel<K>]: DeepKebabToCamel<T[K]>;
|
|
145
|
+
};
|
|
146
|
+
declare function kebabToCamel<T>(obj: T): DeepKebabToCamel<T>;
|
|
147
|
+
type DeepSnakeToCamel<T> = T extends [any, ...any] ? {
|
|
148
|
+
[I in keyof T]: DeepSnakeToCamel<T[I]>;
|
|
149
|
+
} : T extends (infer V)[] ? DeepSnakeToCamel<V>[] : {
|
|
150
|
+
[K in keyof T as SnakeToCamel<K>]: DeepSnakeToCamel<T[K]>;
|
|
151
|
+
};
|
|
152
|
+
declare function snakeToCamel<T>(obj: T): DeepSnakeToCamel<T>;
|
|
153
|
+
type DeepCamelToSnake<T> = T extends [any, ...any] ? {
|
|
154
|
+
[I in keyof T]: DeepCamelToSnake<T[I]>;
|
|
155
|
+
} : T extends (infer V)[] ? DeepCamelToSnake<V>[] : {
|
|
156
|
+
[K in keyof T as CamelToSnake<K>]: DeepCamelToSnake<T[K]>;
|
|
157
|
+
};
|
|
158
|
+
declare function camelToSnake<T>(obj: T): DeepCamelToSnake<T>;
|
|
159
|
+
type DeepCamelToKebab<T> = T extends [any, ...any] ? {
|
|
160
|
+
[I in keyof T]: DeepCamelToKebab<T[I]>;
|
|
161
|
+
} : T extends (infer V)[] ? DeepCamelToKebab<V>[] : {
|
|
162
|
+
[K in keyof T as CamelToKebab<K>]: DeepCamelToKebab<T[K]>;
|
|
163
|
+
};
|
|
164
|
+
declare function camelToKebab<T>(obj: T): DeepCamelToKebab<T>;
|
|
165
|
+
type DeepSnakeToKebab<T> = T extends [any, ...any] ? {
|
|
166
|
+
[I in keyof T]: DeepSnakeToKebab<T[I]>;
|
|
167
|
+
} : T extends (infer V)[] ? DeepSnakeToKebab<V>[] : {
|
|
168
|
+
[K in keyof T as SnakeToKebab<K>]: DeepSnakeToKebab<T[K]>;
|
|
169
|
+
};
|
|
170
|
+
declare function snakeToKebab<T>(obj: T): DeepSnakeToKebab<T>;
|
|
171
|
+
type DeepKebabToSnake<T> = T extends [any, ...any] ? {
|
|
172
|
+
[I in keyof T]: DeepKebabToSnake<T[I]>;
|
|
173
|
+
} : T extends (infer V)[] ? DeepKebabToSnake<V>[] : {
|
|
174
|
+
[K in keyof T as KebabToSnake<K>]: DeepKebabToSnake<T[K]>;
|
|
175
|
+
};
|
|
176
|
+
declare function kebabToSnake<T>(obj: T): DeepKebabToSnake<T>;
|
|
177
|
+
|
|
178
|
+
export { CamelToKebab, CamelToSnake, DeepCamelToKebab, DeepCamelToSnake, DeepKebabToCamel, DeepKebabToSnake, DeepSnakeToCamel, DeepSnakeToKebab, EnhancedRequestInit, HTTPMethod, JSONValue, KebabToCamel, KebabToSnake, PathParams, Schema, SearchParams, ServiceRequestInit, SnakeToCamel, SnakeToKebab, TypedResponse, TypedResponseJson, TypedResponseText, addQueryToURL, camelToKebab, camelToSnake, enhancedFetch, ensureStringBody, kebabToCamel, kebabToSnake, makeFetcher, makeGetApiURL, makeService, mergeHeaders, replaceURLParams, snakeToCamel, snakeToKebab, typedResponse };
|
package/dist/index.js
CHANGED
|
@@ -21,13 +21,19 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var src_exports = {};
|
|
22
22
|
__export(src_exports, {
|
|
23
23
|
addQueryToURL: () => addQueryToURL,
|
|
24
|
+
camelToKebab: () => camelToKebab,
|
|
25
|
+
camelToSnake: () => camelToSnake,
|
|
24
26
|
enhancedFetch: () => enhancedFetch,
|
|
25
27
|
ensureStringBody: () => ensureStringBody,
|
|
28
|
+
kebabToCamel: () => kebabToCamel,
|
|
29
|
+
kebabToSnake: () => kebabToSnake,
|
|
26
30
|
makeFetcher: () => makeFetcher,
|
|
27
31
|
makeGetApiURL: () => makeGetApiURL,
|
|
28
32
|
makeService: () => makeService,
|
|
29
33
|
mergeHeaders: () => mergeHeaders,
|
|
30
34
|
replaceURLParams: () => replaceURLParams,
|
|
35
|
+
snakeToCamel: () => snakeToCamel,
|
|
36
|
+
snakeToKebab: () => snakeToKebab,
|
|
31
37
|
typedResponse: () => typedResponse
|
|
32
38
|
});
|
|
33
39
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -172,15 +178,69 @@ function makeService(baseURL, baseHeaders) {
|
|
|
172
178
|
}
|
|
173
179
|
return service;
|
|
174
180
|
}
|
|
181
|
+
|
|
182
|
+
// src/transforms.ts
|
|
183
|
+
function words(str) {
|
|
184
|
+
const matches = str.match(
|
|
185
|
+
/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g
|
|
186
|
+
);
|
|
187
|
+
return matches ? Array.from(matches) : [str];
|
|
188
|
+
}
|
|
189
|
+
function toCamelCase(str) {
|
|
190
|
+
const result = words(str).map((x) => x.slice(0, 1).toUpperCase() + x.slice(1).toLowerCase()).join("");
|
|
191
|
+
return result.slice(0, 1).toLowerCase() + result.slice(1);
|
|
192
|
+
}
|
|
193
|
+
function toKebabCase(str) {
|
|
194
|
+
return words(str).map((x) => x.toLowerCase()).join("-");
|
|
195
|
+
}
|
|
196
|
+
function toSnakeCase(str) {
|
|
197
|
+
return words(str).map((x) => x.toLowerCase()).join("_");
|
|
198
|
+
}
|
|
199
|
+
function deepTransformKeys(obj, transform) {
|
|
200
|
+
if (!["object", "array"].includes(typeOf(obj)))
|
|
201
|
+
return obj;
|
|
202
|
+
if (Array.isArray(obj)) {
|
|
203
|
+
return obj.map((x) => deepTransformKeys(x, transform));
|
|
204
|
+
}
|
|
205
|
+
const res = {};
|
|
206
|
+
for (const key in obj) {
|
|
207
|
+
res[transform(key)] = deepTransformKeys(obj[key], transform);
|
|
208
|
+
}
|
|
209
|
+
return res;
|
|
210
|
+
}
|
|
211
|
+
function kebabToCamel(obj) {
|
|
212
|
+
return deepTransformKeys(obj, toCamelCase);
|
|
213
|
+
}
|
|
214
|
+
function snakeToCamel(obj) {
|
|
215
|
+
return deepTransformKeys(obj, toCamelCase);
|
|
216
|
+
}
|
|
217
|
+
function camelToSnake(obj) {
|
|
218
|
+
return deepTransformKeys(obj, toSnakeCase);
|
|
219
|
+
}
|
|
220
|
+
function camelToKebab(obj) {
|
|
221
|
+
return deepTransformKeys(obj, toKebabCase);
|
|
222
|
+
}
|
|
223
|
+
function snakeToKebab(obj) {
|
|
224
|
+
return deepTransformKeys(obj, toKebabCase);
|
|
225
|
+
}
|
|
226
|
+
function kebabToSnake(obj) {
|
|
227
|
+
return deepTransformKeys(obj, toSnakeCase);
|
|
228
|
+
}
|
|
175
229
|
// Annotate the CommonJS export names for ESM import in node:
|
|
176
230
|
0 && (module.exports = {
|
|
177
231
|
addQueryToURL,
|
|
232
|
+
camelToKebab,
|
|
233
|
+
camelToSnake,
|
|
178
234
|
enhancedFetch,
|
|
179
235
|
ensureStringBody,
|
|
236
|
+
kebabToCamel,
|
|
237
|
+
kebabToSnake,
|
|
180
238
|
makeFetcher,
|
|
181
239
|
makeGetApiURL,
|
|
182
240
|
makeService,
|
|
183
241
|
mergeHeaders,
|
|
184
242
|
replaceURLParams,
|
|
243
|
+
snakeToCamel,
|
|
244
|
+
snakeToKebab,
|
|
185
245
|
typedResponse
|
|
186
246
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -138,14 +138,68 @@ function makeService(baseURL, baseHeaders) {
|
|
|
138
138
|
}
|
|
139
139
|
return service;
|
|
140
140
|
}
|
|
141
|
+
|
|
142
|
+
// src/transforms.ts
|
|
143
|
+
function words(str) {
|
|
144
|
+
const matches = str.match(
|
|
145
|
+
/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g
|
|
146
|
+
);
|
|
147
|
+
return matches ? Array.from(matches) : [str];
|
|
148
|
+
}
|
|
149
|
+
function toCamelCase(str) {
|
|
150
|
+
const result = words(str).map((x) => x.slice(0, 1).toUpperCase() + x.slice(1).toLowerCase()).join("");
|
|
151
|
+
return result.slice(0, 1).toLowerCase() + result.slice(1);
|
|
152
|
+
}
|
|
153
|
+
function toKebabCase(str) {
|
|
154
|
+
return words(str).map((x) => x.toLowerCase()).join("-");
|
|
155
|
+
}
|
|
156
|
+
function toSnakeCase(str) {
|
|
157
|
+
return words(str).map((x) => x.toLowerCase()).join("_");
|
|
158
|
+
}
|
|
159
|
+
function deepTransformKeys(obj, transform) {
|
|
160
|
+
if (!["object", "array"].includes(typeOf(obj)))
|
|
161
|
+
return obj;
|
|
162
|
+
if (Array.isArray(obj)) {
|
|
163
|
+
return obj.map((x) => deepTransformKeys(x, transform));
|
|
164
|
+
}
|
|
165
|
+
const res = {};
|
|
166
|
+
for (const key in obj) {
|
|
167
|
+
res[transform(key)] = deepTransformKeys(obj[key], transform);
|
|
168
|
+
}
|
|
169
|
+
return res;
|
|
170
|
+
}
|
|
171
|
+
function kebabToCamel(obj) {
|
|
172
|
+
return deepTransformKeys(obj, toCamelCase);
|
|
173
|
+
}
|
|
174
|
+
function snakeToCamel(obj) {
|
|
175
|
+
return deepTransformKeys(obj, toCamelCase);
|
|
176
|
+
}
|
|
177
|
+
function camelToSnake(obj) {
|
|
178
|
+
return deepTransformKeys(obj, toSnakeCase);
|
|
179
|
+
}
|
|
180
|
+
function camelToKebab(obj) {
|
|
181
|
+
return deepTransformKeys(obj, toKebabCase);
|
|
182
|
+
}
|
|
183
|
+
function snakeToKebab(obj) {
|
|
184
|
+
return deepTransformKeys(obj, toKebabCase);
|
|
185
|
+
}
|
|
186
|
+
function kebabToSnake(obj) {
|
|
187
|
+
return deepTransformKeys(obj, toSnakeCase);
|
|
188
|
+
}
|
|
141
189
|
export {
|
|
142
190
|
addQueryToURL,
|
|
191
|
+
camelToKebab,
|
|
192
|
+
camelToSnake,
|
|
143
193
|
enhancedFetch,
|
|
144
194
|
ensureStringBody,
|
|
195
|
+
kebabToCamel,
|
|
196
|
+
kebabToSnake,
|
|
145
197
|
makeFetcher,
|
|
146
198
|
makeGetApiURL,
|
|
147
199
|
makeService,
|
|
148
200
|
mergeHeaders,
|
|
149
201
|
replaceURLParams,
|
|
202
|
+
snakeToCamel,
|
|
203
|
+
snakeToKebab,
|
|
150
204
|
typedResponse
|
|
151
205
|
};
|
package/package.json
CHANGED