Skip to content

Navigation Menu

Sign in
Sign up

Repository files navigation

ShipEngine Integration with Next.js

ShipEngine + Next.js

Overview

This project demonstrates how to integrate ShipEngine's shipping APIs with a Next.js application. It provides a complete implementation of shipping rate calculation, label generation, and shipment tracking functionality using ShipEngine's powerful API.

Features

  • 🚚 Real-time Shipping Rates: Get accurate shipping rates from multiple carriers
  • πŸ“¦ Label Generation: Create shipping labels with a single click
  • πŸ” Shipment Tracking: Track shipments in real-time
  • πŸŒ™ Dark/Light Mode: Fully responsive UI with theme support
  • πŸ“± Mobile-Friendly: Responsive design that works on all devices

Prerequisites

  • Node.js 18.x or later
  • npm or yarn
  • ShipEngine API key (sign up at ShipEngine)

Getting Started

1. Clone the repository

git clone https://github.com/yourusername/shipengine-with-nextjs.git
cd shipengine-with-nextjs

2. Install dependencies

npm install
# or
yarn install

3. Set up environment variables

Create a .env.local file in the root directory with your ShipEngine API key:

SHIPENGINE_API_KEY=your_api_key_here
# Optional: Add specific carrier IDs if you have them
SHIPENGINE_FIRST_COURIER=carrier_id_1
SHIPENGINE_SECOND_COURIER=carrier_id_2
SHIPENGINE_THIRD_COURIER=carrier_id_3
SHIPENGINE_FOURTH_COURIER=carrier_id_4
SHIPENGINE_FIFTH_COURIER=carrier_id_5

4. Run the development server

npm run dev
# or
yarn dev

Open http://localhost:3000 in your browser to see the application.

Project Structure

β”œβ”€β”€ app/ # Next.js app directory
β”‚ β”œβ”€β”€ api/ # API routes
β”‚ β”‚ └── shipengine/ # ShipEngine API endpoints
β”‚ β”‚ β”œβ”€β”€ get-rates/ # Shipping rates endpoint
β”‚ β”‚ β”œβ”€β”€ label/ # Label creation endpoint
β”‚ β”‚ └── tracking/ # Tracking endpoint
β”‚ β”œβ”€β”€ components/ # React components
β”‚ β”‚ β”œβ”€β”€ Footer.tsx # Footer component
β”‚ β”‚ └── Navbar.tsx # Navigation component
β”‚ β”œβ”€β”€ tracking/ # Tracking page
β”‚ β”œβ”€β”€ globals.css # Global styles
β”‚ β”œβ”€β”€ layout.tsx # Root layout
β”‚ └── page.tsx # Home page
β”œβ”€β”€ lib/ # Utility functions
β”‚ β”œβ”€β”€ data.ts # Sample data
β”‚ β”œβ”€β”€ shipEngine.ts # ShipEngine client setup
β”‚ └── types.ts # TypeScript types
β”œβ”€β”€ public/ # Static assets
β”œβ”€β”€ .env.local # Environment variables (create this)
β”œβ”€β”€ next.config.js # Next.js configuration
β”œβ”€β”€ package.json # Project dependencies
β”œβ”€β”€ README.md # Project documentation
└── tsconfig.json # TypeScript configuration

Integration Guide

1. Setting Up ShipEngine Client

First, create a ShipEngine client instance using your API key:

// lib/shipEngine.ts
import { ShipEngine } from 'shipengine';
export const shipengine = new ShipEngine(process.env.SHIPENGINE_API_KEY!);

2. Creating API Routes

Shipping Rates API

// app/api/shipengine/get-rates/route.ts
import { shipengine } from '@/lib/shipEngine';
import { NextResponse } from 'next/server';
export async function POST(request: Request) {
 try {
 const { toAddress } = await request.json();
 
 // Define shipment details
 const shipmentDetails = {
 rateOptions: {
 carrierIds: [
 // Your carrier IDs
 ],
 },
 shipment: {
 validateAddress: 'validate_and_clean',
 shipTo: toAddress,
 shipFrom: {
 // Your warehouse address
 },
 packages: [
 // Package details
 ],
 },
 };
 
 // Get rates from ShipEngine
 const ratesResult = await shipengine.getRatesWithShipmentDetails(shipmentDetails);
 
 return NextResponse.json(ratesResult);
 } catch (error) {
 console.error('Error getting rates:', error);
 return NextResponse.json({ error: 'Failed to get shipping rates' }, { status: 500 });
 }
}

