@snail-js/api 0.1.1 → 0.1.2

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 CHANGED
@@ -5,7 +5,8 @@
5
5
  ## 项目介绍
6
6
 
7
7
  - 基于 Axios 二次封装
8
- - 提供请求基本实例`Snail`,请求实例`Api`
8
+ - 使用`reflect-metadata`创建和处理元数据
9
+ - 提供装饰器方式定义请求,基本实例`Snail`,请求实例`Api`
9
10
 
10
11
  ## 安装
11
12
 
@@ -13,134 +14,298 @@
13
14
 
14
15
  ## 使用
15
16
 
16
- 1. 创建`Snail`实例
17
+ 1. 请开启`TypeScript`相关装饰器配置
18
+
19
+ ```json
20
+ // tsconfig.json
21
+ {
22
+ "module": "ESNext",
23
+ // 模块解析策略
24
+ "moduleResolution": "node",
25
+ "baseUrl": ".",
26
+ // target 必须大于ES6
27
+ "target": "ESNext",
28
+ // lib 需要包含大于ES6的ES版本
29
+ "lib": ["ESNext", "DOM"],
30
+ // 包含reflect-metadata类型
31
+ "types": ["reflect-metadata"],
32
+ "emitDecoratorMetadata": true,
33
+ "experimentalDecorators": true,
34
+
35
+ "skipLibCheck": true,
36
+ "strictNullChecks": false
37
+ }
38
+ ```
39
+
40
+ 2. 创建`Snail`后端基本配置实例
17
41
 
18
42
  ```typescript
19
- import { Snail, SnailConfig, VersioningType, CacheType } from "@snail-js/api";
20
- import { AxiosRequestConfig } from "axios";
21
-
22
- const options:SnailConfig = {
23
- baseUrl:'api',
24
- Versioning: {
25
- type: VersioningType.Uri,
26
- prefix: "v",
27
- defaultVersion: "0.1.0",
28
- },
43
+ // service.ts
44
+ import { Snail, Server } from "@snail-js/api";
45
+
46
+ @Server({
47
+ baseURL: "/api",
29
48
  timeout: 5000,
30
- requestInterceptors: {
31
- onFulfilled(config: AxiosRequestConfig) {
32
- console.log("requestInterceptors:", config.url);
33
- return config
34
- },
35
- },
36
- responseInterceptors: {
37
- onFulfilled(response) {
38
- console.log(response);
39
- return response
40
- },
41
- onRejected(error) {
42
- console.log(error);
43
- },
44
- },
45
- CacheManage: {
46
- type: CacheType.LocalStorage,
47
- ttl: 60, //缓存过期时间
48
- },
49
- }
50
- export SnailInstance = new Snail(options)
49
+ })
50
+ class BackEnd extends Snail {}
51
+ export const Service = new BackEnd();
51
52
  ```
52
53
 
53
- 2. 创建请求方法实例
54
+ 3. 创建请求实例
54
55
 
55
56
  ```typescript
56
- import { ApiConfig, RequestPipe } from "@snail-js/api";
57
-
58
- import { SnailInstance } from "./snail";
59
- const pipe: RequestPipe = (input) => {
60
- const { data, headers } = input;
61
- const newHeaders = {
62
- ...headers,
63
- pipe: "RequestPipe",
64
- };
65
- return {
66
- data,
67
- headers: newHeaders,
68
- };
69
- };
57
+ // user.ts
58
+ import { Api, Get, Post, Params, Data } from "@snail-js/api";
70
59
 
71
- const transform = (data: any) => {
72
- return {
73
- ...data,
74
- transform: "transform",
75
- };
76
- };
77
-
78
- const options: ApiConfig = {
79
- transform,
80
- version: "0.3.0", //会覆盖defaultVersion
81
- };
82
- const Api = Snail.Get("test", options);
83
- Api.use(pipe);
84
- export const testApi = Api;
85
-
86
- // 配置了hitSource,Api2请求成功时会使Api的缓存失效
87
- // 当你更新了数据时,get请求的缓存失效,会发起请求,这很有用
88
- const Api2 = Snail.Post("test",{hitSource:Api})
89
- export const testApi2 = Api2
60
+ import { Service } from "./service";
61
+
62
+ @Api("user")
63
+ class UserApi {
64
+ @Get()
65
+ get(@Params("id") id: string) {}
66
+
67
+ @Post()
68
+ create(@Data() user: User) {}
69
+ }
70
+ // 创建并导出api
71
+ export const userApi = Service.createApi(UserApi);
90
72
  ```
