eCommerce with Go

A full-featured e-commerce API built with Go, featuring secure authentication, product management, and order processing

A RESTful e-commerce backend application that demonstrates modern Go web development practices. Built with Gin framework and MongoDB, it provides secure user authentication with JWT, product catalog management, and shopping cart functionality—all containerized with Docker for reproducible development.

TECH STACK
GO
GIN
MONGODB
MONGODB DRIVER
JWT
DOCKER
BSON
GO-PLAYGROUND/VALIDATOR

Why I Built This

After building the Job App with Go, Gorilla Mux, and PostgreSQL, I wanted to test myself with a different stack combination to broaden my backend expertise. E-commerce applications require robust infrastructure that balances security, performance, and maintainability—making them the perfect domain to test alternative technology choices.

This project represents my deliberate exploration of Go's ecosystem diversity. Instead of using Gorilla Mux (from Job App), I chose Gin for its lightweight framework and routing performance. Instead of PostgreSQL with GORM, I embraced MongoDB's document model using the official MongoDB driver with BSON serialization. This comparison taught me that stack selection isn't about 'better'—it's about matching database paradigms to data patterns.

Every component was chosen to contrast with my previous work: Gin's minimal overhead vs Gorilla Mux's explicit routing, MongoDB's schema flexibility vs PostgreSQL's rigid schemas, Docker Compose for database containerization as a repeatable pattern from Job App. The goal wasn't just building an e-commerce API—it was systematically understanding trade-offs in the Go backend ecosystem.

eCommerce with Go

Architecture Overview

The application follows a layered, modular architecture with clear separation of concerns—similar to the Job App pattern but implemented with different technologies. Data flows from HTTP requests through Gin route handlers to controllers, which coordinate validation, business logic, and MongoDB operations. JWT middleware enforces authentication before requests reach protected endpoints.

HTTP & Routing

Gin framework defines all routes and applies middleware for authentication. Routes are grouped by domain: /users, /admin, /products. Unlike Gorilla Mux's explicit router, Gin provides built-in JSON rendering and middleware chaining out-of-the-box.

Business Logic

Controllers orchestrate core functionality: user signup/login, product CRUD operations, and order/cart management. JWT token generation and validation occur here, with BSON serialization handling MongoDB document mapping.

Data Persistence

MongoDB stores users, products, and orders using the official Go driver. The bson package handles document serialization, while primitive.ObjectID manages MongoDB's unique identifier format. Connection pooling ensures efficient concurrent access.

Stateless API with JWT-based authentication. Cart state persists in MongoDB as embedded documents within user profiles. No server-side session storage required, enabling horizontal scaling across multiple instances.

EXPLORER
eCommerce-with-Go
controllers
database
middleware
models
routes
tokens
docker-compose.yaml
main.go
go.mod
go.sum
product.json
README.md

Core Features

Secure User Authentication

The authentication system establishes user identity through signup and login endpoints, issuing JWT tokens for subsequent requests. Unlike PostgreSQL's relational model, MongoDB stores user documents with BSON format, and primitive.ObjectID serves as the unique identifier.

• User SignupPOST /users/signup accepts username/email and password, validates format with go-playground/validator, hashes password with bcrypt, stores BSON document in MongoDB using mongo-driver's InsertOne(), returns success/error response.
• User LoginPOST /users/login accepts credentials, queries MongoDB using bson.M filter, verifies against stored password hash, generates JWT token on success, returns token to client.
• Token ValidationMiddleware intercepts requests to protected routes (e.g., /admin/products), extracts token from Authorization header, validates signature and expiration using JWT claims, injects user context into Gin's context for downstream handlers.
• AuthorizationControllers extract user identity from token claims (stored in Gin context), enforce role-based access by checking user role field in MongoDB document before executing admin-only operations.

Product & Order Management

The catalog system enables administrators to publish products and customers to browse items. MongoDB's flexible schema allows products to have variable attributes without migrations—a stark contrast to PostgreSQL's rigid schema from the Job App project.

• Browse ProductsGET /users/productview uses MongoDB's Find() with bson.D{} filter to return all products. Gin automatically marshals BSON documents to JSON responses.
• Create ProductPOST /admin/products validates input with struct tags, generates primitive.ObjectID for new document, uses InsertOne() to persist to MongoDB's products collection (admin-only via JWT middleware).
• Update ProductPUT /admin/products/:id parses primitive.ObjectID from URL, constructs bson.M update document, uses UpdateOne() with filter to modify product fields atomically.
• Delete ProductDELETE /admin/products/:id uses DeleteOne() with bson.M{"_id": objectId} to remove product document from collection (admin-only with authorization middleware).
• Add to CartPOST /addtocart?id={product_id}&userID={user_id} uses bson.M filter to find user, then $push operator to append product reference to user's cart array field in MongoDB.
• Cart PersistenceCart state stored as embedded array within user document in MongoDB. Unlike relational JOINs, single document fetch retrieves user + cart data atomically.

