Hey there, fellow Go enthusiast! Ready to dive into the world of ShipStation API integration? You're in for a treat. ShipStation's API is a powerhouse for managing orders, shipments, and all things e-commerce. In this guide, we'll walk through building a robust integration that'll have you shipping like a pro in no time.
Before we jump in, make sure you've got:
Got those? Great! Let's get coding.
First things first, let's create a new Go module:
mkdir shipstation-integration cd shipstation-integration go mod init github.com/yourusername/shipstation-integration
Now, let's grab the dependencies we'll need:
go get github.com/go-resty/resty/v2
We're using resty
here because it makes HTTP requests a breeze. Feel free to use your favorite HTTP client if you prefer.
ShipStation uses API key and secret for authentication. Let's create a reusable client:
package main import ( "github.com/go-resty/resty/v2" ) type ShipStationClient struct { client *resty.Client } func NewShipStationClient(apiKey, apiSecret string) *ShipStationClient { client := resty.New() client.SetBasicAuth(apiKey, apiSecret) client.SetBaseURL("https://ssapi.shipstation.com") return &ShipStationClient{client: client} }
Now that we've got our client set up, let's make some requests!
func (c *ShipStationClient) GetOrders() ([]Order, error) { var response OrdersResponse _, err := c.client.R(). SetResult(&response). Get("/orders") return response.Orders, err }
func (c *ShipStationClient) CreateShipment(shipment Shipment) (CreatedShipment, error) { var response CreatedShipment _, err := c.client.R(). SetBody(shipment). SetResult(&response). Post("/shipments/createlabel") return response, err }
ShipStation returns JSON responses. Let's parse them and handle errors:
type APIError struct { Message string `json:"message"` Code int `json:"code"` } func (c *ShipStationClient) doRequest(method, endpoint string, body interface{}) ([]byte, error) { resp, err := c.client.R(). SetBody(body). Execute(method, endpoint) if err != nil { return nil, err } if resp.IsError() { var apiError APIError if err := json.Unmarshal(resp.Body(), &apiError); err != nil { return nil, fmt.Errorf("unknown error: %s", resp.String()) } return nil, fmt.Errorf("API error: %s (code: %d)", apiError.Message, apiError.Code) } return resp.Body(), nil }
Now that we've got the basics down, let's implement some key functionalities:
func (c *ShipStationClient) GetOrder(orderID string) (Order, error) { var order Order _, err := c.client.R(). SetResult(&order). Get("/orders/" + orderID) return order, err }
func (c *ShipStationClient) CreateShipment(shipment Shipment) (CreatedShipment, error) { var response CreatedShipment _, err := c.client.R(). SetBody(shipment). SetResult(&response). Post("/shipments/createlabel") return response, err }
func (c *ShipStationClient) GetTracking(carrierCode, trackingNumber string) (TrackingInfo, error) { var tracking TrackingInfo _, err := c.client.R(). SetResult(&tracking). Get(fmt.Sprintf("/shipments/gettrackinginfo?carrierCode=%s&trackingNumber=%s", carrierCode, trackingNumber)) return tracking, err }
ShipStation can send webhooks for various events. Here's a basic webhook handler:
func handleWebhook(w http.ResponseWriter, r *http.Request) { var webhook WebhookPayload if err := json.NewDecoder(r.Body).Decode(&webhook); err != nil { http.Error(w, "Invalid webhook payload", http.StatusBadRequest) return } // Process the webhook based on its resource_type and action switch webhook.ResourceType { case "ORDER_NOTIFY": // Handle order notification case "SHIP_NOTIFY": // Handle shipment notification } w.WriteHeader(http.StatusOK) }
ShipStation has rate limits, so let's implement some basic rate limiting:
func (c *ShipStationClient) rateLimitedRequest(method, endpoint string, body interface{}) ([]byte, error) { time.Sleep(500 * time.Millisecond) // Ensure we don't exceed 2 requests per second return c.doRequest(method, endpoint, body) }
For pagination, we'll need to handle the page
and pageSize
parameters:
func (c *ShipStationClient) GetAllOrders() ([]Order, error) { var allOrders []Order page := 1 pageSize := 100 for { var response OrdersResponse _, err := c.client.R(). SetQueryParams(map[string]string{ "page": strconv.Itoa(page), "pageSize": strconv.Itoa(pageSize), }). SetResult(&response). Get("/orders") if err != nil { return nil, err } allOrders = append(allOrders, response.Orders...) if len(response.Orders) < pageSize { break } page++ } return allOrders, nil }
Don't forget to test your integration! Here's a quick example using the testing
package:
func TestGetOrders(t *testing.T) { client := NewShipStationClient(os.Getenv("SHIPSTATION_API_KEY"), os.Getenv("SHIPSTATION_API_SECRET")) orders, err := client.GetOrders() if err != nil { t.Fatalf("Failed to get orders: %v", err) } if len(orders) == 0 { t.Fatal("Expected at least one order, got none") } }
And there you have it! You've just built a solid foundation for a ShipStation API integration in Go. From here, you can expand on this integration to cover more endpoints and functionalities as needed for your specific use case.
Remember, the ShipStation API is vast and powerful. Don't be afraid to dive deeper into the documentation and experiment with different endpoints. Happy coding, and may your shipments always arrive on time!
Now go forth and conquer the world of e-commerce shipping with your new Go-powered ShipStation integration!