pnw-rexec
v1.1.3
Published
Request builder and executor for the Politics and War API.
Downloads
9
Maintainers
Readme
PnW Rexec
A Request Builder and Executor for the Politics and War API
Features
- Create different profiles for queries.
- Chain executors to create the behavior you want.
- Log your requests with a log callback.
- Paginator results have helper methods.
- Requests are typed with the fields you request and nothing more.
Sections
Install
npm i pnw-rexec
Usage
import { RequesterProfile } from 'pnw-rexec';
or
const { RequesterProfile } = require('pnw-rexec');
and
const profile = new RequesterProfile().key('my-key');
const { me } = await profile.request().me((me) => me
.child('nation', (n) => n.fields('nation_name', 'leader_name'))
)
.send();
const { leader_name, nation_name } = me.nation;
console.log(`Hello, I'm ${leader_name} of ${nation_name}`);
Executors
You can set up your profiles to use one of the available executors, or write your own.
new RequesterProfile()
.bin({defer: true, timeout: 1000})
.cache({cache: true, lifetime: 60_000});
This profile, for example, has three executors chained:
- An instantaneous executor, that gets created with the profile.
- A bin executor, that merges together requests of different endpoints.
- A cache executor, that hashes requests and throws them in a cache.
They are called from the last to the first, so this requester will first look at the cache, then for an empty bin, then execute. You may specify default configurations for each executor, but they can also be overriden in the request itself.
const urgentRequest = await profile.request().send({defer: false});
const unlikelyToChange = await profile.request().send({cache: true, lifetime: 7_200_000})
Logging
You can specify a log callback, that gets a Date object, a query string and a node-fetch Response as parameters.
profile.log((log) => {
console.log("I was ran on ", log.date);
console.log("I tried to get", log.query);
console.log("I got", log.result);
});
Paginators
You can fetch until there are no more pages
const { tradeprices } = await profile.request()
.tradeprices({}, (t) => t.fields('food','date'))
.send();
await tradeprices.fetchAll();
Fetch until a callback returns false
const thisYear = '2022-01-01';
await tradeprices.fetchWhile((p) => p.lastItem?.date >= thisYear);
And then filter the results
const filtered = tradeprices.filter((t) => t.date >= thisYear);
Or fetch only the next page
await tradeprices.fetchMore();
The return type of these functions is a parsed version of paginator info
const p = await tradeprices.fetchMore();
console.log('The first price of food was', p.lastItem?.food);
That is also available in the first page
const p = tradeprices.info;
console.log('The last price of food was', p?.firstItem?.food);
You can also send executor options to these functions
await tradeprices.fetchAll({defer:false});
await tradeprices.fetchWhile(() => false, {defer:false});
await tradeprices.fetchMore({defer:false});
And then you use your result as you wish
tradeprices.forEach((d) => console.log('Food was',d.food,'on',d.date));
Writing an Executor
To create an executor you must import a few types
import { Executor, RequesterProfile, BaseRequest, Types } from 'pnw-rexec';
type Query = Types.Query;
Then you declare your config type
interface MyOptions {...}
Then create an executor class
class MyExecutor<O> implements Executor<MyOptions & O> {
config: RequesterProfile<MyOptions & O>;
executor: Executor<O>;
defaultOptions: MyOptions & O;
}
config
is the profile that created your executor
executor
is the next executor down the line
defaultOptions
is an object that merges executor previous
Now we need a constructor
constructor(
config: RequesterProfile<O & MyOptions>,
executor: Executor<O>,
options: MyOptions & O
) {
this.config = config;
this.executor = executor;
this.defaultOptions = options;
}
And a push()
method, where you do your stuff and send the request.
async push<R>(
requests: [keyof Query, BaseRequest<any, any>][],
options?: O & MyOptions
): Promise<R> {
// DoStuff
// ...
// Send
const res = await this.executor.push(requests, options);
return res as R;
}
To use your executor, you attach it to a profile like so
const profile = new RequesterProfile().executor(MyExecutor, {});
And that's it
Credits
This package was created by the tech team at Rose.
The basic types were generated with help from GraphQL Code Generator.