Label Creation API

// app/api/shipengine/label/route.ts
import { shipengine } from '@/lib/shipEngine';
import { NextResponse } from 'next/server';
export async function POST(request: Request) {
 try {
 const { rateId } = await request.json();
 
 if (!rateId) {
 return NextResponse.json({ error: 'Rate ID is required' }, { status: 400 });
 }
 
 // Create label using the selected rate
 const label = await shipengine.createLabelFromRate({
 rateId,
 validateAddress: 'validate_and_clean',
 });
 
 return NextResponse.json(label);
 } catch (error) {
 console.error('Error creating label:', error);
 return NextResponse.json({ error: 'Failed to create shipping label' }, { status: 500 });
 }
}

Tracking API

// app/api/shipengine/tracking/[labelId]/route.ts
import { shipengine } from '@/lib/shipEngine';
import { NextResponse } from 'next/server';
export async function GET(
 request: Request,
 { params }: { params: { labelId: string } }
) {
 try {
 const labelId = params.labelId;
 
 if (!labelId) {
 return NextResponse.json({ error: 'Label ID is required' }, { status: 400 });
 }
 
 // Track shipment using label ID
 const tracking = await shipengine.trackUsingLabelId({
 labelId,
 });
 
 return NextResponse.json(tracking);
 } catch (error) {
 console.error('Error tracking shipment:', error);
 return NextResponse.json({ error: 'Failed to track shipment' }, { status: 500 });
 }
}

3. Frontend Implementation

Fetching Shipping Rates

const fetchRates = async () => {
 try {
 setLoading(true);
 setError('');
 
 const response = await fetch('/api/shipengine/get-rates', {
 method: 'POST',
 headers: {
 'Content-Type': 'application/json',
 },
 body: JSON.stringify({
 toAddress: shippingAddress,
 }),
 });
 
 const data = await response.json();
 
 if (!response.ok) {
 throw new Error(data.error || 'Failed to get shipping rates');
 }
 
 setRates(data.rates);
 } catch (error) {
 setError(error.message);
 } finally {
 setLoading(false);
 }
};

Creating a Shipping Label

const createLabel = async () => {
 try {
 setLabelLoading(true);
 setError('');
 
 const response = await fetch('/api/shipengine/label', {
 method: 'POST',
 headers: {
 'Content-Type': 'application/json',
 },
 body: JSON.stringify({
 rateId,
 }),
 });
 
 const data = await response.json();
 
 if (!response.ok) {
 throw new Error(data.error || 'Failed to create shipping label');
 }
 
 setLabel(data);
 } catch (error) {
 setError(error.message);
 } finally {
 setLabelLoading(false);
 }
};

Tracking a Shipment

const trackShipment = async (labelId) => {
 try {
 setTrackingLoading(true);
 setTrackingError('');
 
 const response = await fetch(`/api/shipengine/tracking/${labelId}`);
 const data = await response.json();
 
 if (!response.ok) {
 throw new Error(data.error || 'Failed to track shipment');
 }
 
 setTrackingData(data);
 } catch (error) {
 setTrackingError(error.message);
 } finally {
 setTrackingLoading(false);
 }
};

Best Practices

  1. Error Handling: Always implement proper error handling for API calls
  2. Loading States: Show loading indicators during API requests
  3. Validation: Validate user input before sending to the API
  4. Environment Variables: Keep API keys secure in environment variables
  5. TypeScript: Use TypeScript for better type safety and developer experience

Resources


Built with ❀️ by Daniel Hashmi using Next.js and ShipEngine

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

AltStyle γ«γ‚ˆγ£γ¦ε€‰ζ›γ•γ‚ŒγŸγƒšγƒΌγ‚Έ (->γ‚ͺγƒͺγ‚ΈγƒŠγƒ«) /