Using Go (Golang) net/http
To use the CubeMaster API, you need an API key (TokenID) for authentication. Here's how to get started:
TokenID (e.g., abc123xyz789). Copy this key and store it securely, as it will be used in the HTTP headers of your API requests.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 applications to communicate over the internet using standard HTTP methods. Here’s a quick breakdown:
GET: Retrieve data.POST: Send data to create something (used in this guide).PUT: Update data.DELETE: Remove data.https://api.cubemaster.net/loads define where to send requests.200 OK (success) or 401 Unauthorized (authentication failed).In this guide, we’ll use a POST request to send load data to the CubeMaster API and receive a response with loading details.
Ensure you have Go installed and set up:
go version (e.g., go1.21.0).mkdir cubemaster-api && cd cubemaster-api.go mod init cubemaster-api.net/http library.Create a file named main.go to write your code.
Assume your customer’s legacy database stores order or shipment data (e.g., items, quantities, dimensions). Here’s how to fetch and map it to the API request:
package main
import (
"database/sql"
_ "github.com/go-sql-driver/mysql" // Example: MySQL driver
"log"
)
type Item struct {
Name string
Length float64
Width float64
Height float64
Weight float64
Qty int
Color string
}
func fetchItemsFromDB() ([]Item, error) {
db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/legacy_db")
if err != nil {
return nil, err
}
defer db.Close()
rows, err := db.Query("SELECT name, length, width, height, weight, qty, color FROM shipments")
if err != nil {
return nil, err
}
defer rows.Close()
var items []Item
for rows.Next() {
var item Item
if err := rows.Scan(&item.Name, &item.Length, &item.Width, &item.Height, &item.Weight, &item.Qty, &item.Color); err != nil {
return nil, err
}
items = append(items, item)
}
return items, nil
}
This example uses a MySQL database. Adjust the driver and query based on your legacy system (e.g., PostgreSQL, SQLite). The retrieved data will be used in the API request.
Use net/http to build the POST request with the TokenID in the header and JSON payload:
package main
import (
"bytes"
"encoding/json"
"net/http"
"os"
)
type Cargo struct {
Name string `json:"Name"`
Length float64 `json:"Length"`
Width float64 `json:"Width"`
Height float64 `json:"Height"`
Weight float64 `json:"Weight"`
OrientationsAllowed string `json:"OrientationsAllowed"`
TurnAllowedOnFloor bool `json:"TurnAllowedOnFloor"`
Qty int `json:"Qty"`
ColorKnownName string `json:"ColorKnownName"`
}
type Container struct {
VehicleType string `json:"VehicleType"`
Name string `json:"Name"`
Length float64 `json:"Length"`
Width float64 `json:"Width"`
Height float64 `json:"Height"`
ColorKnownName string `json:"ColorKnownName"`
}
type Rules struct {
IsWeightLimited bool `json:"IsWeightLimited"`
IsSequenceUsed bool `json:"IsSequenceUsed"`
FillDirection string `json:"FillDirection"`
CalculationType string `json:"CalculationType"`
}
type LoadRequest struct {
Title string `json:"Title"`
Description string `json:"Description"`
Cargoes []Cargo `json:"Cargoes"`
Containers []Container `json:"Containers"`
Rules Rules `json:"Rules"`
}
func buildRequest() (*http.Request, error) {
// Fetch items from legacy database
items, err := fetchItemsFromDB()
if err != nil {
return nil, err
}
// Map database items to Cargoes
var cargoes []Cargo
for _, item := range items {
cargoes = append(cargoes, Cargo{
Name: item.Name,
Length: item.Length,
Width: item.Width,
Height: item.Height,
Weight: item.Weight,
OrientationsAllowed: "OrientationsAll",
TurnAllowedOnFloor: false,
Qty: item.Qty,
ColorKnownName: item.Color,
})
}
// Define the request payload
payload := LoadRequest{
Title: "New Mixed Truck Load",
Description: "Hello Web API",
Cargoes: cargoes,
Containers: []Container{
{
VehicleType: "Dry",
Name: "53FT-Intermodal",
Length: 630,
Width: 98,
Height: 106,
ColorKnownName: "Blue",
},
},
Rules: Rules{
IsWeightLimited: true,
IsSequenceUsed: false,
FillDirection: "FrontToRear",
CalculationType: "MixLoad",
},
}
// Marshal to JSON
jsonData, err := json.Marshal(payload)
if err != nil {
return nil, err
}
// Create the POST request
req, err := http.NewRequest("POST", "https://api.cubemaster.net/loads", bytes.NewBuffer(jsonData))
if err != nil {
return nil, err
}
// Set headers
req.Header.Set("Content-Type", "application/json")
req.Header.Set("TokenID", os.Getenv("CUBEMASTER_TOKENID")) // Load TokenID from environment
return req, nil
}
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"
}
}
Execute the HTTP request using http.DefaultClient.Do and unmarshal the JSON response into structs:
package main
import (
"encoding/json"
"fmt"
"io"
"log"
"net/http"
)
type LoadSummary struct {
CargoesLoaded int `json:"cargoesLoaded"`
PiecesLoaded int `json:"piecesLoaded"`
VolumeLoaded float64 `json:"volumeLoaded"`
WeightLoaded float64 `json:"weightLoaded"`
ContainersLoaded int `json:"containersLoaded"`
}
type Images struct {
Path3DDiagram string `json:"path3DDiagram"`
PathComposite string `json:"pathComposite"`
}
type Graphics struct {
Images Images `json:"images"`
}
type FilledContainer struct {
Name string `json:"name"`
Sequence int `json:"sequence"`
Graphics Graphics `json:"graphics"`
}
type LoadResponse struct {
Status string `json:"status"`
Message string `json:"message"`
CalculationError string `json:"calculationError"`
LoadSummary LoadSummary `json:"loadSummary"`
FilledContainers []FilledContainer `json:"filledContainers"`
}
func main() {
req, err := buildRequest()
if err != nil {
log.Fatalf("Error building request: %v", err)
}
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Fatalf("Error sending request: %v", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatalf("Error reading response: %v", err)
}
if resp.StatusCode != http.StatusOK {
log.Fatalf("API request failed with status: %s, body: %s", resp.Status, string(body))
}
var loadResp LoadResponse
if err := json.Unmarshal(body, &loadResp); err != nil {
log.Fatalf("Error unmarshaling response: %v", err)
}
fmt.Printf("Status: %s\n", loadResp.Status)
fmt.Printf("Message: %s\n", loadResp.Message)
fmt.Printf("Cargoes Loaded: %d\n", loadResp.LoadSummary.CargoesLoaded)
fmt.Printf("Volume Loaded: %.2f\n", loadResp.LoadSummary.VolumeLoaded)
fmt.Printf("Weight Loaded: %.2f\n", loadResp.LoadSummary.WeightLoaded)
if len(loadResp.FilledContainers) > 0 {
fmt.Printf("3D Diagram: %s\n", loadResp.FilledContainers[0].Graphics.Images.Path3DDiagram)
}
}
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",
"calculationTimeInSeconds": 0.6152743,
"createdBy": "CHANG@LOGEN.CO.KR"
},
"loadSummary": {
"cargoesLoaded": 68,
"piecesLoaded": 68,
"volumeLoaded": 5261723.4606,
"weightLoaded": 42674.59999999999,
"containersLoaded": 1
},
"filledContainers": [
{
"name": "#1 53FT-Intermodal",
"sequence": 1,
"graphics": {
"images": {
"path3DDiagram": "https://api.cubemaster.net/runtimes/b28413ca_51ed_44c9_b92e_13147363fd61.PNG"
}
}
}
]
}
Techniques for monitoring and debugging your API integration in Go:
log package (e.g., log.Printf) to print request and response details.log/slog for JSON log output:import "log/slog"
slog.Info("Sending API request", "url", req.URL.String())
slog.Info("Response received", "status", resp.Status)
net/http/httputil to inspect raw HTTP traffic:import "net/http/httputil"
dump, _ := httputil.DumpRequestOut(req, true)
fmt.Println(string(dump))