A RESTful e-commerce API built with Go, featuring user authentication, product management, shopping cart functionality, and Stripe payment integration.
- User Authentication: Signup and login with JWT-based authentication
- Product Management: Browse products with search functionality (admin-only product creation)
- Shopping Cart: Add items, view cart, and checkout
- Payment Integration: Stripe payment intent creation for checkout
- Role-Based Access: Admin and regular user roles with different permissions
- Go 1.21 or higher
- PostgreSQL 12 or higher
- Stripe account (for payment processing)
Create a .env file in the root directory or set the following environment variables:
DB_HOST=localhost # PostgreSQL host (default: localhost)
DB_USER=postgres # PostgreSQL user (default: postgres)
DB_PASSWORD=yourpassword # PostgreSQL password (default: mysecretpassword)
DB_NAME=ecommerce_db # Database name (default: ecommerce_db)
DB_PORT=5432 # PostgreSQL port (default: 5432)PORT=8080 # Server port (default: 8080)
JWT_SECRET=your_secret_key # Secret key for JWT signing (default: auto-generated)STRIPE_SECRET_KEY=sk_test_... # Your Stripe secret key (default: mocked for development)ADMIN_USER=admin # Admin username (default: ecommerce_admin)
ADMIN_PASS=adminpass123 # Admin password (default: SuperSecureAdminPass123)Note: If environment variables are not set, the application will use the default values shown above. However, it's recommended to set proper values for production use.
-
Clone the repository (if applicable):
git clone <repository-url> cd ecommerce-api
-
Install dependencies:
go mod download
-
Set up PostgreSQL database:
# Create database createdb ecommerce_db # Or using psql psql -U postgres CREATE DATABASE ecommerce_db;
-
Set environment variables (create
.envfile or export variables):export DB_HOST=localhost export DB_USER=postgres export DB_PASSWORD=yourpassword export DB_NAME=ecommerce_db export DB_PORT=5432 export JWT_SECRET=your_jwt_secret_key_here export STRIPE_SECRET_KEY=sk_test_your_stripe_key export PORT=8080 export ADMIN_USER=admin export ADMIN_PASS=adminpass123
-
Start the server:
go run .Or build and run:
go build -o ecommerce-api ./ecommerce-api
-
The server will start on
http://localhost:8080(or the port specified inPORTenvironment variable). -
The application will automatically:
- Connect to the PostgreSQL database
- Run database migrations (create tables if they don't exist)
- Create an admin user if it doesn't exist
http://localhost:8080
All authenticated endpoints require a JWT token in the Authorization header:
Authorization: Bearer <your_jwt_token>
Create a new user account.
Endpoint: POST /api/signup
Request Body:
{
"username": "john_doe",
"password": "securepassword123"
}Example:
curl -X POST http://localhost:8080/api/signup \
-H "Content-Type: application/json" \
-d '{
"username": "john_doe",
"password": "securepassword123"
}'Response (201 Created):
{
"message": "User created",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}Authenticate and receive a JWT token.
Endpoint: POST /api/login
Request Body:
{
"username": "john_doe",
"password": "securepassword123"
}Example:
curl -X POST http://localhost:8080/api/login \
-H "Content-Type: application/json" \
-d '{
"username": "john_doe",
"password": "securepassword123"
}'Response (200 OK):
{
"message": "Login successful",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"is_admin": false
}Retrieve all products with optional search query.
Endpoint: GET /api/products
Query Parameters:
q(optional): Search query to filter products by name or description
Example (Get all products):
curl -X GET http://localhost:8080/api/productsExample (Search products):
curl -X GET "http://localhost:8080/api/products?q=laptop"Response (200 OK):
[
{
"id": 1,
"name": "Laptop",
"description": "High-performance laptop",
"price": "999.99",
"inventory": 50
},
{
"id": 2,
"name": "Mouse",
"description": "Wireless mouse",
"price": "29.99",
"inventory": 100
}
]Add a product to the shopping cart.
Endpoint: POST /api/cart/add
Headers:
Authorization: Bearer <your_jwt_token>
Request Body:
{
"product_id": 1,
"quantity": 2
}Example:
curl -X POST http://localhost:8080/api/cart/add \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
-d '{
"product_id": 1,
"quantity": 2
}'Response (200 OK):
{
"ID": 1,
"CreatedAt": "2024-01-15T10:30:00Z",
"UpdatedAt": "2024-01-15T10:30:00Z",
"DeletedAt": null,
"UserID": 1,
"Items": [
{
"ID": 1,
"CreatedAt": "2024-01-15T10:30:00Z",
"UpdatedAt": "2024-01-15T10:30:00Z",
"DeletedAt": null,
"CartID": 1,
"ProductID": 1,
"Quantity": 2,
"Name": "Laptop",
"PriceCents": 99999
}
]
}Retrieve the current user's shopping cart.
Endpoint: GET /api/cart
Headers:
Authorization: Bearer <your_jwt_token>
Example:
curl -X GET http://localhost:8080/api/cart \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."Response (200 OK):
{
"cart": {
"ID": 1,
"CreatedAt": "2024-01-15T10:30:00Z",
"UpdatedAt": "2024-01-15T10:30:00Z",
"DeletedAt": null,
"UserID": 1,
"Items": [
{
"ID": 1,
"CreatedAt": "2024-01-15T10:30:00Z",
"UpdatedAt": "2024-01-15T10:30:00Z",
"DeletedAt": null,
"CartID": 1,
"ProductID": 1,
"Quantity": 2,
"Name": "Laptop",
"PriceCents": 99999
}
]
},
"total_usd": "1999.98",
"total_cents": 199998
}Process checkout and create a Stripe payment intent.
Endpoint: POST /api/checkout
Headers:
Authorization: Bearer <your_jwt_token>
Example:
curl -X POST http://localhost:8080/api/checkout \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."Response (200 OK):
{
"message": "Checkout successful. Payment initiated.",
"total_paid_cents": 199998,
"payment_intent_id": "pi_1234567890",
"client_secret": "pi_1234567890_secret_abc123"
}Note: This endpoint will:
- Validate cart is not empty
- Check product inventory
- Update inventory for all products
- Create a Stripe payment intent
- Clear the user's cart
Create a new product (Admin only).
Endpoint: POST /api/admin/products
Headers:
Authorization: Bearer <admin_jwt_token>
Request Body:
{
"name": "New Product",
"description": "Product description",
"price_cents": 4999,
"inventory": 100
}Example:
curl -X POST http://localhost:8080/api/admin/products \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
-d '{
"name": "New Product",
"description": "Product description",
"price_cents": 4999,
"inventory": 100
}'Response (201 Created):
{
"ID": 3,
"CreatedAt": "2024-01-15T10:30:00Z",
"UpdatedAt": "2024-01-15T10:30:00Z",
"DeletedAt": null,
"Name": "New Product",
"Description": "Product description",
"PriceCents": 4999,
"Inventory": 100
}Note:
price_centsis the price in cents (e.g., 4999 = $49.99)- Only users with
is_admin: truecan access this endpoint
All endpoints may return error responses in the following format:
{
"error": "Error message description"
}200 OK: Request successful201 Created: Resource created successfully400 Bad Request: Invalid request data401 Unauthorized: Missing or invalid authentication token403 Forbidden: Insufficient permissions (e.g., non-admin accessing admin endpoint)404 Not Found: Resource not found409 Conflict: Resource conflict (e.g., username already taken)500 Internal Server Error: Server error
{
"error": "Invalid username or password"
}The application automatically creates the following tables:
- users: User accounts with authentication
- products: Product catalog
- carts: Shopping carts (one per user)
- cart_items: Items in shopping carts
-
Sign up a new user:
curl -X POST http://localhost:8080/api/signup \ -H "Content-Type: application/json" \ -d '{"username": "testuser", "password": "testpass123"}'
Save the
tokenfrom the response. -
Login (alternative):
curl -X POST http://localhost:8080/api/login \ -H "Content-Type: application/json" \ -d '{"username": "testuser", "password": "testpass123"}'
-
Get products:
curl -X GET http://localhost:8080/api/products
-
Add item to cart (use token from step 1):
curl -X POST http://localhost:8080/api/cart/add \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_TOKEN_HERE" \ -d '{"product_id": 1, "quantity": 1}'
-
View cart:
curl -X GET http://localhost:8080/api/cart \ -H "Authorization: Bearer YOUR_TOKEN_HERE" -
Checkout:
curl -X POST http://localhost:8080/api/checkout \ -H "Authorization: Bearer YOUR_TOKEN_HERE"
ecommerce-api/
├── config.go # Configuration loading
├── main.go # Application entry point and routing
├── domain/ # Domain models and interfaces
│ ├── user.go
│ ├── product.go
│ ├── cart.go
│ ├── jwt_claims.go
│ ├── errors.go
│ ├── user_repo.go
│ ├── product_repo.go
│ └── cart_repo.go
├── repository/ # Database implementations
│ ├── postgres_repo.go
│ ├── user_repo.go
│ ├── product_repo.go
│ └── cart_repo.go
├── service/ # Business logic
│ ├── user_service.go
│ ├── product_service.go
│ ├── cart_service.go
│ ├── auth_service.go
│ └── stripe_service.go
├── handler/ # HTTP handlers
│ ├── handler.go
│ ├── user_handler.go
│ └── middleware.go
└── go.mod # Go dependencies
- JWT Secret: Use a strong, randomly generated secret key for
JWT_SECRET - Password Hashing: The current implementation uses SHA256. For production, use
bcryptorargon2 - HTTPS: Always use HTTPS in production
- Database: Use strong database passwords and restrict database access
- Environment Variables: Never commit
.envfiles or secrets to version control - Stripe Keys: Use test keys for development and live keys only in production
- Ensure PostgreSQL is running:
pg_isready - Verify database credentials in environment variables
- Check if database exists:
psql -l | grep ecommerce_db
- Change the
PORTenvironment variable - Or stop the process using the port:
lsof -ti:8080 | xargs kill
- Ensure PostgreSQL user has CREATE TABLE permissions
- Check database connection string format
MIT License