Backend Systems

MongoDB Driver Integration

Official go.mongodb.org/mongo-driver used for all database operations. bson package handles document serialization/deserialization between Go structs and MongoDB's BSON format. primitive package manages ObjectID generation and parsing. Connection pool configured with minPoolSize and maxPoolSize for concurrent request handling.

Gin Framework Architecture

Gin provides routing groups, middleware support, and JSON rendering. Routes organized by domain: /users (profile, signup, login, product viewing), /admin (product CRUD), / (cart operations). Gin.Context passes between middleware and handlers, storing user claims after JWT validation.

Authentication & Security

JWT tokens with claims for user identity, email, and role (user/admin). Password hashing using bcrypt (cost factor 10). Middleware validates tokens on protected routes, extracts claims, stores in Gin context. go-playground/validator enforces input constraints with struct tags.

Docker Development Environment

Docker Compose orchestrates MongoDB container with persistent volume using official mongo image. Mongo Express provides web-based database administration on port 8081. Environment variables configure MongoDB connection URI, JWT secret, and API port. Docker network allows container communication without host networking.

Key Decisions

Gin over Gorilla Mux

After using Gorilla Mux in the Job App, I chose Gin for comparison. Gin provides built-in JSON rendering, middleware chaining, and error management with less boilerplate. Performance benchmarks show Gin's router is faster due to radix tree implementation. Tradeoff: less explicit route registration than Gorilla Mux, but productivity gains justified for this project.

MongoDB over PostgreSQL

After using PostgreSQL with GORM in Job App, I chose MongoDB to understand NoSQL trade-offs. MongoDB's document model matches e-commerce data patterns: products with variable attributes, orders with nested line items. The bson package provides native Go serialization. Tradeoff: no ACID transactions across documents, but schema flexibility avoids migrations during rapid iteration. This comparison taught me that relational vs document databases aren't universally 'better'—they solve different problems.

Official MongoDB Driver over Third-party

Used go.mongodb.org/mongo-driver instead of community drivers (like globalsign/mgo). Official driver provides BSON type safety, primitive.ObjectID support, and connection pooling. While steeper learning curve than GORM, it offers finer control over queries and better performance.

JWT Over Session Cookies

Same as Job App, JWT enables stateless authentication for horizontal scaling. Token validation happens in middleware without database lookups (unlike session stores). Tradeoff: token revocation requires short expiration times (e.g., 24 hours) or blacklist implementation.

Docker Compose Pattern

Reused Docker Compose pattern from Job App for MongoDB + Mongo Express. This consistency across projects means any developer familiar with one setup understands the other. Docker volumes persist database state between container restarts, preventing data loss during development.

What I Learned

Database paradigms fundamentally shape code

MongoDB's document model let me store cart items as embedded arrays—a single query retrieves everything. PostgreSQL would require joins or multiple queries. But MongoDB's lack of transactions meant I couldn't atomically update inventory across multiple orders. This experience taught me that database choice isn't marginal—it changes how you write business logic entirely.

Gin vs Gorilla Mux: different philosophies

Gin felt more 'batteries-included'—JSON rendering, binding, and validation are built-in. Gorilla Mux felt more 'Lego-like'—compose exactly what you need. Neither is superior; the Job App needed explicit control, eCommerce needed rapid development. Knowing both means I can pick the right tool for each project's constraints.

Infrastructure patterns transfer across stacks

The Docker Compose pattern I built for Job App (PostgreSQL + Adminer) transferred directly to eCommerce (MongoDB + Mongo Express). The same principle applies: database containers + web admin interface + volume persistence. Learning infrastructure once benefits every future project regardless of language or database.

BSON vs JSON vs struct tags

Working with mongo-driver's bson tags alongside json tags revealed serialization complexity. A single Go struct needs both bson:"field_name" for database and json:"field_name" for API. Missing tags cause silent failures. Created helper functions to ensure consistency—the kind of pattern you only discover by building both serialization layers.

Validation remains validation regardless of database

go-playground/validator worked identically whether backing with PostgreSQL/GORM or MongoDB/driver. Input validation happens at API boundary—database is just storage. This separation of concerns means validation logic doesn't need rewriting when changing databases.

Stack exploration is professional development

Building similar functionality (CRUD, auth, carts) with different stacks (Gorilla Mux+PostgreSQL vs Gin+MongoDB) gave me genuine comparative insights. I can now articulate trade-offs from experience, not just documentation. This project wasn't just eCommerce—it was deliberate practice in technology evaluation.

Background

SUCCESS IS NO ACCIDENT, IT IS HARD WORK.

LET'S MAKE IT HAPPEN!

MAKE IT WORK. MAKE IT RIGHT. MAKE IT FAST. — Kent Beck

Get In Touch

I'm always open to discussing new opportunities, creative projects, or just having a chat about technology.