91
73
 
92
- 3. 使用请求
74
+ 3. 发送请求
93
75
 
94
76
  ```typescript
95
- import { testApi } from "./testApi";
96
- // 发送时也可临时更改version,便于测试
97
- const res = await TestApi.send({ version: "0.1.0" });
98
- const { Catch, error, data } = res;
99
- if (error == null) {
100
- console.log("Snail-Api:", data);
101
- }
102
- Catch((error) => {
103
- console.log(error);
104
- });
105
- // success {error:null,data}
106
- // error {error,data:null} 附带的相关错误数据会保存在error.cause中
107
- // 某些服务端标记的code !=0的请求,会被捕获为错误,而且携带数据
77
+ import { userApi } from "./user";
78
+
79
+ const res = await userApi.get("1");
80
+ const { error, data } = res;
81
+ if (error !== null) {
82
+ console.log(data);
83
+ }
108
84
  ```
109
85
 
110
- ### Snail 配置
86
+ ### Server 配置
111
87
 
112
- - `baseUrl`:同`Axios`
88
+ - `baseUrl`:同`Axios`,使用`vite.proxy`时,请使用`\`开头,直接跨域请求请填写完整地址
113
89
  - `Versioning`:版本管理器
114
- - type:管理器类型,enum:Uri,Head,Query,Custom
115
- - prifix:前缀
116
- - defaultVersion:全局默认版本
90
+ - type:管理器类型,enum:Uri,Head,Query,Custom
91
+ - prifix:前缀
92
+ - defaultVersion:全局默认版本
117
93
  - timenout:全局超时时间,会被 Api 的 timeout 值覆盖
118
- - requestInterceptors:全局请求拦截器
119
- - responseInterceptors:全局响应拦截器
120
94
  - CacheManage:缓存管理器
121
- - type:缓存管理器类型,CacheType,enum:localStorage,IndexDB,Memory
122
- - ttl: 缓存过期时间
95
+ - type:缓存管理器类型,CacheType,enum:localStorage,IndexDB,Memory
96
+ - ttl: 缓存过期时间
123
97
 
124
98
  ## Api 配置
125
99
 
126
- - name?: 请求名称,用于hitSource来使缓存失效
127
- - timeout?: 请求超时时间;会覆盖`SnailConfig.timeout`
128
- - version?: 请求版本,会覆盖`SnailConfig.Versioning.defaultVersion`;
129
- - transform?: `(data: any) => T`;响应数据转换器,用于对返回数据进行转换操作
130
- - headers?: Record<string, string>;
131
- - params?: Record<string, string>;
132
- - hitSource?: string | Api;失效源
100
+ - url?: api 请求端点,与 Server 中的`baseUrl`拼接请求地址,,不要使用`/`开头
101
+ - timeout?: 请求超时时间;会覆盖`Server.timeout`
102
+ - version?: 请求版本,会覆盖`Server.Versioning.defaultVersion`;
103
+
104
+ ## 请求方法装饰器
105
+
106
+ - 提供 axios 的全部请求方法`Get,Post,Head,Put,Delete,Patch,Options`
107
+ - path?: string; 请求端点路径,与`baseUrl,api.url`共同拼接组成最终请求路径,不要使用`/`开头
108
+
109
+ ## 参数装饰器
110
+
111
+ ### 查询参数 `@Params`
112
+
113
+ - `@Params(key?:string)`
114
+
115
+ - 单个参数使用
116
+
117
+ ```typescript
118
+ @Api("user")
119
+ class UserApi {
120
+ @Get()
121
+ get(@Params("id") id: string, @Params("sign") sign: string) {}
122
+ }
123
+ ```
124
+
125
+ > 传入 key,标记单个查询参数,拼接到请求`?k1=v1&k2=v2`
126
+
127
+ - 对象参数使用
128
+
129
+ ```typescript
130
+ class QueryParams {
131
+ id: string;
132
+ sign: string;
133
+ }
134
+
135
+ @Api("user")
136
+ class UserApi {
137
+ @Get()
138
+ get(@Params() params: QueryParams) {}
139
+ }
140
+ ```
141
+
142
+ > 不传入 key,会被标记为对象类型查询参数;也能自动拼接到请求
143
+
144
+ - 混合使用
145
+
146
+ ```typescript
147
+ class QueryParams {
148
+ id: string;
149
+ sign: string;
150
+ }
151
+
152
+ @Api("user")
153
+ class UserApi {
154
+ @Get()
155
+ get(@Params() params: QueryParams, @Params("a") a: number) {}
156
+ }
157
+ ```
158
+
159
+ ### 请求数据
160
+
161
+ - `@Data(key?:string)`
162
+ - 使用方式和`@Params`相同,也支持混合使用
133
163
 
134
- ## send参数配置
164
+ ## 策略装饰器`@UseStrategy`
165
+
166
+ - `@UseStrategy(Strategy[])`
167
+
168
+ ### 请求策略
169
+
170
+ - 在请求发送前执行,后面的策略返回结果会覆盖前面的策略
171
+ - 必须将处理后的 request 返回
172
+
173
+ ```typescript
174
+ class CustomStrategy extends Strategy {
175
+ applyRequest(request: AxiosRequestConfig) {
176
+ request.headers["Access-Token"] = "abcde";
177
+ return request;
178
+ }
179
+ }
135
180
 
