Skip to main content

Platform Plugins

tip

This feature is currently in alpha. Drop us a line on slack if you are interested in using it.

Plugins can be used to create derived fields, check requests against a boolean expression or trigger a range of other activities.

Before building your first app it's important to keep a couple of points in mind:

  • Plugins run on all the events currently stored in Speakeasy.
  • Plugins will timeout if they take longer than 10ms per request.
  • It is currently not possible to chain multiple plugins together.

Let's look at how you can build a plugin.

edit plugin.

Defining a plugin

Scripts must include a function called handler. Code that exists outside of this function will also be called, but handler is the code that will be executed on the data.

// valid declaration
function handler(data) {
}

// also valid declaration
const handler = (data) => {
};

The data argument is always passed into handler. data is the full set of request & response data that is captured by Speakeasy. Here is the structure:

// note: typescript annotation is for documentation purposes; plugins do not currently accept typescript
type data = {
http: {
requestBody: any,
responseBody: any,
headers: { name: string, value: string }[],
queryParams: { name: string, value: string }[],
url: string,
info: {
apiId: string,
versionId: string,
endpointPath: string,
method: string,
path: string,
status: number,
requestStartTime: DateTime,
responseFinishTime: DateTime,
customerId: string,
createdAt: DateTime,
latency: number,
sdkLanguage: string,
sdkVersion: string,
sdkGenVersion: string
},
},
addMetadata: (key: string, value: string) => void
}

http

This represents the REST request ingested by the server-side sdk. In addition to the url, queryParams, headers, requestBody, and responseBody, the info object contains generic information about the REST request and information that may have been provided directly to Speakeasy during ingest (customerId and sdk-telemetry).

if the request (or the response body) is not valid json, requestBody (or responseBody) will be the

string-representation of the data

addMetadata

This function tags a request with a key-value pair. One key can be associated with multiple values (adding the same metadata twice will result in duplicate entries).

These key-value pairs are presented in the request-viewer as additional columns.

plugin output

Examples

Below is an example of how the plugin functionality can be used to enrich the data captured by Speakeasy with an additional column. In this case, we are flagging that an invalid or deprecated SDK version was used to call the API. This type of information can help transform raw API logs into something that can be shared with customer support teams to take further action:

Flag requests made with invalid sdk versions

const validSdkVersions = ["v2.0.0", "1.9.0"];
const deprecatedSdkVersions = ["v1.8.0", "v1.7.2", "v1.7.1", "v1.7.0"];

function handler(data) {
const sdkVersion = data.http.info.sdkVersion;
if (!sdkVersion) {
if (data.http.info.customerId) {
data.addMetadata(
"task",
`customer ${data.http.info.customerId} requesting without sdk`
);
return;
}
}

if (!validSdkVersions.includes(sdkVersion)) {
if (deprecatedSdkVersions.includes(sdkVersion)) {
data.addMetadata(
"task",
`customer ${data.http.info.customerId} using deprecated sdk`
);
} else {
data.addMetadata(
"task",
`custermer ${data.http.info.customerId} using invalid sdk`
);
}
}
}

It is possible to add multiple columns via a single plugin. In the following example, when there is a successful GET request that does not contain a response body, a column will be added to flag the error. When there is a request body, the length of the response body will be recorded.

Api tracking

const handler = ({http, addMetadata}) => {
if (http.info.method !== `GET` || http.info.endpointPath !== `/v1/apis`) {
return;
}

if (!http.responseBody) {
if (http.info.status === 200) {
addMetadata(`error`, `successful api request without response body`);
}
}
if (http.info.status === 200) {
addMetadata(`api_count`, http.responseBody.length);
}

const apis = http.responseBody
.map((api) => `${api.api_id}_${api.version_id}`)
.join(`,`);
addMetadata(`apis`, apis);
};