@empathyco/x-adapter
Advanced tools
Comparing version 8.0.0-alpha.18 to 8.0.0-alpha.19
@@ -67,4 +67,6 @@ import { AnyFunction, DeepPartial, ExtractPath, ExtractPathByType, ExtractType, Primitive } from '@empathyco/x-utils'; | ||
* @param newSchema - The {@link Schema | schema} to be used to extend the original one. | ||
* Both schema's Target and Source can be unique or also be extending from another one. | ||
* @returns The {@link Schema | schema} created. | ||
*/ | ||
$extends<NewSource extends Source, NewTarget extends Target>(newSchema: DeepPartial<Schema<Source & NewSource, Target>> & Schema<Source & NewSource, Omit<NewTarget, keyof Target>>): MutableSchema<Source & NewSource, Target & NewTarget>; | ||
$extends<NewSource, NewTarget = {}>(newSchema: DeepPartial<Schema<Source & NewSource, Target>> & Schema<Source & NewSource, NewTarget>): MutableSchema<Source & NewSource, Target & NewTarget>; | ||
@@ -71,0 +73,0 @@ /** |
{ | ||
"name": "@empathyco/x-adapter", | ||
"version": "8.0.0-alpha.18", | ||
"version": "8.0.0-alpha.19", | ||
"description": "A utils library to create a client for any API", | ||
@@ -53,3 +53,3 @@ "author": "Empathy Systems Corporation S.L.", | ||
}, | ||
"gitHead": "9a571e850e671c1227d17db9b574579a8a8464ae" | ||
"gitHead": "b5640ccccd296584a4775a8db625f9039b6025e9" | ||
} |
276
README.md
@@ -77,3 +77,3 @@ # x-adapter | ||
```ts | ||
// API data models | ||
// API models | ||
interface ApiRequest { | ||
@@ -93,3 +93,3 @@ q?: string; | ||
// App's data models | ||
// App models | ||
interface AppSearchRequest { | ||
@@ -248,3 +248,3 @@ query: string; | ||
```ts | ||
// API data models | ||
// API models | ||
interface ApiUserRequest { | ||
@@ -262,3 +262,3 @@ q: string; | ||
// App's data models | ||
// App models | ||
interface AppUserRequest { | ||
@@ -314,3 +314,3 @@ query: string; | ||
```ts | ||
// API data models | ||
// API models | ||
interface ApiRequest { | ||
@@ -336,3 +336,3 @@ q: string; | ||
// APP data models | ||
// App models | ||
interface AppRequest { | ||
@@ -417,21 +417,224 @@ query: string; | ||
This feature lets you have some default mappers, and modify or extend them for some concrete | ||
implementations. To do so, you should use the `createMutableSchema` helper function, and pass as a | ||
parameter the schema you want to make mutable. | ||
This feature lets you have some default schemas, and modify or extend them for some concrete | ||
implementations. To do so, you can use the `createMutableSchema` function, passing a `Source` and | ||
`Target` type parameters to map your models. This function will return a `MutableSchema` that apart | ||
from the mapping information will also contain some methods to create new schemas or modify the | ||
current one. | ||
In the example below we will create a `MutableSchema` to have a default object that will be reused | ||
for different endpoint calls. | ||
###### Types definition and MutableSchema | ||
```ts | ||
// TODO: Creating a mutable schema | ||
// API models | ||
export interface ApiBaseObject { | ||
id: number; | ||
body: string; | ||
} | ||
// APP models | ||
export interface AppBaseObject { | ||
id: string; | ||
text: string; | ||
} | ||
// Mutable Schema | ||
export const baseObjectSchema = createMutableSchema<ApiBaseObject, AppBaseObject>({ | ||
id: ({ id }) => id.toString(), | ||
text: 'body' | ||
}); | ||
``` | ||
Once you have your mutable schema, you can use its available methods to obtain a new schema based on | ||
it: | ||
Once we have the `MutableSchema`, we can use the following methods to fit our different APIs needs: | ||
- `replace`: Replaces completely the original Schema. | ||
- `override`: Merges the original schema with the new one. | ||
- `extends`: Creates a new Schema based on the original one. The original remains unchanged. | ||
- `$extends`: Creates a new `MutableSchema` based on the original one. The original remains | ||
unchanged. This can be useful if we need to create a new `EndpointAdapter` with models based on | ||
another API. | ||
- `$override`: Merges/modifies the original `MutableSchema` partially, so the change will affect to | ||
all the `EndpointAdapter`(s) that are using it. It can be used to change the structure of our | ||
request/response mappers, or to add them new fields. Useful for clients with few differences in | ||
their APIs. For example, you can create a library with a default adapter and use this library from | ||
the customer projects overriding only the needed field (e.g. retrieve the images from `pictures` | ||
instead of `images` in a products API). | ||
- `$replace`: Replaces completely the original `MutableSchema` by a new one, it won't exist anymore. | ||
The change will affect to all the `EndpointAdapter`(s) that were using it. Useful for clients with | ||
a completely different API/response to the standard you have been working with. | ||
###### Extend a MutableSchema to reuse it in two different endpoints with more fields | ||
```ts | ||
// TODO: Mutable schema's methods: '$replace', '$override', '$extends' | ||
import { ApiBaseObject, AppBaseObject, baseObjectSchema } from '@/base-types'; | ||
// Api models | ||
interface ApiPost extends ApiBaseObject { | ||
title: string; | ||
} | ||
interface ApiPostsResponse { | ||
posts: ApiPost[]; | ||
} | ||
interface ApiComment extends ApiBaseObject { | ||
postId: number; | ||
} | ||
interface ApiCommentsResponse { | ||
comments: ApiComment[]; | ||
} | ||
// App models | ||
interface AppPost extends AppBaseObject { | ||
postTitle: string; | ||
} | ||
interface AppPostsResponse { | ||
posts: AppPost[]; | ||
} | ||
interface AppComment extends AppBaseObject { | ||
postId: number; | ||
} | ||
interface AppCommentsResponse { | ||
comments: AppComment[]; | ||
} | ||
// Extend for posts endpoint | ||
const postSchema = baseObjectSchema.$extends<ApiPost, AppPost>({ | ||
postTitle: 'title' | ||
}); | ||
const postsResponse = schemaMapperFactory<ApiPostsResponse, AppPostsResponse>({ | ||
posts: { | ||
$subSchema: postSchema, | ||
$path: 'posts' | ||
} | ||
}); | ||
export const searchPosts = endpointAdapterFactory({ | ||
endpoint: 'https://dummyjson.com/posts', | ||
responseMapper: postsResponse | ||
}); | ||
// Extend for comments endpoint | ||
const commentSchema = baseObjectSchema.$extends<ApiComment, AppComment>({ | ||
postId: 'postId' | ||
}); | ||
const commentsResponse = schemaMapperFactory<ApiCommentsResponse, AppCommentsResponse>({ | ||
comments: { | ||
$subSchema: commentSchema, | ||
$path: 'comments' | ||
} | ||
}); | ||
export const searchComments = endpointAdapterFactory({ | ||
endpoint: 'https://dummyjson.com/comments', | ||
responseMapper: commentsResponse | ||
}); | ||
``` | ||
###### Override a MutableSchema to add more fields | ||
As said above, the suitable context for using the `override` method would be a project with an API | ||
that doesn't differ too much against the one used in our "base project". That means we can reuse | ||
most of the types and schemas definitions, so we would only add a few new fields from the new API. | ||
```ts | ||
import { ApiBaseObject, AppBaseObject, baseObjectSchema } from '@/base-types'; | ||
// Api models | ||
interface ApiTodo { | ||
completed: boolean; | ||
todo: string; | ||
userId: number; | ||
} | ||
interface ApiTodosResponse { | ||
todos: ApiBaseObject[]; | ||
} | ||
// App models | ||
interface AppTodo { | ||
completed: boolean; | ||
text: string; | ||
userId: string; | ||
} | ||
interface AppTodosResponse { | ||
todos: AppBaseObject[]; | ||
} | ||
// Response mapper | ||
const todosResponse = schemaMapperFactory<ApiTodosResponse, AppTodosResponse>({ | ||
todos: { | ||
$subSchema: baseObjectSchema, | ||
$path: 'todos' | ||
} | ||
}); | ||
// Endpoint Adapter | ||
export const searchTodos = endpointAdapterFactory({ | ||
endpoint: 'https://dummyjson.com/todos', | ||
responseMapper: todosResponse | ||
}); | ||
// Override the original Schema. The Schema changes to map: 'id', 'completed', 'text' and 'userId'' | ||
baseObjectSchema.$override<ApiTodo, AppTodo>({ | ||
completed: 'completed', | ||
text: 'todo', | ||
userId: ({ userId }) => userId.toString() | ||
}); | ||
``` | ||
###### Replace a MutableSchema to completely change it | ||
In this case we are facing too many differences between API responses. We don't need to write a | ||
whole adapter from scratch, as there are other parts of the API that aren't changing so much, but we | ||
should replace some `endpointAdapter`'s schemas. | ||
```ts | ||
import { ApiBaseObject, AppBaseObject, baseObjectSchema } from '@/base-types'; | ||
// Api models | ||
interface ApiQuote { | ||
id: number; | ||
quote: string; | ||
author: string; | ||
} | ||
interface ApiQuotesResponse { | ||
quotes: ApiBaseObject[]; | ||
} | ||
// App models | ||
interface AppQuote { | ||
quoteId: string; | ||
quote: string; | ||
author: string; | ||
} | ||
interface AppQuotesResponse { | ||
quotes: AppBaseObject[]; | ||
} | ||
// Response mapper | ||
const quotesResponse = schemaMapperFactory<ApiQuotesResponse, AppQuotesResponse>({ | ||
quotes: { | ||
$subSchema: baseObjectSchema, | ||
$path: 'quotes' | ||
} | ||
}); | ||
// Endpoint Adapter | ||
export const searchQuotes = endpointAdapterFactory({ | ||
endpoint: 'https://dummyjson.com/quotes', | ||
responseMapper: quotesResponse | ||
}); | ||
// Replace the original Schema | ||
baseObjectSchema.$replace<ApiQuote, AppQuote>({ | ||
quoteId: ({ id }) => id.toString(), | ||
quote: 'quote', | ||
author: 'author' | ||
}); | ||
``` | ||
<br> | ||
@@ -441,8 +644,33 @@ | ||
You can check the | ||
[x-platform-adapter](https://github.com/empathyco/x/tree/main/packages/x-adapter-platform) library. | ||
You will find a sample implementation of the `x-adapter` library based on the | ||
[Search Platform API](https://docs.empathy.co/develop-empathy-platform/api-reference/search-api.html), | ||
and also some guidance on how to extend it for your needs. | ||
Imagine you have a new setup and that you can reuse most of the stuff you have developed. Probably | ||
you have built an adapter instance as a configuration object that contains all of your | ||
`EndpointAdapter` calls, so you only need to extend the endpoint you need to change. | ||
```ts | ||
export const adapter = { | ||
searchItem: getItemById, | ||
searchList: searchComments | ||
// Any endpoint adapter you are using to communicate with your API | ||
}; | ||
adapter.searchList = searchComments.extends({ | ||
endpoint: 'https://dummyjson.com/comments/', | ||
defaultRequestOptions: { | ||
// If you need to send an id, a header... | ||
}, | ||
defaultRequestOptions: { | ||
parameters: { | ||
limit: 10, | ||
skip: 10 | ||
} | ||
} | ||
}); | ||
``` | ||
For further detail, you can check the | ||
[x-platform-adapter](https://github.com/empathyco/x/tree/main/packages/x-adapter-platform) package. | ||
It is a whole adapter implementation using this `x-adapter` library to suit the | ||
[Search Platform API](https://docs.empathy.co/develop-empathy-platform/api-reference/search-api.html) | ||
needs. | ||
## Test | ||
@@ -463,5 +691,5 @@ | ||
To start contributing to the project, please take a look to | ||
our **[Contributing Guide](https://github.com/empathyco/x/blob/main/.github/CONTRIBUTING.md).** Take | ||
in account that `x-adapter` is developed using [Typescript](https://www.typescriptlang.org/), so we | ||
To start contributing to the project, please take a look to our | ||
**[Contributing Guide](https://github.com/empathyco/x/blob/main/.github/CONTRIBUTING.md).** Take in | ||
account that `x-adapter` is developed using [Typescript](https://www.typescriptlang.org/), so we | ||
recommend you check it out. | ||
@@ -468,0 +696,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
182348
1597
691