136
- - params?: Record<string, string>; 请求Query参数
137
- - data?: RequestBody; 请求体数据
138
- - version?: string; 请求版本,如设置,会临时使用此版本运行版本管理器
181
+ // 用在Snail,全局的请求策略
182
+
183
+ @Server({
184
+ baseURL: "/api",
185
+ timeout: 5000,
186
+ })
187
+ @UseStrategy(new CustomStrategy())
188
+ class BackEnd extends Snail<ShanheResponse> {}
189
+ export const Service = new BackEnd();
190
+
191
+ // 用在Api, 当Api下的方法请求时生效
192
+ @Api("test")
193
+ @UseStrategy(new CustomStrategy())
194
+ class Test {}
195
+
196
+ // 用在方法,此方法请求时生效
197
+ @Api("test")
198
+ @UseStrategy(new CustomStrategy())
199
+ class Test {
200
+ @Get()
201
+ @UseStrategy(new CustomStrategy())
202
+ get() {}
203
+ }
204
+ ```
205
+
206
+ ### 响应策略
207
+
208
+ - 在收到服务器响应后执行
209
+ - 必须将处理后的 response 返回
210
+
211
+ ```typescript
212
+ // 如何定义
213
+ class CustomStrategy extends Strategy {
214
+ applyResponse(response: AxiosResponse) {
215
+ const { status } = response;
216
+ if (status == 200) {
217
+ // do something
218
+ }
219
+ return response;
220
+ }
221
+ }
222
+ ```
223
+
224
+ ## 版本管理装饰器`@Versioning`和`@Version`
225
+
226
+ ### 版本管理器`@Versioning(VersioningOption)`
227
+
228
+ - 全局管理版本
229
+
230
+ ```typescript
231
+ @Server({
232
+ baseURL: "/api",
233
+ timeout: 5000,
234
+ })
235
+ @Versioning({
236
+ type: VersioningType.Header,
237
+ defaultVersion: "0.1.0",
238
+ })
239
+ class BackEnd extends Snail<ShanheResponse> {}
240
+
241
+ export const Service = new BackEnd();
242
+ ```
243
+
244
+ #### `VersioningOption`类型
245
+
246
+ ```typescript
247
+ export enum VersioningType {
248
+ Uri,
249
+ Header,
250
+ Query,
251
+ Custom,
252
+ }
253
+
254
+ interface VersioningCommonOption {
255
+ defaultVersion: string;
256
+ }
257
+
258
+ export interface VersioningUriOption extends VersioningCommonOption {
259
+ type: VersioningType.Uri;
260
+ prefix?: string;
261
+ }
262
+
263
+ export interface VersioningHeaderOption extends VersioningCommonOption {
264
+ type: VersioningType.Header;
265
+ header?: string;
266
+ }
267
+
268
+ export interface VersioningQueryOption extends VersioningCommonOption {
269
+ type: VersioningType.Query;
270
+ key?: string;
271
+ }
272
+
273
+ export interface VersioningCustomOption extends VersioningCommonOption {
274
+ type: VersioningType.Custom;
275
+ extractor: (requestOptions: unknown) => {
276
+ url: string;
277
+ headers: Record<string, any>;
278
+ };
279
+ }
280
+
281
+ export type VersioningOption =
282
+ | VersioningUriOption
283
+ | VersioningHeaderOption
284
+ | VersioningQueryOption
285
+ | VersioningCustomOption;
286
+ ```
287
+
288
+ ### 临时版本修改器`@Version`
289
+
290
+ ```typescript
291
+ @Api("test")
292
+ class Test {
293
+ @Get("HelloWorld")
294
+ @Version("0.2.0")
295
+ test() {}
296
+ }
297
+ ```
298
+
299
+ > 临时改变 api 版本,便于测试
300
+
301
+ ### 缓存装饰器`@Cache`
302
+ - 待测试,测试后发布文档
139
303
 
140
304
  ### 代码仓库
305
+
141
306
  - ![Static Badge](https://img.shields.io/badge/snail-js?style=flat&label=gitee&labelColor=F56C6C&link=https%3A%2F%2Fgitee.com%2Flimich%2Fsnail)
142
307
  - ![Static Badge](https://img.shields.io/badge/snail-js?style=flat&label=github&labelColor=F56C6C&link=https%3A%2F%2Fgihub.com%2Flimingchang%2Fsnail)
143
308
 
144
-
145
309
  ### 作者
146
- - mc.lee
310
+
311
+ - mc.lee
@@ -2,4 +2,4 @@ import MemoryCache from "./memoryCache";
2
2
  import LocalStorageCache from "./localstorageCache";
3
3
  import IndexDBCache from "./indexDBCache";
4
4
  import { CacheType } from "../typings";
5
- export declare function createCache(type: CacheType, ttl: number): MemoryCache | LocalStorageCache | IndexDBCache | undefined;
5
+ export declare function createCache(type: CacheType, ttl: number): LocalStorageCache | IndexDBCache | MemoryCache | undefined;
@@ -1,2 +1 @@
1
- export * from './api';
2
1
  export * from './snail';
@@ -1,20 +1,20 @@
1
- import { AxiosInstance } from "axios";
2
- import { Api } from "./api";
3
- import { SnailConfig, VersioningConfig, ApiConfig, CacheStorage } from "../typings";
4
- export declare class Snail {
5
- axiosInstance: AxiosInstance;
6
- baseURL: string;
7
- versioning?: VersioningConfig;
8
- options: SnailConfig;
9
- cacheStorage?: CacheStorage;
10
- cacheSource: Api[];
11
- constructor(options: SnailConfig);
12
- Get<T = any, E = any, D = any>(url: string, options?: ApiConfig): Api<T, E, D>;
13
- Post<T = any, E = any, D = any>(url: string, options?: ApiConfig): Api<T, E, D>;
14
- Put<T = any, E = any, D = any>(url: string, options?: ApiConfig): Api<T, E, D>;
15
- Delete<T = any, E = any, D = any>(url: string, options?: ApiConfig): Api<T, E, D>;
16
- Patch<T = any, E = any, D = any>(url: string, options?: ApiConfig): Api<T, E, D>;
17
- Head<T = any, E = any, D = any>(url: string, options?: ApiConfig): Api<T, E, D>;
18
- Options<T = any, E = any, D = any>(url: string, options?: ApiConfig): Api<T, E, D>;
1
+ import "reflect-metadata";
2
+ import { Strategy, ApiProxy, ResponseData } from "../typings";
3
+ export declare class Snail<R extends {
4
+ data: any;
5
+ } = ResponseData> {
6
+ private axiosInstance;
7
+ private strategies;
8
+ private cacheStorage?;
9
+ private version?;
10
+ registerStrategy(strategy: Strategy): void;
11
+ createApi<T extends object>(constructor: new () => T): ApiProxy<T, R>;
12
+ private buildRequestArgs;
13
+ private getStrategies;
14
+ private applyStrategies;
15
+ private applyVersion;
16
+ private applyCache;
17
+ private getCacheConfig;
18
+ private handleResponse;
19
+ private handleError;
19
20
  }
20
- export declare const createSnail: (option: SnailConfig) => Snail;
@@ -0,0 +1,12 @@
1
+ import "reflect-metadata";
2
+ import { ApiConfig } from "../typings";
3
+ export declare const METHOD_KEY = "SNAIL_METHOD_KEY";
4
+ export declare const API_CONFIG_KEY = "SNAIL_API_CONFIG_KEY";
5
+ export declare const Api: (url?: string, config?: ApiConfig) => ClassDecorator;
6
+ export declare const Get: (path?: string) => (target: any, propertyKey: string | symbol) => void;
7
+ export declare const Post: (path?: string) => (target: any, propertyKey: string | symbol) => void;
8
+ export declare const Put: (path?: string) => (target: any, propertyKey: string | symbol) => void;
9
+ export declare const Delete: (path?: string) => (target: any, propertyKey: string | symbol) => void;
10
+ export declare const Patch: (path?: string) => (target: any, propertyKey: string | symbol) => void;
11
+ export declare const Options: (path?: string) => (target: any, propertyKey: string | symbol) => void;
12
+ export declare const Head: (path?: string) => (target: any, propertyKey: string | symbol) => void;
@@ -0,0 +1,4 @@
1
+ import "reflect-metadata";
2
+ import { CacheManagementOption } from '../typings';
3
+ export declare const CACHE_KEY = "SNALI_CACHE_KEY";
4
+ export declare const Cache: (options: CacheManagementOption) => (target: any, propertyKey?: string) => void;
@@ -0,0 +1,4 @@
1
+ import "reflect-metadata";
2
+ export declare const REQUEST_ARGS_KEY: unique symbol;
3
+ export declare const Params: (key?: string) => (target: any, propertyKey: string | symbol, parameterIndex: number) => void;
4
+ export declare const Data: () => (target: any, propertyKey: string | symbol, parameterIndex: number) => void;
@@ -0,0 +1,4 @@
1
+ import "reflect-metadata";
2
+ import { SnailOption } from "../typings";
3
+ export declare const SERVER_CONFIG_KEY = "SANIL_SERVER_CONFIG_KEY";
4
+ export declare const Server: (config: SnailOption) => (target: any) => void;
@@ -0,0 +1,4 @@
1
+ import "reflect-metadata";
2
+ import { Strategy } from "../typings";
3
+ export declare const STRATEGY_KEY: unique symbol;
4
+ export declare const UseStrategy: (...strategies: Strategy[]) => (target: any, propertyKey?: string) => void;
@@ -0,0 +1,6 @@
1
+ import "reflect-metadata";
2
+ import { VersioningOption } from "../typings";
3
+ export declare const VERSIONING_KEY: unique symbol;
4
+ export declare const VERSION_KEY: unique symbol;
5
+ export declare const Versioning: (options: VersioningOption) => (target: any) => void;
6
+ export declare const Version: (version: string) => (target: any, propertyKey: string) => void;
package/dist/index.d.ts CHANGED
@@ -1,3 +1,9 @@
1
1
  export * from "./core";
2
+ export * from "./decorators/server";
3
+ export * from "./decorators/api";
4
+ export * from "./decorators/cache";
5
+ export * from "./decorators/param";
6
+ export * from "./decorators/strategy";
7
+ export * from "./decorators/versioning";
2
8
  export * from "./typings";
3
9
  export * from "./utils";