New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

booze

Package Overview
Dependencies
Maintainers
1
Versions
23
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

booze

cross platform client http framework

latest
Source
npmnpm
Version
1.0.0
Version published
Maintainers
1
Created
Source

booze

🇨🇳中文 | ENGLISH

booze是一个客户端HTTP上层应用框架,使客户端请求代码编写核心为描述一个请求。

booze不提供请求的能力,只收集请求信息,通过一个适配器递交给底层的请求引擎,所以兼容所有请求方案。

安装

npm i booze -S

使用

import { Prefix, Get, regAdapter } from 'booze';
import axiosAdapter from 'booze/adapter/axios';

// 注册适配器 使用axios为底层请求框架
regAdapter(axiosAdapter);

// 设置服务域名
@Prefix('https://some.site.com')
class Request {
  // 表示为一个get请求,接口为/list
  // 被Get装饰后,方法内容会被改写
  @Get('/list')
  public getList(page: number) {
    // 返回值被booze处理后会作为一部分参数,递交给axios,返回值就是服务端响应的内容
    return {
      page,
    };
  }
}

const service = new Request();

// 调用方法,会发起一个请求
const result = await service.getList(1);

// 请求响应的数据
console.log(result);

核心原理

booze提供了一些装饰器,如GetPost,这些装饰器装饰类的方法后,会对方法进行重写。

重写前的方法会被内部保留,每次调用被装饰过的方法后,内部会调用原方法,得到返回值作为请求参数,然后递交适配器处理后,返回适配器处理后的内容。

适配器

booze 不包含任何请求相关的能力,仅负责收集请求相关的信息。

适配器的作用就是根据这些配置去发起请求,所以booze兼容所有请求方案,但在特殊场景下并非开箱即用。

// 请求信息
interface BoozeRequestConfig {
  url: string;
  method: RequestMethod;
  queryString: string;
  query: Record<string, string>;
  params: Record<string, any>;
  headers: Record<string, string>;
  jsonp: string|null;
  onProgress: Function|null;
  cancel: Function|null;
  _prefix: string;
  _url: string;
}

适配器本质是一个对象,包含name属性和handler方法。

const adapter = {
  // 适配器名称
  name: 'adapter name',
  // 适配器处理函数
  // 接收收集的请求数据,在这里调用真正的请求方法,然后返回
  handler: async (config) => {
    console.log(config.url);

    const result = await axios.get(...);

    return result;
  },
};

注册适配器

booze 内置了部分适配器,提供的能力不一定完善,可以自行扩展。

import { regAdapter } from 'booze';
import axiosAdapter from 'booze/adapter/axios';

// 全局注册适配器
regAdapter(axiosAdapter);

Decorators

Prefix

设置所有请求的前缀。

用于装饰一个类,类下的方法在生成请求配置的时候,会使用传入的参数作为请求的前缀。

@Prefix('https://some.site.com')
class Req {}

Get

装饰方法,调用该方法后,会把方法的返回值作为参数,发起一个get请求。

@Prefix('https://some.site.com')
class Req {
  @Get('/list')
  public getList() {
    return {
      page: 1,
    };
  }
}

可以携带第二个参数,会替代装饰在类上的前缀。

@Prefix('https://some.site.com')
class Req {
  @Get('/list', '//site.com')
  public getList() {
    return {
      page: 1,
    };
  }
}

有些情况下,参数是带在路径上的,可以通过占位符的方式解决。

path中通过:placeholder的方式占位,这时候返回值需要变成数组,第二个参数来返回占位同名的参数,这样在处理参数过程中,booze会对占位符进行替换。

@Prefix('https://some.site.com')
class Req {
  @Get('/list/:id')
  public getList() {
    return [{
      page: 1,
    }, {
      id: 996,
    }];
  }
}

注:装饰请求方法的装饰器,必须放在第一位。

Post

装饰方法,调用该方法后,会把方法的返回值作为参数,发起一个Post请求。

@Prefix('https://some.site.com')
class Req {
  @Post('/')
  public updateSomeThing() {
    return {};
  }
}

Headers

额外携带的请求头,可以传递三种形式的参数。

// 设置一组
class Req {
  @Post('/')
  @Headers('Authorization', 'Bearer .......')
  public updateSomeThing() {
    return {};
  }
}

// 传递对象
class Req {
  @Post('/')
  @Headers({
    Authorization: 'Bearer .......',
    ContentType: 'application/json',
  })
  public updateSomeThing() {
    return {};
  }
}

// 传递函数
class Req {
  @Post('/')
  @Headers((config: BoozeRequestConfig) => {
    return {};
  })
  public updateSomeThing() {
    return {};
  }
}

@Prefix('')
// 同上
@Headers()
class Req {}

JSONP

标记请求为JSONP的形式处理。

@Prefix('https://some.site.com')
class Req {
  @Get('/list')
  @JSONP()
  public getList() {
    return {
      page: 1,
    };
  }
}

Before

请求发送前会调用,如果返回 false ,请求就会被中断。

如果装饰在类上,则每个方法被调用的时候都会触发。

