Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/5olitude/ecommerce
A fully functional Ecommerce API in GO GIN Framework and mongoDB with JWT Authentication
https://github.com/5olitude/ecommerce
api ecommerce gin gin-gonic go golang gorm hacktoberfest hacktoberfest2021 hact jwt jwt-authentication mongodb mongodb-driver orm rest-api
Last synced: 3 months ago
JSON representation
A fully functional Ecommerce API in GO GIN Framework and mongoDB with JWT Authentication
- Host: GitHub
- URL: https://github.com/5olitude/ecommerce
- Owner: 5olitude
- Created: 2021-09-20T17:33:51.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2021-10-16T03:39:42.000Z (over 3 years ago)
- Last Synced: 2024-10-01T01:01:50.944Z (4 months ago)
- Topics: api, ecommerce, gin, gin-gonic, go, golang, gorm, hacktoberfest, hacktoberfest2021, hact, jwt, jwt-authentication, mongodb, mongodb-driver, orm, rest-api
- Language: Go
- Homepage:
- Size: 394 KB
- Stars: 32
- Watchers: 2
- Forks: 5
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
## **Fully functional ECOMMERCE API USING GIN FRAMEWORK AND MONGODB**
-----**Initial Release v2.30** โ ๏ธNot tested the efficiency
# project structure
- **Ecommerce** ๐
- controllers ๐
- controllers.go๐
- database๐
- database.go๐
- middleware๐
- middleware.go๐
- models๐
- models.go๐
- routes๐
- routes.go๐
- tokens๐
- tokengen.go๐
- go.sum ๐
- main.go๐clone this repo and change into the directory ecommerce-main***
make sure go is installed in your system
Run```bash
# Start the mongodb container for local development
docker-compose up -d
go run main.go
```#### ` Using Mongodb for small scale ecommerce industry is not a good idea instead use redis or mysql`
## API FUNCTIONALITY CURRENTLY ADDED?
- Signup ๐
- Login ๐
- Product listing General View ๐
- Adding the products to DB
- Sorting the products from DB using regex ๐
- Adding the products to cart ๐
- Removing the Product from cart๐
- Viewing the items in cart with total price๐๐ฐ
- Adding the Home Address ๐
- Adding the Work Address ๐ข
- Editing the Address โ๏ธ
- Deleting the Adress ๐๏ธ
- Checkout the Items from Cart
- Buy Now products๐ฐ#### future implementations?
- Pagination 1>>2>>3
- Admin Part
- OAuth 2
- etc\*\*\*## Code At glance in Database(database.go)
first we need to define the database , make sure the mongodb installed in your system.
The important thing we have to remember is we need to create a database with two collections , Two collections that for storing the user informations and the other for storing the product informations.We must have to configure the url and port of mongodb configured in your system```go
// code example of url and port in databasetup.go
mongo.NewClient(options.Client().ApplyURI("mongodb://localhost:27017")) --port and url
// code example of defining collection name
var collection *mongo.Collection = client.Database("Ecommerce").Collection(CollectionName)
```like to know more about configurations visit: https://www.mongodb.com/blog/post/quick-start-golang-mongodb-starting-and-setup
## Code At glance in models.go
This part defines us how should our database looks like, I think its not about programming skills, but if you have creativity and basic syntax ideas and have some ability to defines struct from creativity 90% of work completed.Before Jumping into other codes we should have a rough idea about our plan so its better to lookup into models .
- We have to define a product first , having a unique id , name and price
```go
type Product struct {
Product_ID primitive.ObjectID `bson:"_id"`
Product_Name *string `json:"product_name"`
Price *uint64 `json:"price"`
Rating *uint8 `json:"rating"`
Image *string `json:"image"`
}
```- We have to define an slice of array products where a user can store individual products
```go
type ProductUser struct {
Product_ID primitive.ObjectID `bson:"_id"`
Product_Name *string `json:"product_name" bson:"product_name"`
Price int `json:"price" bson:"price"`
Rating *uint `json:"rating" bson:"rating"`
Image *string `json:"image" bson:"image"`
}
```- The next struct we have to define the Address
```go
type Address struct {
Address_id primitive.ObjectID `bson:"_id"`
House *string `json:"house_name" bson:"house_name"`
Street *string `json:"street_name" bson:"street_name"`
City *string `json:"city_name" bson:"city_name"`
Pincode *string `json:"pin_code" bson:"pin_code"`
}
```- If the user has ordered something the struct look like the one in below, having an embedded struct inside a struct , here we define the ProductUser as a slice(A person can buy more than one product right?) and a payement struct to define Cash on delivery or digital payement
```go
type Order struct {
Order_ID primitive.ObjectID `bson:"_id"`
Order_Cart []ProductUser `json:"order_list" bson:"order_list"`
Orderered_At time.Time `json:"ordered_on" bson:"ordered_on"`
Price int `json:"total_price" bson:"total_price"`
Discount *int `json:"discount" bson:"discount"`
Payment_Method Payment `json:"payment_method" bson:"payment_method"`
}
```The Payement struct is something look like this
```go
type Payment struct {
Digital bool `json:"digital" bson:"digital"`
COD bool `json:"cod" bson:"cod"`
}
```**_we can define those structs as the simple fields or blocks (genrally known as documents and subdocuments in mongodb)in the user databse or the user struct_**
- Finally in the user struct we are going to embedd the simple structs .The new fields in struct are ID, Name ,Email, Token etc
```go
type User struct {
ID primitive.ObjectID `json:"_id" bson:"_id"`
First_Name *string `json:"first_name" validate:"required,min=2,max=30"`
Last_Name *string `json:"last_name" validate:"required,min=2,max=30"`
Password *string `json:"password" validate:"required,min=6"`
Email *string `json:"email" validate:"email,required"`
Phone *string `json:"phone" validate:"required"`
Token *string `json:"token"`
Refresh_Token *string `josn:"refresh_token"`
Created_At time.Time `json:"created_at"`
Updated_At time.Time `json:"updtaed_at"`
User_ID string `json:"user_id"`
UserCart []ProductUser `json:"usercart" bson:"usercart"`
Address_Details []Address `json:"address" bson:"address"`
Order_Status []Order `json:"orders" bson:"orders"`
}
```## Code At Glance in controllers.go
This file mainly describes about the token authentication process . We have used the JWT authentication from dgrijalwa but now the repository has changed . I have used the same implemtaion for signup and login from
https://dev.to/joojodontoh/build-user-authentication-in-golang-with-jwt-and-mongodb-2igd , this blog is clear and precise about jwt auhentication rather than my explanation here.**_There is an important thing we have to remember when defining array struct the mongodb converts the array to a nil in document field_**
So to overcome this problem we make an empty array in signup function like this,whever a user calls the signup function it initialise the documents to empty array
```go
user.UserCart = make([]models.ProductUser, 0)
user.Address_Details = make([]models.Address, 0)
user.Order_Status = make([]models.Order, 0)
```- **SIGNUP FUNCTION API CALL (POST REQUEST)**
http://localhost:8000/users/signup
```json
{
"first_name": "Joseph",
"last_name": "Hermis",
"email": "[email protected]", // Use @example.com for email because that is it's purpose. See https://www.rfc-editor.org/rfc/rfc6761.html and https://www.rfc-editor.org/rfc/rfc2606.html
"password": "unlucky",
"phone": "+1558426655"
}
```Response :"Successfully Signed Up!!"
- **LOGIN FUNCTION API CALL (POST REQUEST)**
http://localhost:8000/users/login
```json
{
"email": "[email protected]",
"password": "unlucky"
}
```response will be like this
```json
{
"_id": "***********************",
"first_name": "joseph",
"last_name": "hermis",
"password": "$2a$14$UIYjkTfnFnhg4qhIfhtYnuK9qsBQifPKgu/WPZAYBaaN17j0eTQZa",
"email": "[email protected]",
"phone": "+1558921455",
"token": "eyJc0Bwcm90b25vbWFpbC5jb20iLCJGaXJzdF9OYW1lIjoiam9zZXBoIiwiTGFzdF9OYW1lIjoiaGVybWlzIiwiVWlkIjoiNjE2MTRmNTM5ZjI5YmU5NDJiZDlkZjhlIiwiZXhwIjoxNjMzODUzNjUxfQ.NbcpVtPLJJqRF44OLwoanynoejsjdJb5_v2qB41SmB8",
"Refresh_Token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJFbWFpbCI6IiIsIkZpcnLCJVaWQiOiIiLCJleHAiOjE2MzQzNzIwNTF9.ocpU8-0gCJsejmCeeEiL8DXhFcZsW7Z3OCN34HgIf2c",
"created_at": "2021-10-09T08:14:11Z",
"updtaed_at": "2021-10-09T08:14:11Z",
"user_id": "61614f539f29be942bd9df8e",
"usercart": [],
"address": [],
"orders": []
}
```Login Function call create an outlayer for our collection
- **Admin add Product Function POST REQUEST**
**note this function is not seperated from normal user fixed soon for admin**
http://localhost:8000/admin/addproduct
```json
{
"product_name": "laptop",
"price": 300,
"rating": 10,
"image": "1.jpg"
}
```Response : "Successfully added our Product Admin!!"
- **View all the Products in db GET REQUEST**
pagination added soon in next release
http://localhost:8000/users/productview
Response
```json
[
{
"Product_ID": "6153ff8edef2c3c0a02ae39a",
"product_name": "notepad",
"price": 50,
"rating": 10,
"image": "penc.jpg"
},
{
"Product_ID": "616152679f29be942bd9df8f",
"product_name": "laptop",
"price": 300,
"rating": 10,
"image": "1.jpg"
},
{
"Product_ID": "616152ee9f29be942bd9df90",
"product_name": "top",
"price": 300,
"rating": 10,
"image": "1.jpg"
},
{
"Product_ID": "616152fa9f29be942bd9df91",
"product_name": "table",
"price": 300,
"rating": 10,
"image": "1.jpg"
},
{
"Product_ID": "616153039f29be942bd9df92",
"product_name": "apple",
"price": 300,
"rating": 10,
"image": "1.jpg"
}
]
```- **Search Product by regex function (GET REQUEST)**
defines the word search sorting
http://localhost:8000/users/search?name=leresponse:
```json
[
{
"Product_ID": "616152fa9f29be942bd9df91",
"product_name": "table",
"price": 300,
"rating": 10,
"image": "1.jpg"
},
{
"Product_ID": "616153039f29be942bd9df92",
"product_name": "apple",
"price": 300,
"rating": 10,
"image": "1.jpg"
}
]
```The corresponding Query to mongodb is **ProductCollection.Find(ctx, bson.M{"product_name": bson.M{"$regex": queryParam}})**
- **Adding the Products to the Cart (GET REQUEST)**
http://localhost:8000/addtocart?id=xxxproduct_idxxx&userID=xxxxxxuser_idxxxxxx
Corresponding mongodb query
```go
filter := bson.D{primitive.E{Key: "_id", Value: id}}
update := bson.D{{Key: "$push", Value: bson.D{primitive.E{Key: "usercart", Value: bson.D{{Key: "$each", Value: productcart}}}}}}
_, err = UserCollection.UpdateOne(ctx, filter, update)
```- **Removing Item From the Cart (GET REQUEST)**
http://localhost:8000/addtocart?id=xxxxxxx&userID=xxxxxxxxxxxx
Corresponding mongodb query
```go
filter := bson.D{primitive.E{Key: "_id", Value: usert_id}}update := bson.M{"$pull": bson.M{"usercart": bson.M{"_id": removed_id}}}
_, err = UserCollection.UpdateMany(ctx, filter, update)
```- **Listing the item in the users cart (GET REQUEST) and total price**
http://localhost:8000/listcart?id=xxxxxxuser_idxxxxxxxxxx
Corresponding Mongodb Query (WE are using the aggrgate operation to find sum)
filter_match := bson.D{{Key: "$match", Value: bson.D{primitive.E{Key: "_id", Value: usert_id}}}}
unwind := bson.D{{Key: "$unwind", Value: bson.D{primitive.E{Key: "path", Value: "$usercart"}}}}
grouping := bson.D{{Key: "$group", Value: bson.D{primitive.E{Key: "_id", Value: "$_id"}, {Key: "total", Value: bson.D{primitive.E{Key: "$sum", Value: "$usercart.price"}}}}}}
pointcursor, err := UserCollection.Aggregate(ctx, mongo.Pipeline{filter_match, unwind, grouping})- **Addding the Address (POST REQUEST)**
http://localhost:8000/addadress?id=user_id**\*\***\***\*\***
The Address array is limited to two values home and work address more than two address is not acceptable
```json
{
"house_name": "jupyterlab",
"street_name": "notebook",
"city_name": "mars",
"pin_code": "685607"
}
```- **Editing the Home Address(PUT REQUEST)**
http://localhost:8000/edithomeaddress?id=xxxxxxxxxxuser_idxxxxxxxxxxxxxxx
- **Editing the Work Address(PUT REQUEST)**
http://localhost:8000/editworkaddress?id=xxxxxxxxxxuser_idxxxxxxxxxxxxxxx
- **Delete Addresses(GET REQUEST)**
http://localhost:8000/deleteaddresses?id=xxxxxxxxxuser_idxxxxxxxxxxxxx
delete both addresses
- **Cart Checkout Function and placing the order(GET REQUEST)**
After placing the order the items have to be deleted from cart functonality added
http://localhost:8000?id=xxuser_idxxx
- **Instantly Buying the Products(GET REQUEST)**
http://localhost:8000?userid=xxuser_idxxx&pid=xxxxproduct_idxxxx## Code At Glance in main.go
All the routes defined here requires the api authentication key
Repo dedicting to my best friend mathappan ๐ถ ,who left me without saying a goodbye and fill me with hopes even in my dark days RIP my friend
#### Here are some of the reference I gone through while working on this project
JWT Authentication using golang [^1]
MongoDB Quick Introduction with Golang official blog [^2]
Package context instead of goroutine [^3]
Context use cases in real scenarios [^4]
Mongo GO Driver official Documentation [^5]
Mongo Go official go documentation [^6]
Is "logout" useless on a REST API? [^7]
JWT AUTHENTICATION OFFICIAL [^8]
Gin framework Documentation [^9]
[^1]: https://dev.to/joojodontoh/build-user-authentication-in-golang-with-jwt-and-mongodb-2igd
[^2]: https://www.mongodb.com/blog/post/quick-start-golang-mongodb-starting-and-setup
[^3]: https://pkg.go.dev/context
[^4]: https://levelup.gitconnected.com/context-in-golang-98908f042a57
[^5]: https://docs.mongodb.com/drivers/go/current/
[^6]: https://pkg.go.dev/go.mongodb.org/mongo-driver/mongo
[^7]: https://stackoverflow.com/questions/36294359/is-logout-useless-on-a-rest-api
[^8]: github.com/golang-jwt/jwt
[^9]: https://github.com/gin-gonic/gin