Skip to content

Commit

Permalink
feat: add http client component (#1098)
Browse files Browse the repository at this point in the history
  • Loading branch information
czy88840616 authored Jul 31, 2021
1 parent b9d73f0 commit 4e2f90a
Show file tree
Hide file tree
Showing 18 changed files with 356 additions and 17 deletions.
12 changes: 12 additions & 0 deletions packages/axios/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# midway axios component

[![Package Quality](http://npm.packagequality.com/shield/midway-core.svg)](http://packagequality.com/#?package=midway-core)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/midwayjs/midway/pulls)

this is a sub package for midway.

Document: [https://midwayjs.org/midway](https://midwayjs.org/midway)

## License

[MIT]((http://github.com/midwayjs/midway/blob/master/LICENSE))
7 changes: 7 additions & 0 deletions packages/axios/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testPathIgnorePatterns: ['<rootDir>/test/fixtures'],
coveragePathIgnorePatterns: ['<rootDir>/test/'],
setupFilesAfterEnv: ['./jest.setup.js'],
};
2 changes: 2 additions & 0 deletions packages/axios/jest.setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
process.env.MIDWAY_TS_MODE = 'true';
jest.setTimeout(30000);
36 changes: 36 additions & 0 deletions packages/axios/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "@midwayjs/axios",
"description": "midway http client with axios",
"version": "2.11.0",
"main": "dist/index",
"typings": "dist/index.d.ts",
"files": [
"dist/**/*.js",
"dist/**/*.d.ts"
],
"devDependencies": {
"@midwayjs/core": "^2.11.0",
"@midwayjs/decorator": "^2.11.0",
"@midwayjs/mock": "^2.11.0"
},
"dependencies": {
"axios": "^0.21.1"
},
"keywords": [
"http client",
"axios"
],
"author": "czy88840616 <czy88840616@gmail.com>",
"license": "MIT",
"scripts": {
"build": "tsc",
"test": "node --require=ts-node/register ../../node_modules/.bin/jest",
"cov": "node --require=ts-node/register ../../node_modules/.bin/jest --coverage --forceExit",
"ci": "npm run test",
"lint": "mwts check"
},
"repository": {
"type": "git",
"url": "https://github.com/midwayjs/midway.git"
}
}
1 change: 1 addition & 0 deletions packages/axios/src/config.default.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const axios = {};
13 changes: 13 additions & 0 deletions packages/axios/src/configuration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Configuration } from '@midwayjs/decorator';
import { join } from 'path';
import { HttpService } from './servicManager';

@Configuration({
namespace: 'axios',
importConfigs: [join(__dirname, './config.default')],
})
export class AutoConfiguration {
async onReady(container) {
await container.getAsync(HttpService);
}
}
3 changes: 3 additions & 0 deletions packages/axios/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { AutoConfiguration as Configuration } from './configuration';
export * from './interface';
export * from './servicManager';
49 changes: 49 additions & 0 deletions packages/axios/src/interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import {
AxiosRequestConfig,
AxiosResponse,
AxiosInterceptorManager,
} from 'axios';

export const AXIOS_INSTANCE_KEY = 'axios:instance';

export interface AxiosHttpService {
interceptors: {
request: AxiosInterceptorManager<AxiosRequestConfig>;
response: AxiosInterceptorManager<AxiosResponse>;
};
getUri(config?: AxiosRequestConfig): string;
request<T = any, R = AxiosResponse<T>>(
config: AxiosRequestConfig
): Promise<R>;
get<T = any, R = AxiosResponse<T>>(
url: string,
config?: AxiosRequestConfig
): Promise<R>;
delete<T = any, R = AxiosResponse<T>>(
url: string,
config?: AxiosRequestConfig
): Promise<R>;
head<T = any, R = AxiosResponse<T>>(
url: string,
config?: AxiosRequestConfig
): Promise<R>;
options<T = any, R = AxiosResponse<T>>(
url: string,
config?: AxiosRequestConfig
): Promise<R>;
post<T = any, R = AxiosResponse<T>>(
url: string,
data?: any,
config?: AxiosRequestConfig
): Promise<R>;
put<T = any, R = AxiosResponse<T>>(
url: string,
data?: any,
config?: AxiosRequestConfig
): Promise<R>;
patch<T = any, R = AxiosResponse<T>>(
url: string,
data?: any,
config?: AxiosRequestConfig
): Promise<R>;
}
128 changes: 128 additions & 0 deletions packages/axios/src/servicManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import axios, { AxiosRequestConfig, AxiosInstance, AxiosResponse } from 'axios';
import { Provide, Inject, Init, Config, App } from '@midwayjs/decorator';
import { IMidwayApplication } from '@midwayjs/core';
import { AXIOS_INSTANCE_KEY, AxiosHttpService } from './interface';

@Provide()
export class HttpService implements AxiosHttpService {
private instance: AxiosInstance;

@Inject()
protected ctx: any;

@App()
protected app: IMidwayApplication;

@Config('axios')
protected httpConfig: AxiosRequestConfig;

get interceptors() {
return this.instance.interceptors;
}

@Init()
protected async init() {
if (
!this.app.getApplicationContext().registry.hasObject(AXIOS_INSTANCE_KEY)
) {
// 动态往全局容器中创建一个单例
const instance = axios.create(this.httpConfig ?? {});

// Add a request interceptor
instance.interceptors.request.use(
config => {
// Do something before request is sent
return config;
},
error => {
// Do something with request error
return Promise.reject(error);
}
);

// Add a response interceptor
instance.interceptors.response.use(
response => {
// Any status code that lie within the range of 2xx cause this function to trigger
// Do something with response data
return response;
},
error => {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
return Promise.reject(error);
}
);

this.app
.getApplicationContext()
.registry.registerObject(AXIOS_INSTANCE_KEY, instance);
}

this.instance = this.app
.getApplicationContext()
.registry.getObject(AXIOS_INSTANCE_KEY);
}

getUri(config?: AxiosRequestConfig): string {
return this.instance.getUri(config);
}

request<T = any, R = AxiosResponse<T>>(
config: AxiosRequestConfig
): Promise<R> {
return this.instance.request(config);
}

get<T = any, R = AxiosResponse<T>>(
url: string,
config?: AxiosRequestConfig
): Promise<R> {
return this.instance.get(url, config);
}

delete<T = any, R = AxiosResponse<T>>(
url: string,
config?: AxiosRequestConfig
): Promise<R> {
return this.instance.delete(url, config);
}

head<T = any, R = AxiosResponse<T>>(
url: string,
config?: AxiosRequestConfig
): Promise<R> {
return this.instance.head(url, config);
}

options<T = any, R = AxiosResponse<T>>(
url: string,
config?: AxiosRequestConfig
): Promise<R> {
return this.instance.options(url, config);
}

post<T = any, R = AxiosResponse<T>>(
url: string,
data?: any,
config?: AxiosRequestConfig
): Promise<R> {
return this.instance.post(url, config);
}

put<T = any, R = AxiosResponse<T>>(
url: string,
data?: any,
config?: AxiosRequestConfig
): Promise<R> {
return this.instance.put(url, config);
}

patch<T = any, R = AxiosResponse<T>>(
url: string,
data?: any,
config?: AxiosRequestConfig
): Promise<R> {
return this.instance.patch(url, config);
}
}
6 changes: 6 additions & 0 deletions packages/axios/test/fixtures/base-app/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "base-app",
"version": "1.0.0",
"dependencies": {
}
}
10 changes: 10 additions & 0 deletions packages/axios/test/fixtures/base-app/src/configuration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Configuration } from '@midwayjs/decorator';

@Configuration({
imports: [
require('../../../../src')
]
})
export class AutoConfiguration {

}
59 changes: 59 additions & 0 deletions packages/axios/test/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { LightFramework } from '@midwayjs/core';
import { join } from 'path';
import { HttpService } from '../src';

describe('/test/index.test.ts', () => {

let httpService: any;
let container;
let framework;

beforeAll(async () => {
framework = new LightFramework();
framework.configure();
await framework.initialize({ baseDir: join(__dirname, './fixtures/base-app/src') });
container = framework.getApplicationContext();
httpService = await container.getAsync(HttpService);
});

it('should test http service singleton', async () => {
expect(httpService).toBeDefined();
const httpService2 = await container.getAsync(HttpService);
expect(httpService).toEqual(httpService2);
});

it('should test context http service', async () => {
const ctx = framework.getApplication().createAnonymousContext();
const httpServiceWithRequest = await ctx.requestContext.getAsync(HttpService);
expect(httpServiceWithRequest).toBeDefined();
expect(httpServiceWithRequest).not.toEqual(httpService);
});

it('should test proxy method', function () {
const proxyMethods = [
'getUri',
'request',
'get',
'delete',
'head',
'options',
'post',
'put',
'patch',
];

for (const method of proxyMethods) {
const fn = jest.spyOn(httpService['instance'], method).mockImplementation(() => {
return 'hello world'
});
httpService[method].call(httpService);
expect(fn).toHaveBeenCalled();
jest.restoreAllMocks();
}
});

it('should test get method', async () => {
const result = await httpService.get('https://api.github.com/users/octocat/orgs');
expect(result.status).toEqual(200);
});
});
11 changes: 11 additions & 0 deletions packages/axios/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"extends": "../../tsconfig.json",
"compileOnSave": true,
"compilerOptions": {
"rootDir": "src",
"outDir": "dist"
},
"include": [
"./src/**/*.ts"
]
}
1 change: 0 additions & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
"@midwayjs/logger": "^2.11.3",
"class-transformer": "^0.3.1",
"extend2": "^1.0.0",
"lodash.assign": "^4.2.0",
"lodash.clonedeep": "^4.5.0",
"lodash.defaultsdeep": "^4.6.0",
"lodash.get": "^4.4.2",
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/common/lodashWrap.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as assign from 'lodash.assign';
import * as get from 'lodash.get';
import * as set from 'lodash.set';
import * as template from 'lodash.template';
import * as cloneDeep from 'lodash.clonedeep';
import * as defaultsDeep from 'lodash.defaultsdeep';
import * as assign from 'extend2';

const isArray = Array.isArray;

Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export { MidwayRequestContainer } from './context/requestContainer';
export { BaseFramework } from './baseFramework';
export * from './context/providerWrapper';
export * from './common/constants';
export { safelyGet, safeRequire } from './util/';
export { safelyGet, safeRequire, delegateTargetPrototypeMethod } from './util/';
export * from './util/pathFileUtil';
export * from './features';
export * from './util/webRouterParam';
Expand Down
15 changes: 15 additions & 0 deletions packages/core/src/util/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,18 @@ export function joinURLPath(...strArray) {
}
return p;
}

export function delegateTargetPrototypeMethod(
derivedCtor: any,
constructors: any[]
) {
constructors.forEach(baseCtor => {
Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
if (name !== 'constructor' && !/^_/.test(name)) {
derivedCtor.prototype[name] = async function (...args) {
return this.instance[name](...args);
};
}
});
});
}
Loading

0 comments on commit 4e2f90a

Please sign in to comment.