npm package: @redhare/http
Description: # Background Currently Http module code is hardcoded into the template code which will make future update or bug fix infeasible. The Http module code should be extracted into an independent nestjs module. In this way developer can not only update the corr
Latest version: 0.0.2

# @infra-node-kit/http

# Background
Currently Http module code is hardcoded into the template code which will make future update
or bug fix infeasible. The Http module code should be extracted into an independent nestjs module. In this way developer can not only update the corresponding package when new features are released, but also have an option to choose whether they want to use our module in their project.

# Features
* Implement a Http module with nestjs standard modules(https://docs.nestjs.com/modules) technique which provides a variety of high-frequency use http request methods.
* request multiplexing.
* current limiting. base on [p-queue](https://github.com/sindresorhus/p-queue)
* (WIP)Need to consider using circuit breaker pattern.

# How to use
## Install
```
yarn install @infra-node-kit/http
```

## Basic Usage

### normal

It's same with `@nestjs/axios`. The usage of `@nestjs/axios` can be found at https://docs.nestjs.com/techniques/http-module.

[Axios](https://github.com/axios/axios) can be configured with a variety of options to customize the behavior of the HttpService. Besides the `AxiosRequestConfig`, you can also configure with the following options:

| Option        | Description | Type       | Default     |
| ------------- | ----------- | ---------- | ----------- |
| retryMaxCount | max retry count when can't get response.| Number | 1 |
| retryDelay    | retry delay | Number     | 500 (ms)    |
| concurrency   | concurrency limit. | Number     | Infinity    |
| skipPaths | the paths which the log is not required | string[] | [] |
| skipBodyPaths | Whether to hide the body field in the log | boolean | false |
| skipHeadersPaths | Whether to hide the headers field in the log | boolean | false |

The path rule can reference to [path-to-regexp](https://www.npmjs.com/package/path-to-regexp)

Besides `path-to-regexp` rules you can use `*` to match all the paths.

```typescript
HttpModule.registerAsync({
  imports: [ConfigModule],
  useFactory: async (configService: ConfigService) => ({
    timeout: configService.get('HTTP_TIMEOUT'),
    maxRedirects: configService.get('HTTP_MAX_REDIRECTS'),
    retryMaxCount: 3,
    retryDelay: 1000
  }),
  inject: [ConfigService],
});
```

### Best Practice

If you want to use a lot of servers, you can create a module for each server which can customize the behavior of the `HttpService`.

demo:

```typescript
// server 1
@Module({
  controllers: [],
  imports: [
    HttpModule.register({
      baseURL: 'https://api.rap.shopee.io/app/mock/110',
      concurrency: 1,
    }),
  ],
  providers: [Server1Service],
  exports: [Server1Service],
})
export class Server1Module {}

// server 2, have different configurations
@Module({
  controllers: [],
  imports: [
    HttpModule.register({
      baseURL: 'https://api.rap.shopee.io/app/mock/120',
      timeout: 5000,
      concurrency: 1,
    }),
  ],
  providers: [Server2Service],
  exports: [Server2Service],
})
export class Server2Module {}

// Biz modules can combine these modules
@Module({
  imports: [
    Server1Module,
    Server2Module
  ],
})
export class BizModule {}
```

### working with rapper

> Get more information about `rap`:  [link](https://shopee.git-pages.garena.com/InfraFe/one-site/tech-stack/rap/rap)

First import `HttpModule`.

```typescript
import { HttpModule } from '@infra-node-kit/http'
import { Module } from '@nestjs/common'
import { AppController } from './app.controller'
import { AppService } from './app.service'

@Module({
  imports: [HttpModule.register({ concurrency: 1000 })],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}
```

Next, get the method `request` from the instance of `HttpService`. After that, hava fun with [rapper](https://www.yuque.com/rap/rapper/overridefetch#Y0Clz).

```typescript
import { NestFactory } from '@nestjs/core'
import { HttpService } from '@infra-node-kit/http'
import { AppModule } from './app.module'
import { overrideFetch } from './rapper'

async function bootstrap() {
  const app = await NestFactory.create(AppModule)
  const httpService = app.get(HttpService)
  overrideFetch(async ({ url, method, params }) => {
    try {
      const response = await httpService.request({
        baseURL: 'https://api.rap.shopee.io/app/mock/110',
        method,
        url,
        data: params,
      })
      return response.data
    } catch (error) {
      return Promise.reject(error)
    }
  })
  await app.listen(3000)
}
bootstrap()
```

```typescript
import { fetch } from '../../rapper'

@Controller('example')
export class ExampleController {
  @Get('getTestRap')
  async getTestRap(): Promise<string> {
    return await fetch['GET/test/get']({})
  }
}
```

## API
### request method
provide the following methods:
+ request(config)
+ get(url[, config])
+ post(url[, data[, config]])
+ put(url[, data[, config]])
+ del(url[, config])

return an `AxiosResponse`

### downloadFile([configs])

configs:

+ sourceUrl `<string>`
+ destinationFolder `<string>`
+ options:
   + name `<string>`
   + override `<boolean>`, defalut is `false`
   + autoCreateFolder `<boolean>`, defalut is `false`

### axiosRef
`axiosRef` is provided. You can use it to [intercept requests](https://axios-http.com/docs/interceptors) or [specify config defaults](https://axios-http.com/docs/config_defaults) that will be applied to every request. But please use the above method to send request, it will loss of concurrency if you send request by `axiosRef` directly.