npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

booze

v1.0.0

Published

cross platform client http framework

Downloads

11

Readme

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';