Implementing Your Methods

The purpose of developing a ShipEngine Connect application is to provide a communication layer between your backend API or service and our suite of e-commerce solutions where end users can utilize your services. You will provide the integration with your backend API or service when you implement the methods generated by the connect initcommand.

Every ShipEngine Connect application provides methods that correspond to the services offered through the API or service with which you are integrating. During the course of your application development, you will likely need to map data from your data model to match what ShipEngine Connect expects. Your method will receive data from ShipEngine Connect that it will then need to transform into the required format before passing it along to the backend service or API. Likewise, your backend API or service will return data that will then need to be transformed into the format expected by ShipEngine Connect before returning it from the method.

Each method will generally have the following structure and flow:

  1. Validate the incoming information from ShipEngine Connect.
  2. Map the data passed to your method by ShipEngine Connect to the data structure needed by the backend API or service for which your application provides the integration.
  3. Call the the backend API or service for which your application provides the integration.
  4. Map the response from your backend API or service to the data structure expected by ShipEngine Connect and return it from the method.

Example

Let's look at an example implementation of the createShipment method.

The following block of code shows the method taking a shipment argument, which is a NewShipment object, and does the following:

  1. Transforms the data passed to the method by ShipEngine Connect into the structure expected by the backend API. For example, the backend API we are calling expects a property called confirmation_code. We extract this value from the package.deliveryConfirmation.code property of the shipment object that was passed to this method from ShipEngine Connect.
  2. Calls the backend API or service. In this example, we are calling a REST API for a carrier service and passing the data object we created in step 1.
  3. Takes the response from the backend API and calls the formatShipment method to transform the carrier's label creation response into the format that ShipEngine Connect expects. For example, ShipEngine Connect requires the return object to contain a property called trackingNumber which we extract from the tracking_number property of the response object returned from the backend API call performed in step 2.
import { NewShipment, ShipmentConfirmation, Transaction } from "@shipengine/connect";
/**
* Generates a shipping label and tracking number for a shipment
*/
export default async function createShipment(
transaction: Transaction<Session>, shipment: NewShipment): Promise<ShipmentConfirmation> {
// STEP 1: Create the data that the carrier's API expects
let data: GenerateLabelRequest = {
operation: "generate_label",
session_id: transaction.session.id,
service_code: shipment.deliveryService.code,
confirmation_code: shipment.deliveryConfirmation.code,
ship_date: shipment.shipDateTime.toISOString(),
from_zone: parseInt(shipment.shipFrom.postalCode, 10),
to_zone: parseInt(shipment.shipTo.postalCode, 10),
total_weight: shipment.package.weight.ounces,
};
// STEP 2: Call the carrier's API
const response = await apiClient.request<GenerateLabelResponse>({ data });
// STEP 3: Create the output data that ShipEngine expects
return formatShipment(response.data);
}
/**
* Formats a shipment in the way ShipEngine expects
*/
function formatShipment(response: GenerateLabelResponse): ShipmentConfirmation {
return {
trackingNumber: response.tracking_number,
deliveryDateTime: response.delivery_date,
charges: [
{
type: ChargeType.Shipping,
amount: {
value: response.shipment_cost,
currency: "USD",
}
},
{
type: ChargeType.DeliveryConfirmation,
amount: {
value: response.confirmation_cost,
currency: "USD",
}
},
{
type: ChargeType.LocationFee,
amount: {
value: response.location_cost,
currency: "USD",
}
},
],
packages: [{
trackingNumber: response.tracking_number,
documents: [
{
name: "Shipping Label",
type: DocumentType.Label,
size: DocumentSize.Inches4x6,
format: DocumentFormat.PDF,
data: Buffer.from(response.image, "base64"),
}
]
}],
};
}
/**
* Generates a shipping label and tracking number for a shipment
*/
async function createShipment(transaction, shipment) {
// STEP 1: Create the data that the carrier's API expects
let data = {
operation: "generate_label",
session_id: transaction.session.id,
service_code: shipment.deliveryService.code,
confirmation_code: shipment.deliveryConfirmation.code,
ship_date: shipment.shipDateTime.toISOString(),
from_zone: parseInt(shipment.shipFrom.postalCode, 10),
to_zone: parseInt(shipment.shipTo.postalCode, 10),
total_weight: shipment.package.weight.ounces,
};
// STEP 2: Call the carrier's API
const response = await apiClient.request({ data });
// STEP 3: Create the output data that ShipEngine expects
return await formatShipment(response.data);
}
/**
* Formats a shipment in the way ShipEngine expects
*/
async function formatShipment(response) {
return {
trackingNumber: response.tracking_number,
deliveryDateTime: response.delivery_date,
charges: [
{
type: "shipping",
amount: {
value: response.shipment_cost,
currency: "USD"
}
},
{
type: "delivery_confirmation",
amount: {
value: response.confirmation_cost,
currency: "USD"
}
},
{
type: "location_fee",
amount: {
value: response.location_cost,
currency: "USD"
}
},
],
packages: [{
trackingNumber: response.tracking_number,
documents: [
{
name: "Label",
type: "label",
size: "letter",
data: await downloadLabel(response.image_url),
}
]
}],
};
}
/**
* Downloads a label image
*/
async function downloadLabel(imageUrl) {
let response = await axios.get(imageUrl);
return Buffer.from(response.data, "utf-8")
}