Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

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: about 7 hours ago
JSON representation

A fully functional Ecommerce API in GO GIN Framework and mongoDB with JWT Authentication

Awesome Lists containing this project

README

        

## **Fully functional ECOMMERCE API USING GIN FRAMEWORK AND MONGODB**

drawing

-----**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=le

response:

```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