Skip to content

feat(Client): add apiResponse and apiRequest events #6739

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"@discordjs/collection": "^0.2.1",
"@discordjs/form-data": "^3.0.1",
"@sapphire/async-queue": "^1.1.5",
"@types/node-fetch": "^2.5.12",
"@types/ws": "^8.2.0",
"discord-api-types": "^0.23.1",
"node-fetch": "^2.6.1",
Expand Down
63 changes: 62 additions & 1 deletion src/rest/RequestHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const DiscordAPIError = require('./DiscordAPIError');
const HTTPError = require('./HTTPError');
const RateLimitError = require('./RateLimitError');
const {
Events: { DEBUG, RATE_LIMIT, INVALID_REQUEST_WARNING },
Events: { DEBUG, RATE_LIMIT, INVALID_REQUEST_WARNING, API_RESPONSE, API_REQUEST },
} = require('../util/Constants');
const Util = require('../util/Util');

Expand Down Expand Up @@ -162,6 +162,34 @@ class RequestHandler {
}
this.manager.globalRemaining--;

/**
* Represents a request that will or has been made to the Discord API
* @typedef {Object} APIRequest
* @property {HTTPMethod} method The HTTP method used in this request
* @property {string} path The full path used to make the request
* @property {string} route The API route identifying the ratelimit for this request
* @property {Object} options Additional options for this request
* @property {number} retries The number of times this request has been attempted
*/

if (this.manager.client.listenerCount(API_REQUEST)) {
/**
* Emitted before every API request.
* This event can emit several times for the same request, e.g. when hitting a rate limit.
* <info>This is an informational event that is emitted quite frequently,
* it is highly recommended to check `request.path` to filter the data.</info>
* @event Client#apiRequest
* @param {APIRequest} request The request that is about to be sent
*/
this.manager.client.emit(API_REQUEST, {
method: request.method,
path: request.path,
route: request.route,
options: request.options,
retries: request.retries,
});
}

// Perform the request
let res;
try {
Expand All @@ -176,6 +204,29 @@ class RequestHandler {
return this.execute(request);
}

if (this.manager.client.listenerCount(API_RESPONSE)) {
/**
* Emitted after every API request has received a response.
* This event does not necessarily correlate to completion of the request, e.g. when hitting a rate limit.
* <info>This is an informational event that is emitted quite frequently,
* it is highly recommended to check `request.path` to filter the data.</info>
* @event Client#apiResponse
* @param {APIRequest} request The request that triggered this response
* @param {Response} response The response received from the Discord API
*/
this.manager.client.emit(
API_RESPONSE,
{
method: request.method,
path: request.path,
route: request.route,
options: request.options,
retries: request.retries,
},
res.clone(),
);
}

let sublimitTimeout;
if (res.headers) {
const serverDate = res.headers.get('date');
Expand Down Expand Up @@ -315,3 +366,13 @@ class RequestHandler {
}

module.exports = RequestHandler;

/**
* @external HTTPMethod
* @see {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods}
*/

/**
* @external Response
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Response}
*/
2 changes: 2 additions & 0 deletions src/util/Constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ exports.Opcodes = {
exports.Events = {
RATE_LIMIT: 'rateLimit',
INVALID_REQUEST_WARNING: 'invalidRequestWarning',
API_RESPONSE: 'apiResponse',
API_REQUEST: 'apiRequest',
CLIENT_READY: 'ready',
APPLICATION_COMMAND_CREATE: 'applicationCommandCreate',
APPLICATION_COMMAND_DELETE: 'applicationCommandDelete',
Expand Down
13 changes: 13 additions & 0 deletions typings/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import {
import { ChildProcess } from 'node:child_process';
import { EventEmitter } from 'node:events';
import { AgentOptions } from 'node:https';
import { Response } from 'node-fetch';
import { Stream } from 'node:stream';
import { MessagePort, Worker } from 'node:worker_threads';
import * as WebSocket from 'ws';
Expand Down Expand Up @@ -3129,6 +3130,14 @@ export interface APIErrors {
STICKER_ANIMATION_DURATION_EXCEEDS_MAXIMUM_OF_5_SECONDS: 170007;
}

export interface APIRequest {
method: 'get' | 'post' | 'delete' | 'patch' | 'put';
options: unknown;
path: string;
retries: number;
route: string;
}

export interface ApplicationAsset {
name: string;
id: Snowflake;
Expand Down Expand Up @@ -3439,6 +3448,8 @@ export interface ChannelWebhookCreateOptions {
}

export interface ClientEvents {
apiResponse: [request: APIRequest, response: Response];
apiRequest: [request: APIRequest];
applicationCommandCreate: [command: ApplicationCommand];
applicationCommandDelete: [command: ApplicationCommand];
applicationCommandUpdate: [oldCommand: ApplicationCommand | null, newCommand: ApplicationCommand];
Expand Down Expand Up @@ -3677,6 +3688,8 @@ export interface ConstantsColors {
export interface ConstantsEvents {
RATE_LIMIT: 'rateLimit';
INVALID_REQUEST_WARNING: 'invalidRequestWarning';
API_RESPONSE: 'apiResponse';
API_REQUEST: 'apiRequest';
CLIENT_READY: 'ready';
APPLICATION_COMMAND_CREATE: 'applicationCommandCreate';
APPLICATION_COMMAND_DELETE: 'applicationCommandDelete';
Expand Down