ExpressJs SDK Guide
To integrate your ExpressJs application with APItoolkit, you need to use this SDK to monitor incoming traffic, aggregate the requests, and then send them to APItoolkit's servers. Kindly follow this guide to get started and learn about all the supported features of APItoolkit's ExpressJs SDK.
Prerequisites
Ensure you have already completed the first three steps of the onboarding guide.
Installation
Kindly run the command below to install the SDK:
npm install apitoolkit-express
# Or
yarn add apitoolkit-express
Configuration
Next, initialize APItoolkit in your application's entry point (e.g., index.js
), like so:
import { APIToolkit } from "apitoolkit-express";
import express from "express";
import axios from "axios";
const app = express();
const port = 3000;
// IMPORTANT: apitoolkitClient must be declared
// BEFORE all controllers and middleware in your application.
const apitoolkitClient = APIToolkit.NewClient({
apiKey: "{ENTER_YOUR_API_KEY_HERE}",
debug: false,
tags: ["environment: production", "region: us-east-1"],
serviceVersion: "v2.0",
ignoreEndpoints: ["/products", "POST /categories", "GET /user/:name"],
});
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(apitoolkitClient.expressMiddleware);
app.get("/", (req, res) => {
res.json({ hello: "Hello world!" });
});
// IMPORTANT: apitoolkitClient.errorHandler must be declared
// AFTER declaring apitoolkitClient.expressMiddleware
// and all controllers and BEFORE any other error middleware.
app.use(apitoolkitClient.errorHandler);
app.listen(port, () => console.log("App running on port: " + port));
const express = require("express");
const APIToolkit = require("apitoolkit-express").default;
const app = express();
const port = 3000;
// IMPORTANT: apitoolkitClient must be declared
// BEFORE all controllers and middleware in your application.
const apitoolkitClient = APIToolkit.NewClient({
apiKey: "{ENTER_YOUR_API_KEY_HERE}",
debug: false,
tags: ["environment: production", "region: us-east-1"],
serviceVersion: "v2.0",
ignoreEndpoints: ["/products", "POST /categories", "GET /user/:name"],
});
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(apitoolkitClient.expressMiddleware);
app.get("/", (req, res) => {
res.json({ hello: "Hello world!" });
});
// IMPORTANT: apitoolkitClient.errorHandler must be declared
// AFTER declaring apitoolkitClient.expressMiddleware
// and all controllers and BEFORE any other error middleware.
app.use(apitoolkitClient.errorHandler);
app.listen(port, () => {
console.log("App running on port: " + port);
});
In the configuration above, only the apiKey
option is required, but you can add the following optional fields:
Option | Description |
---|---|
debug | Set to true to enable debug mode. |
tags | A list of defined tags for your services (used for grouping and filtering data on the dashboard). |
serviceVersion | A defined string version of your application (used for further debugging on the dashboard). |
ignoreEndpoints | A list of endpoints that should not be captured. |
redactHeaders | A list of HTTP header keys to redact. |
redactResponseBody | A list of JSONPaths from the request body to redact. |
redactRequestBody | A list of JSONPaths from the response body to redact. |
Tip
The {ENTER_YOUR_API_KEY_HERE}
demo string should be replaced with the API key generated from the APItoolkit dashboard.
Warning
apitoolkitClient
must be declared BEFORE all controllers and middleware in your application.apitoolkitClient.errorHandler
must be declared AFTERapitoolkitClient.expressMiddleware
and all other controllers and BEFORE any other error middleware.
Redacting Sensitive Data
If you have fields that are sensitive and should not be sent to APItoolkit servers, you can mark those fields to be redacted (the fields will never leave your servers).
To mark a field for redacting via this SDK, you need to add some additional arguments to the apitoolkitClient
configuration object with paths to the fields that should be redacted. There are three arguments you can provide to configure what gets redacted, namely:
redactHeaders
: A list of HTTP header keys.redactRequestBody
: A list of JSONPaths from the request body.redactResponseBody
: A list of JSONPaths from the response body.
JSONPath is a query language used to select and extract data from JSON files. For example, given the following sample user data JSON object:
{
"user": {
"name": "John Martha",
"email": "[email protected]",
"addresses": [
{
"street": "123 Main St",
"city": "Anytown",
"state": "CA",
"zip": "12345"
},
{
"street": "123 Main St",
"city": "Anytown",
"state": "CA",
"zip": "12345"
}
],
"credit_card": {
"number": "4111111111111111",
"expiration": "12/28",
"cvv": "123"
}
}
}
Examples of valid JSONPath expressions would be:
JSONPath | Description |
---|---|
$.user.addresses[*].zip | In this case, APItoolkit will replace the zip field in all the objects of the addresses list inside the user object with the string [CLIENT_REDACTED] . |
$.user.credit_card | In this case, APItoolkit will replace the entire credit_card object inside the user object with the string [CLIENT_REDACTED] . |
Tip
To learn more about JSONPaths, please take a look at the official docs or use this JSONPath Evaluator to validate your JSONPath expressions.
You can also use our JSON Redaction Tool to preview what the final data sent from your API to APItoolkit will look like, after redacting any given JSON object.
Here's an example of what the configuration would look like with redacted fields:
import express from "express";
import { APIToolkit } from "apitoolkit-express";
const app = express();
const port = 3000;
const startServer = async () => {
const apiKey = "{ENTER_YOUR_API_KEY_HERE}";
const redactHeaders = ["content-type", "Authorization", "HOST"];
const redactRequestBody = ["$.user.email", "$.user.addresses"];
const redactResponseBody = ["$.users[*].email", "$.users[*].credit_card"];
const apitoolkitClient = await APIToolkit.NewClient({
apiKey,
redactHeaders,
redactRequestBody,
redactResponseBody,
});
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(apitoolkitClient.expressMiddleware);
app.get("/", (req, res) => {
res.send("Hello World!");
});
app.use(apitoolkitClient.errorHandler);
app.listen(port, () => {
console.log("App running on port " + port);
});
};
startServer();
Note
- The
redactHeaders
config field expects a list of case-insensitive headers as strings. - The
redactRequestBody
andredactResponseBody
config fields expect a list of JSONPaths as strings. - The list of items to be redacted will be applied to all endpoint requests and responses on your server.
Handling File Uploads
If you handling file uploads in your application using a framework, you might need to add some extra configuration to ensure that the request object contains all the parsed data, enabling accurate monitoring of file uploads across your application.
Working with file uploads using multer for example requires no extra work since the parsed data (fields
and files
) are attached to the request object in multipart/form-data requests. However, if you're using formidable, you need to attach the parsed data yourself to ensure accurate monitoring. Here's an example:
import express from "express";
import { APIToolkit } from "apitoolkit-express";
import formidable from "formidable";
const app = express();
const port = 3000;
const client = APIToolkit.NewClient({
apiKey: "{ENTER_YOUR_API_KEY_HERE}",
});
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(client.expressMiddleware);
app.post("/upload-formidable", (req, res, next) => {
const form = formidable({});
form.parse(req, (err, fields, files) => {
// Attach fields to request body
req.body = fields;
// Attach files to request body
req.files = files;
res.json({ message: "Uploaded successfully!" });
});
});
app.listen(port, () => {
console.log("App running on port " + port);
});
Error Reporting
With APItoolkit, you can track and report different unhandled or uncaught errors, API issues, and anomalies at different parts of your application. This will help you associate more detail and context from your backend with any failing customer request.
Tip Ensure to add the errorHandler
middleware immediately after your app's controllers, like so:import { APIToolkit, ReportError } from "apitoolkit-express";
import express from "express";
import axios from "axios";
const app = express();
const port = 3000;
const apitoolkitClient = APIToolkit.NewClient({
apiKey: "{ENTER_YOUR_API_KEY_HERE}",
});
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(apitoolkitClient.expressMiddleware);
// All controllers
app.get("/", (req, res) => {
// Controller logic here
});
// Other controllers...
// Add the error handler
// to automatically report all uncaught errors to APItoolkit
app.use(apitoolkitClient.errorHandler);
app.listen(port, () => {
console.log("App running on port " + port);
});
apitoolkitClient.errorHandler
after all controllers and before any other error middleware.ReportError()
function, passing in the error
argument, like so:import { APIToolkit, ReportError } from "apitoolkit-express";
import express from "express";
const app = express();
const port = 3000;
const apitoolkitClient = APIToolkit.NewClient({
apiKey: "{ENTER_YOUR_API_KEY_HERE}",
});
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(apitoolkitClient.expressMiddleware);
app.get("/", (req, res) => {
try {
throw new Error("Deliberate error");
res.send("Hello"); // This line will not be reached due to the error thrown above
} catch (error) {
// Report the error to APItoolkit
ReportError(error);
res.send("Something went wrong...");
}
});
app.listen(port, () => {
console.log("App running on port " + port);
});
Monitoring Outgoing Requests
Outgoing requests are external API calls you make from your API. By default, APItoolkit monitors all requests users make from your application and they will all appear in the API Log Explorer page. However, you can separate outgoing requests from others and explore them in the Outgoing Integrations page, alongside the incoming request that triggered them.
The The monitorAxios
to the apitoolkitClient
configuration options, like so:import APIToolkit from "apitoolkit-express";
import axios from "axios";
import express from "express";
const app = express();
const port = 3000;
const apitoolkitClient = APIToolkit.NewClient({
apiKey: "{ENTER_YOUR_API_KEY_HERE}",
monitorAxios: axios,
});
app.use(apitoolkitClient.expressMiddleware);
app.get("/", async (req, res) => {
// This outgoing axios request will be monitored
const response = await axios.get(baseURL + "users/123");
res.send(response.data);
});
app.listen(port, () => {
console.log("App running on port " + port);
});
observeAxios()
function, like so:import APIToolkit, { observeAxios } from "apitoolkit-express";
import axios from "axios";
import express from "express";
const app = express();
const port = 3000;
const apitoolkitClient = APIToolkit.NewClient({ apiKey: "{ENTER_YOUR_API_KEY_HERE}" });
app.use(apitoolkitClient.expressMiddleware);
app.get("/", async (req, res) => {
try {
const response = await observeAxios(axios).get(baseURL + "/users/user1234");
res.send(response.data);
} catch (error) {
console.error("Error occurred:", error);
res.status(500).send("Error occurred while fetching data");
}
});
app.listen(port, () => {
console.log("App running on port " + port);
});
observeAxios
function above accepts a required axios
instance and the following optional arguments:Option Description pathWildCard
The url_path
string for URLs with path parameters.redactHeaders
A list of HTTP header keys to redact. redactResponseBody
A list of JSONPaths from the request body to redact. redactRequestBody
A list of JSONPaths from the response body to redact. observeAxios
directly from apitoolkit-express
will not be available. Instead, call observeAxios
directly from apitoolkitClient
, like so:import axios from "axios";
import { APIToolkit } from "apitoolkit-express";
async function fetchData() {
const apitoolkitClient = APIToolkit.NewClient({
apiKey: "{ENTER_YOUR_API_KEY_HERE}",
});
try {
const response = await apitoolkitClient.observeAxios(axios).get("http://localhost:8080/ping");
console.log(response.data);
} catch (error) {
console.error("Error occurred:", error);
}
}
// Call the async function to execute the code
fetchData();
observeAxios
function above accepts a required axios
instance and the following optional arguments:Option Description pathWildCard
The url_path
for URLs with path parameters.redactHeaders
A list of HTTP header keys to redact. redactResponseBody
A list of JSONPaths from the request body to redact. redactRequestBody
A list of JSONPaths from the response body to redact.
Explore the ExpressJS SDK