Step-by-Step Guide to Consume CubeMaster API with AWS

Learn how to integrate the CubeMaster API (https://api.cubemaster.net/loads) using AWS Lambda and other services.

To use the CubeMaster API, you need an API key (TokenID) for authentication. Here's how to get started:

  1. Visit the CubeMaster website: https://cubemaster.net.
  2. Locate the "Sign In" option (typically found in the top-right corner).
  3. Fill out the registration form with your details (e.g., name, email, password, company information).
  4. After signing up, log in to your account dashboard.
  5. Navigate to the "Settings" - "Integration" section to generate your API key (TokenID).
  6. Generate an API key. Once generated, you’ll receive a unique TokenID (e.g., abc123xyz789). Copy this key and store it securely, as it will be used in the HTTP headers of your API requests.
  7. Copy the TokenID and store it securely.

Note: The TokenID will be used in the HTTP headers of your POST request for authentication.

A RESTful API (Representational State Transfer) is a way for systems to communicate over the internet using standard HTTP methods like GET, POST, PUT, and DELETE. Here’s a quick breakdown:

  • Endpoint: A specific URL (e.g., https://api.cubemaster.net/loads) where the API can be accessed.
  • HTTP Methods: Actions you can perform:
    • POST: Create a new resource (e.g., build a load in CubeMaster).
    • GET: Retrieve data.
  • JSON: A lightweight data format used to send and receive information (e.g., your request and response data).
  • Headers: Metadata sent with the request, like the TokenID for authentication.

In this guide, we’ll use the POST method to send a JSON payload to https://api.cubemaster.net/loads to build a load.

You’ll use AWS Lambda to make the API call. Here’s how to set it up:

  1. Log in to the AWS Management Console.
  2. In the top search bar, type "Lambda" and select Lambda from the "Services" results.
  3. Click the orange Create function button on the Lambda dashboard.
  4. Choose Author from scratch, then:
    • Function name: Enter "CubeMasterLoadBuilder".
    • Runtime: Select "Node.js 18.x" (or Python 3.9 if preferred).
    • Click Create function at the bottom.
  5. You’ll land on the function’s configuration page with tabs like Code, Deploy, and Configuration.

Assume your customer’s orders or shipments data is stored in a legacy database (e.g., MySQL on AWS RDS). Here’s how to fetch it:

  1. In the AWS Console, search for RDS and select it.
  2. Click on your database instance, then note the Endpoint (e.g., my-db-instance.xxx.us-east-1.rds.amazonaws.com) and Port.
  3. Use AWS Lambda to query the database. Add the "mysql" package:
    • In the Lambda function’s Code tab, scroll to the terminal at the bottom.
    • Run: npm install mysql (for Node.js).
  4. Update your Lambda code to query orders (example in Node.js):
    const mysql = require('mysql');
    const connection = mysql.createConnection({
        host: 'my-db-instance.xxx.us-east-1.rds.amazonaws.com',
        user: 'admin',
        password: 'yourpassword',
        database: 'legacy_db'
    });
    
    exports.handler = async (event) => {
        return new Promise((resolve, reject) => {
            connection.query('SELECT name, length, width, height, weight, qty FROM shipments', (err, results) => {
                if (err) reject(err);
                resolve(results); // e.g., [{name: "ITEM001", length: 72, width: 30, height: 75, weight: 1002.45, qty: 16}, ...]
            });
        });
    };
  5. Map this data to the CubeMaster API’s Cargoes array format in the next step.

Now, integrate the database data into the API request and send it to CubeMaster:

  1. In the Lambda Code tab, install the axios package for HTTP requests:
    npm install axios
  2. Update your Lambda function to construct and send the request:
    const axios = require('axios');
    const mysql = require('mysql');
    
    const connection = mysql.createConnection({
        host: 'my-db-instance.xxx.us-east-1.rds.amazonaws.com',
        user: 'admin',
        password: 'yourpassword',
        database: 'legacy_db'
    });
    
    exports.handler = async (event) => {
        const shipments = await new Promise((resolve, reject) => {
            connection.query('SELECT name, length, width, height, weight, qty FROM shipments', (err, results) => {
                if (err) reject(err);
                resolve(results);
            });
        });
    
        const requestBody = {
            "Title": "New Mixed Truck Load",
            "Description": "Hello Web API",
            "Cargoes": shipments.map(item => ({
                "Name": item.name,
                "Length": item.length,
                "Width": item.width,
                "Height": item.height,
                "Weight": item.weight,
                "OrientationsAllowed": "OrientationsAll",
                "TurnAllowedOnFloor": false,
                "Qty": item.qty,
                "ColorKnownName": "Brown" // Adjust as needed
            })),
            "Containers": [
                {
                    "VehicleType": "Dry",
                    "Name": "53FT-Intermodal",
                    "Length": 630,
                    "Width": 98,
                    "Height": 106,
                    "ColorKnownName": "Blue"
                }
            ],
            "Rules": {
                "IsWeightLimited": true,
                "IsSequenceUsed": false,
                "FillDirection": "FrontToRear",
                "CalculationType": "MixLoad"
            }
        };
    
        const response = await axios.post('https://api.cubemaster.net/loads', requestBody, {
            headers: {
                'TokenID': 'abc123xyz789', // Replace with your actual TokenID
                'Content-Type': 'application/json'
            }
        });
    
        return response.data;
    };
  3. Click Deploy in the Lambda UI to save your changes.
  4. Request JSON Example:
    {
        "Title": "New Mixed Truck Load",
        "Description": "Hello Web API",
        "Cargoes": [
            {
                "Name": "ITEM001",
                "Length": 72,
                "Width": 30,
                "Height": 75,
                "Weight": 1002.45,
                "OrientationsAllowed": "OrientationsAll",
                "TurnAllowedOnFloor": false,
                "Qty": 16,
                "ColorKnownName": "Brown"
            },
            {
                "Name": "ITEM002",
                "Length": 27.31,
                "Width": 37.5,
                "Height": 76.67,
                "Weight": 521.45,
                "OrientationsAllowed": "OrientationsAll",
                "TurnAllowedOnFloor": false,
                "Qty": 28,
                "ColorKnownName": "Aqua"
            },
            {
                "Name": "SKU0005",
                "Length": 27.31,
                "Width": 9.5,
                "Height": 75.67,
                "Weight": 501.45,
                "OrientationsAllowed": "OrientationsAll",
                "TurnAllowedOnFloor": true,
                "Qty": 24,
                "ColorKnownName": "Beige"
            },
            {
                "Name": "SKU0005",
                "Qty": 23
            },
            {
                "Name": "SKU0008",
                "Qty": 34
            }
        ],
        "Containers": [
            {
                "VehicleType": "Dry",
                "Name": "53FT-Intermodal",
                "Length": 630,
                "Width": 98,
                "Height": 106,
                "ColorKnownName": "Blue"
            }
        ],
        "Rules": {
            "IsWeightLimited": true,
            "IsSequenceUsed": false,
            "FillDirection": "FrontToRear",
            "CalculationType": "MixLoad"
        }
    }

The API will return a detailed response. Here’s how to process it:

  1. Check the status field:
    • If "succeed", proceed to extract data.
    • If not, log the message and calculationError for debugging.
  2. Extract key data like loadSummary (e.g., cargoesLoaded, volumeLoaded) and filledContainers (e.g., volumeUtilization).
  3. Save the response to Amazon S3 for record-keeping:
    • In the AWS Console, search for S3, create a bucket (e.g., "cubemaster-responses").
    • Update your Lambda code to use the AWS SDK:
      const AWS = require('aws-sdk');
      const s3 = new AWS.S3();
      
      exports.handler = async (event) => {
          // ... (previous code for API call)
          const responseData = response.data;
      
          if (responseData.status === 'succeed') {
              await s3.putObject({
                  Bucket: 'cubemaster-responses',
                  Key: `load-${Date.now()}.json`,
                  Body: JSON.stringify(responseData),
                  ContentType: 'application/json'
              }).promise();
          } else {
              console.error('Error:', responseData.message, responseData.calculationError);
          }
      
          return responseData;
      };
  4. Response JSON Example:
    {
        "status": "succeed",
        "message": "Engine created. 5 cargoes. 1 empty containers. Calculation started. Calculation ended. The load built successfully. The load saved to the cloud database.",
        "calculationError": "InvalidCargoSize",
        "document": {
            "title": "New Mixed Truck Load",
            "description": "Hello Web API",
            "isShared": true,
            "isAutoSaved": true,
            "isPending": false,
            "calculationTimeInSeconds": 0.6152743,
            "processId": "",
            "batchId": "",
            "createdBy": "CHANG@LOGEN.CO.KR",
            "createdAt": "2023-02-11T01:17:01.7392204+09:00",
            "updatedAt": "0001-01-01T00:00:00"
        },
        "loadSummary": {
            "cargoesLoaded": 68,
            "piecesLoaded": 68,
            "cargoesLeft": 0,
            "piecesLeft": 57,
            "unitloadsLoaded": 0,
            "volumeLoaded": 5261723.4606,
            "weightLoaded": 42674.59999999999,
            "priceLoaded": 0,
            "containersLoaded": 1
        },
        "filledContainers": [
            {
                "name": "#1 53FT-Intermodal",
                "sequence": 1,
                "loadSummary": {
                    "cargoesLoaded": 68,
                    "piecesLoaded": 68,
                    "unitloadsLoaded": 0,
                    "volumeLoaded": 5261723.4606,
                    "volumeUtilization": 80.39990374424703,
                    "vollumeUtilizationToLoadHeight": 81.03441853085657,
                    "floorLoaded": 57090.75,
                    "floorUtilization": 92.46963070942662,
                    "weightLoaded": 42674.59999999999,
                    "weightTotal": 42674.59999999999,
                    "weightUtilization": 0,
                    "dimWeight": 39424.33734939759,
                    "priceLoaded": 0,
                    "pricetUtilization": 0,
                    "cargoesPerLayer": 14,
                    "layersPerUnitload": 0
                },
                "actualSize": {
                    "length": 630,
                    "width": 98,
                    "height": 106
                },
                "loadSize": {
                    "length": 625.6499999999999,
                    "width": 97.5,
                    "height": 105.17
                },
                "cog": {
                    "length": 0,
                    "width": 0,
                    "height": 0
                },
                "emptyContainer": {
                    "containerType": "SeaVan",
                    "vehicleType": "Dry",
                    "palletType": "Wood2WaysDoube",
                    "cartonType": "Tuck",
                    "qty": 0,
                    "length": 630,
                    "width": 98,
                    "height": 106,
                    "emptyWeight": 0,
                    "maxLength": 0,
                    "maxWidth": 0,
                    "maxHeight": 0,
                    "maxWeight": 0,
                    "palletThickness": 0,
                    "maxVolPercent": 0,
                    "name": "53FT-Intermodal",
                    "alias": "",
                    "priority": 0,
                    "maxCargoTypes": 0,
                    "color": 16711680,
                    "colorHexaCode": "",
                    "colorKnownName": "",
                    "palletOverhang": false,
                    "palletOvarhangLength": 0,
                    "palletOvarhangWidth": 0,
                    "palletUnderhang": false,
                    "palletUnderhangLength": 0,
                    "palletUnderhangWidth": 0,
                    "zones": null,
                    "vehicleDropDeckRearSize": null,
                    "vehicleDropDeckFrontSize": null,
                    "price": 0,
                    "maxPrice": 0
                },
                "graphics": {
                    "images": {
                        "path3DDiagram": "https://api.cubemaster.net/runtimes/b28413ca_51ed_44c9_b92e_13147363fd61.PNG",
                        "path2DBottom": "https://api.cubemaster.net/runtimes/3fddce14_5ac2_4db5_99b5_844e1e13fcec.PNG",
                        "path2DTop": "https://api.cubemaster.net/runtimes/e67b3f31_9280_4995_94be_4f577b7e39cc.PNG",
                        "path2DLeft": "https://api.cubemaster.net/runtimes/3a5db539_3c87_4068_bd68_fe5a3ebc7e6e.PNG",
                        "path2DRight": "https://api.cubemaster.net/runtimes/a3e1e15b_9ab5_48e6_a472_3b9a27124853.PNG",
                        "path2DRear": "https://api.cubemaster.net/runtimes/5c919834_4d98_4826_9271_87d9e52850f2.PNG",
                        "path2DFront": "https://api.cubemaster.net/runtimes/266765b7_f48e_4fcb_b381_d58be2959e93.PNG",
                        "pathComposite": "https://api.cubemaster.net/runtimes/7eb09974_2f1d_41bc_9371_2002658dce07.PNG"
                    }
                }
            }
        ]
    }

Use AWS CloudWatch to monitor and debug your API calls:

  1. In the AWS Console, search for CloudWatch and select it.
  2. Go to Logs > Log groups, find /aws/lambda/CubeMasterLoadBuilder.
  3. Click the log group, then select a log stream to view logs. Look for:
    • Success messages (e.g., API response data).
    • Errors (e.g., InvalidCargoSize from calculationError).
  4. Set up metrics:
    • In CloudWatch, go to Metrics > All metrics.
    • Filter by Lambda, select your function, and monitor Invocations, Errors, and Duration.
  5. Test your function:
    • In the Lambda UI, click Test, create a test event (e.g., empty JSON {}), and run it.
    • Review the execution results and logs in the UI.