@Prefix('https://some.site.com')
@Before((config: BoozeRequestConfig) => {

})
class Req {
  @Get('/list')
  @JSONP()
  @Before((config: BoozeRequestConfig) => {

  })
  public getList() {
    return {
      page: 1,
    };
  }
}

After

请求被响应后调用。

如果装饰在类上,则每个方法被调用的时候都会触发。

@Prefix('https://some.site.com')
@After<ResponseType>((response, config: BoozeRequestConfig) => {

})
class Req {
  @Get('/list')
  @JSONP()
  @After<ResponseType>((response, config: BoozeRequestConfig) => {

  })
  public getList() {
    return {
      page: 1,
    };
  }
}

Adapter

给某个请求单独指定适配器。

@Prefix('https://some.site.com')
class Req {
  @Get('/list')
  @Adapter(axiosAdapter)
  public getList() {
    return {
      page: 1,
    };
  }
}

也可以传递字符串,会从注册过的适配器里匹配name属性。

@Prefix('https://some.site.com')
class Req {
  @Get('/list')
  @Adapter('jqueryAdapter')
  public getList() {
    return {
      page: 1,
    };
  }
}

BeforeExecSourceFn

在原始方法被执行前会执行,如果返回false,会中断请求的发送。

@Prefix('https://some.site.com')
@BeforeExecSourceFn(() => {})
class Req {
  @Delete('/')
  @BeforeExecSourceFn(() => {})
  public updateSomeThing() {}
}

BodyType

预设了部分content-type类型。

  • BodyType.Type.Form - application/x-www-form-urlencoded
  • BodyType.Type.JSON - application/json
import { BodyType } from 'booze';

@Prefix('https://some.site.com')
@BodyType(BodyType.Type.Form)
class Req {
  @Delete('/')
  @BodyType(BodyType.Type.JSON)
  public updateSomeThing() {}
}

Delete

@Prefix('https://some.site.com')
class Req {
  @Delete('/')
  public updateSomeThing() {}
}

Put

@Prefix('https://some.site.com')
class Req {
  @Put('/')
  public updateSomeThing() {}
}

Options

@Prefix('https://some.site.com')
class Options {
  @Put('/')
  public updateSomeThing() {}
}

Head

@Prefix('https://some.site.com')
class Options {
  @Head('/')
  public updateSomeThing() {}
}

Patch

@Prefix('https://some.site.com')
class Patch {
  @Head('/')
  public updateSomeThing() {}
}

APIs

regAdapter

注册适配器,可以注册多个,默认使用第一个作为适配器,可以通过setAdapter切换。

import { regAdapter } from 'booze';

// 注册一个
regAdapter(axiosAdapter);
// 注册多个
regAdapter([
  jqueryAdapter,
  fetchAdapter,
  {
    name: 'xhrAdapter',
    handler: (config) => {
      return {};
    },
  },
]);

setAdapter

设置适配器,有多个适配器的时候,可以直接通过name指定,也可以传入一个新的适配器。

import { setAdapter } from 'booze';

setAdapter('xhrAdapter');

setAdapter({
  name: '',
  handler: () => {},
});

makeBody

如果需要一些特殊需求,如取消请求、进度条展示等,可以用到这个方法。

@Prefix('https://some.site.com')
class Req {
  @Get('/list')
  public getList() {
    return makeBody {
      // body中的参数
      params: {},
      // 被拼到url上的参数
      query: {},
      // 路径参数
      placeholder: {},
      // 进度条变化回调
      onProgress: () => {},
      // 取消请求
      cancel: () => {},
      // jsonp callback的名称
      jsonp: '',
    };
  }
}

eachBeforeExecSourceFn

注册全局的钩子,会在原始方法被调用前触发。

如果返回值是 false 则会中断请求。

import { eachBeforeExecSourceFn } from 'booze';

eachBeforeExecSourceFn((baseConfig) => {
  console.log(baseConfig);
});

eachAfter

注册全局的钩子,会在适配器执行后触发。

import { eachAfter } from 'booze';

eachAfter((response, baseConfig) => {
  console.log(baseConfig);
});

开发注意点

数据类型问题

因为方法被装饰器重写了,所以调用方法后得到的返回值,类型推断层面会存在问题,官方也有相关ISSUE

推荐采用as的方式:

interface SomeInterface {

}

@Prefix('https://some.site.com')
class Req {
  @Get('/')
  public getSomeThing() {
    return {} as SomeInterface;
  }
}

装饰顺序问题

标记请求方法的装饰器,必须放在第一个。

包括:

  • @Get
  • @Post
  • @Delete
  • @Put
  • @Patch
  • @Options
  • @Head
@Prefix('https://some.site.com')
class Req {
  // 这样会运行异常,Get必须放在最前面
  @After()
  @Get('/')
  public getSomeThing() {
    return {};
  }
}

JavaScript无法使用

配置在package.json里的main是指向src/index.ts的,所以JS需要调用,需要引入TSC编译好的版本:

import { Get, Prefix } from 'booze/release/commonjs';

Keywords

http

FAQs

Package last updated on 21 Apr 2023

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts