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 init
command.
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:
- Validate the incoming information from ShipEngine Connect.
- 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.
- Call the the backend API or service for which your application provides the integration.
- 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:
- 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 thepackage.deliveryConfirmation.code
property of theshipment
object that was passed to this method from ShipEngine Connect. - 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. - 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 calledtrackingNumber
which we extract from thetracking_number
property of theresponse
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")}