working -> renamed from nestjs-http-promise-retry
This commit is contained in:
commit
8f4d747d2e
19 changed files with 3728 additions and 0 deletions
2
.eslintignore
Normal file
2
.eslintignore
Normal file
|
@ -0,0 +1,2 @@
|
|||
.eslintrc.js
|
||||
index.ts
|
26
.eslintrc.js
Normal file
26
.eslintrc.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
module.exports = {
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
project: './tsconfig.json',
|
||||
sourceType: 'module',
|
||||
},
|
||||
plugins: ['@typescript-eslint/eslint-plugin'],
|
||||
extends: [
|
||||
'plugin:@typescript-eslint/eslint-recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'prettier',
|
||||
],
|
||||
root: true,
|
||||
env: {
|
||||
node: true,
|
||||
jest: true,
|
||||
},
|
||||
rules: {
|
||||
'@typescript-eslint/interface-name-prefix': 'off',
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/no-use-before-define': 'off',
|
||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
},
|
||||
};
|
||||
|
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Smartphone (please complete the following information):**
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
46
.github/workflows/publish.yml
vendored
Normal file
46
.github/workflows/publish.yml
vendored
Normal file
|
@ -0,0 +1,46 @@
|
|||
name: publish-and-tag
|
||||
env:
|
||||
CI: true
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
tags:
|
||||
- "!*"
|
||||
jobs:
|
||||
publish-to-npm:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: setup Node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 14.x
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
- name: install
|
||||
run: npm install
|
||||
- name: test
|
||||
run: npm test
|
||||
# Publish to npm if this version is not published
|
||||
- name: publish
|
||||
run: npm run publish:npm
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
|
||||
create-tag:
|
||||
runs-on: ubuntu-latest
|
||||
needs: publish-to-npm
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v2
|
||||
# Push tag to GitHub if package.json version's tag is not tagged
|
||||
- name: package-version
|
||||
run: node -p -e '`PACKAGE_VERSION=${require("./package.json").version}`' >> $GITHUB_ENV
|
||||
- name: package-version-to-git-tag
|
||||
uses: pkgdeps/git-tag-action@v2
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
github_repo: ${{ github.repository }}
|
||||
version: ${{ env.PACKAGE_VERSION }}
|
||||
git_commit_sha: ${{ github.sha }}
|
||||
git_tag_prefix: "v"
|
19
.gitignore
vendored
Normal file
19
.gitignore
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# IDE
|
||||
/.idea
|
||||
/.awcache
|
||||
/.vscode
|
||||
|
||||
# misc
|
||||
npm-debug.log
|
||||
.DS_Store
|
||||
|
||||
# tests
|
||||
/test
|
||||
/coverage
|
||||
/.nyc_output
|
||||
|
||||
# dist
|
||||
dist
|
6
.prettierrc
Normal file
6
.prettierrc
Normal file
|
@ -0,0 +1,6 @@
|
|||
|
||||
{
|
||||
"trailingComma": "all",
|
||||
"singleQuote": true,
|
||||
"arrowParens": "avoid"
|
||||
}
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2021 benhason1
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
118
README.md
Normal file
118
README.md
Normal file
|
@ -0,0 +1,118 @@
|
|||
# nestjs-http-promise
|
||||
|
||||
## description
|
||||
nestjs module that just doing little modification to the original and good **nestjs** http module.
|
||||
|
||||
|
||||
## features
|
||||
* axios - the most used package for http requests in npm.
|
||||
* promise based - most of us using the current http module and on every call do `.toPromise()`
|
||||
because most of the time we do not need the features of observable.
|
||||
* retries - one of the powerful features of observable is its ability to do in very simple way,
|
||||
you can do it by just adding the retry operator, this package will provide you the same feature even in easier way,
|
||||
just pass `{ retries: NUMBER_OF_RETRIES }` in the config of the http module.
|
||||
## quick start
|
||||
### installing
|
||||
Using npm:
|
||||
```
|
||||
$ npm install nestjs-http-promise
|
||||
```
|
||||
|
||||
Using yarn:
|
||||
```
|
||||
$ yarn add nestjs-http-promise
|
||||
```
|
||||
|
||||
### usage - just like every nest.js module
|
||||
import the module:
|
||||
```ts
|
||||
import { HttpModule } from 'nestjs-http-promise'
|
||||
|
||||
@Module({
|
||||
imports: [HttpModule]
|
||||
})
|
||||
```
|
||||
|
||||
inject the service in the class:
|
||||
```ts
|
||||
import { HttpService } from 'nestjs-http-promise'
|
||||
|
||||
class Demo {
|
||||
constructor(private readonly httpService: HttpService) {}
|
||||
}
|
||||
```
|
||||
|
||||
use the service:
|
||||
```ts
|
||||
public callSomeServer(): Promise<object> {
|
||||
return this.httpService.get('http://fakeService')
|
||||
}
|
||||
```
|
||||
|
||||
##configuration
|
||||
|
||||
the service uses axios and axios-retry, so you can pass any [AxiosRequestConfig](https://github.com/axios/axios#request-config)
|
||||
And/Or [AxiosRetryConfig](https://github.com/softonic/axios-retry#options)
|
||||
|
||||
just pass it in the `.register()` method as you would do in the original nestjs httpModule
|
||||
```ts
|
||||
import { HttpModule } from 'nestjs-http-promise'
|
||||
|
||||
@Module({
|
||||
imports: [HttpModule.register(
|
||||
{
|
||||
timeout: 1000,
|
||||
retries: 5,
|
||||
...
|
||||
}
|
||||
)]
|
||||
})
|
||||
```
|
||||
|
||||
### default configuration
|
||||
just the default config of axios-retry : https://github.com/softonic/axios-retry#options
|
||||
|
||||
## async configuration
|
||||
When you need to pass module options asynchronously instead of statically, use the `registerAsync()` method **just like in nest httpModule**.
|
||||
|
||||
you have a couple of techniques to do it:
|
||||
* with the useFactory
|
||||
```ts
|
||||
HttpModule.registerAsync({
|
||||
useFactory: () => ({
|
||||
timeout: 1000,
|
||||
retries: 5,
|
||||
...
|
||||
}),
|
||||
});
|
||||
```
|
||||
|
||||
* using class
|
||||
|
||||
```ts
|
||||
HttpModule.registerAsync({
|
||||
useClass: HttpConfigService,
|
||||
});
|
||||
```
|
||||
Note that in this example, the HttpConfigService has to implement HttpModuleOptionsFactory interface as shown below.
|
||||
```ts
|
||||
@Injectable()
|
||||
class HttpConfigService implements HttpModuleOptionsFactory {
|
||||
async createHttpOptions(): Promise<HttpModuleOptions> {
|
||||
const configurationData = await sonmeAsyncMethod();
|
||||
return {
|
||||
timeout: configurationData.timeout,
|
||||
retries: 5,
|
||||
...
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
If you want to reuse an existing options provider instead of creating a copy inside the HttpModule,
|
||||
use the useExisting syntax.
|
||||
```ts
|
||||
HttpModule.registerAsync({
|
||||
imports: [ConfigModule],
|
||||
useExisting: ConfigService,
|
||||
});
|
||||
```
|
1
index.ts
Normal file
1
index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export * from './lib'
|
3
lib/http.constants.ts
Normal file
3
lib/http.constants.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export const AXIOS_INSTANCE_TOKEN = 'AXIOS_INSTANCE_TOKEN';
|
||||
export const HTTP_MODULE_ID = 'HTTP_MODULE_ID';
|
||||
export const HTTP_MODULE_OPTIONS = 'HTTP_MODULE_OPTIONS';
|
114
lib/http.module.ts
Normal file
114
lib/http.module.ts
Normal file
|
@ -0,0 +1,114 @@
|
|||
import { DynamicModule, Module, Provider } from '@nestjs/common';
|
||||
import { randomStringGenerator } from '@nestjs/common/utils/random-string-generator.util';
|
||||
import Axios from 'axios';
|
||||
import {
|
||||
AXIOS_INSTANCE_TOKEN,
|
||||
HTTP_MODULE_ID,
|
||||
HTTP_MODULE_OPTIONS,
|
||||
} from './http.constants';
|
||||
import { HttpService } from './http.service';
|
||||
import {
|
||||
HttpModuleAsyncOptions,
|
||||
HttpModuleOptions,
|
||||
HttpModuleOptionsFactory,
|
||||
} from './interfaces';
|
||||
import axiosRetry from 'axios-retry';
|
||||
|
||||
const createAxiosRetry = (config: HttpModuleOptions) => {
|
||||
const axiosInstance = Axios.create(config);
|
||||
axiosRetry(axiosInstance, config);
|
||||
return axiosInstance;
|
||||
}
|
||||
|
||||
@Module({
|
||||
providers: [
|
||||
HttpService,
|
||||
{
|
||||
provide: AXIOS_INSTANCE_TOKEN,
|
||||
useValue: Axios,
|
||||
},
|
||||
],
|
||||
exports: [HttpService],
|
||||
})
|
||||
export class HttpModule {
|
||||
static register(config: HttpModuleOptions): DynamicModule {
|
||||
return {
|
||||
module: HttpModule,
|
||||
providers: [
|
||||
{
|
||||
provide: AXIOS_INSTANCE_TOKEN,
|
||||
useValue: createAxiosRetry(config),
|
||||
},
|
||||
{
|
||||
provide: HTTP_MODULE_ID,
|
||||
useValue: randomStringGenerator(),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
static registerAsync(options: HttpModuleAsyncOptions): DynamicModule {
|
||||
return {
|
||||
module: HttpModule,
|
||||
imports: options.imports,
|
||||
providers: [
|
||||
...this.createAsyncProviders(options),
|
||||
{
|
||||
provide: AXIOS_INSTANCE_TOKEN,
|
||||
useFactory: (config: HttpModuleOptions) => createAxiosRetry(config),
|
||||
inject: [HTTP_MODULE_OPTIONS],
|
||||
},
|
||||
{
|
||||
provide: HTTP_MODULE_ID,
|
||||
useValue: randomStringGenerator(),
|
||||
},
|
||||
...(options.extraProviders || []),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
private static createAsyncProviders(
|
||||
options: HttpModuleAsyncOptions,
|
||||
): Provider[] {
|
||||
if (options.useExisting || options.useFactory) {
|
||||
return [this.createAsyncOptionsProvider(options)];
|
||||
}
|
||||
|
||||
const providers = [
|
||||
this.createAsyncOptionsProvider(options)
|
||||
];
|
||||
|
||||
if(options.useClass)
|
||||
providers.push({
|
||||
provide: options.useClass,
|
||||
useClass: options.useClass,
|
||||
})
|
||||
|
||||
return providers;
|
||||
}
|
||||
|
||||
private static createAsyncOptionsProvider(
|
||||
options: HttpModuleAsyncOptions,
|
||||
): Provider {
|
||||
if (options.useFactory) {
|
||||
return {
|
||||
provide: HTTP_MODULE_OPTIONS,
|
||||
useFactory: options.useFactory,
|
||||
inject: options.inject || [],
|
||||
};
|
||||
}
|
||||
|
||||
let inject;
|
||||
if (options.useExisting)
|
||||
inject = [options.useExisting];
|
||||
else if (options.useClass)
|
||||
inject = [options.useClass];
|
||||
|
||||
return {
|
||||
provide: HTTP_MODULE_OPTIONS,
|
||||
useFactory: async (optionsFactory: HttpModuleOptionsFactory) =>
|
||||
optionsFactory.createHttpOptions(),
|
||||
inject,
|
||||
};
|
||||
}
|
||||
}
|
37
lib/http.service.ts
Normal file
37
lib/http.service.ts
Normal file
|
@ -0,0 +1,37 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { Inject } from '@nestjs/common';
|
||||
import Axios ,{AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
|
||||
import { AXIOS_INSTANCE_TOKEN } from "./http.constants";
|
||||
|
||||
@Injectable()
|
||||
export class HttpService {
|
||||
constructor(
|
||||
@Inject(AXIOS_INSTANCE_TOKEN)
|
||||
private readonly instance: AxiosInstance = Axios,
|
||||
) {}
|
||||
request<T = any>(config: AxiosRequestConfig): Promise<AxiosResponse<T>> {
|
||||
return this.instance.request(config)
|
||||
}
|
||||
get<T = any>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {
|
||||
return this.instance.get(url, config);
|
||||
}
|
||||
delete<T = any>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {
|
||||
return this.instance.delete(url, config);
|
||||
}
|
||||
head<T = any>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {
|
||||
return this.instance.head(url, config);
|
||||
}
|
||||
post<T = any>(url: string, data?: Record<string, any>, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {
|
||||
return this.instance.post(url, data, config);
|
||||
}
|
||||
put<T = any>(url: string, data?: Record<string, any>, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {
|
||||
return this.instance.put(url, data, config);
|
||||
}
|
||||
patch<T = any>(url: string, data?: Record<string, any>, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {
|
||||
return this.instance.patch(url, data, config);
|
||||
}
|
||||
|
||||
get axiosRef(): AxiosInstance {
|
||||
return this.instance
|
||||
}
|
||||
}
|
3
lib/index.ts
Normal file
3
lib/index.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export { HttpService } from './http.service'
|
||||
export { HttpModule } from './http.module'
|
||||
export * from './interfaces'
|
20
lib/interfaces/http-module.interface.ts
Normal file
20
lib/interfaces/http-module.interface.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { ModuleMetadata, Provider, Type } from '@nestjs/common';
|
||||
import { AxiosRequestConfig } from 'axios';
|
||||
import { IAxiosRetryConfig } from 'axios-retry'
|
||||
|
||||
export type HttpModuleOptions = (AxiosRequestConfig & IAxiosRetryConfig);
|
||||
|
||||
export interface HttpModuleOptionsFactory {
|
||||
createHttpOptions(): Promise<HttpModuleOptions> | HttpModuleOptions;
|
||||
}
|
||||
|
||||
export interface HttpModuleAsyncOptions
|
||||
extends Pick<ModuleMetadata, 'imports'> {
|
||||
useExisting?: Type<HttpModuleOptionsFactory>;
|
||||
useClass?: Type<HttpModuleOptionsFactory>;
|
||||
useFactory?: (
|
||||
...args: any[]
|
||||
) => Promise<HttpModuleOptions> | HttpModuleOptions;
|
||||
inject?: any[];
|
||||
extraProviders?: Provider[];
|
||||
}
|
1
lib/interfaces/index.ts
Normal file
1
lib/interfaces/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export * from './http-module.interface';
|
3175
package-lock.json
generated
Normal file
3175
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
59
package.json
Normal file
59
package.json
Normal file
|
@ -0,0 +1,59 @@
|
|||
{
|
||||
"name": "nestjs-http-promise",
|
||||
"version": "2.0.0",
|
||||
"keywords": ["nestjs", "http", "promise", "retry", "retries", "axios"],
|
||||
"description": "promise implementation of nestjs http module with retries feature using axios-retry and axios",
|
||||
"author": "Ben Hason",
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"url": "https://github.com/benhason1/nestjs-http-promise#readme",
|
||||
"scripts": {
|
||||
"build": "rimraf -rf dist && tsc -p tsconfig.json",
|
||||
"format": "prettier --write \"{lib}/**/*.ts\"",
|
||||
"lint": "eslint 'lib/**/*.ts' --fix",
|
||||
"prepublish:npm": "npm run build",
|
||||
"publish:npm": "npm publish --access public",
|
||||
"publish:beta": "npm publish --access public --tag beta",
|
||||
"prepublish:beta": "npm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "0.21.1",
|
||||
"axios-retry": "^3.1.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/common": "8.0.6",
|
||||
"@nestjs/core": "8.0.6",
|
||||
"@nestjs/platform-express": "8.0.6",
|
||||
"@types/node": "14.17.14",
|
||||
"@typescript-eslint/eslint-plugin": "4.30.0",
|
||||
"@typescript-eslint/parser": "4.30.0",
|
||||
"eslint": "7.32.0",
|
||||
"eslint-config-prettier": "8.3.0",
|
||||
"eslint-plugin-import": "2.24.2",
|
||||
"husky": "7.0.2",
|
||||
"lint-staged": "11.1.2",
|
||||
"prettier": "^2.3.2",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"rimraf": "3.0.2",
|
||||
"typescript": "4.4.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nestjs/common": "^7.0.0 || ^8.0.0",
|
||||
"reflect-metadata": "^0.1.12"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.ts": [
|
||||
"prettier --write"
|
||||
]
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/benhason1/nestjs-http-promise"
|
||||
}
|
||||
}
|
19
tsconfig.json
Normal file
19
tsconfig.json
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"declaration": true,
|
||||
"removeComments": true,
|
||||
"noLib": false,
|
||||
"emitDecoratorMetadata": true,
|
||||
"esModuleInterop": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "es6",
|
||||
"sourceMap": false,
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./lib",
|
||||
"skipLibCheck": true,
|
||||
},
|
||||
"include": ["lib/**/*"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
Loading…
Reference in a new issue