Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions Instagram API -(GOLang)/Insta Backend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.DS_Store
.git

# testing
/coverage

# production
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
.env
env.sh
61 changes: 61 additions & 0 deletions Instagram API -(GOLang)/Insta Backend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# AppointyTask API


### Details About the Endpoints

- POST /users: To create a new user {Implemented and Available}
<pre><code>
Checks if the user already exists in the database.
If the user does not exist, creates a new user.

Request Body:
{
"_id" : string, //Later Converted to Mongo ObjectId
"name" : string,
"username" : string,
"password" : string,
}
</code></pre>


- GET /users/{id}: To get a user by id {Implemented and Available}
<pre><code>
Returns the user with the given id.

Request Body:
{
"_id" : string, //Later Converted to Mongo ObjectId
"name" : string,
"username" : string,
"password" : nil,
}
</code></pre>
- POST /posts: To create a new post {Implemented and Available}
<pre><code>
Creates a new post.

Response :
{
"_id" : string, //Later Converted to Mongo ObjectId
"caption" : string,
"imageurl" : string,
"postedat" : string,
"userid" : primitive.ObecjId,
}
</code></pre>
- GET /posts/{id}: To get a post by id {Implemented and Available}
<pre><code>
Returns the post with the given id.

Response :
{
"_id" : string, //Later Converted to Mongo ObjectId
"caption" : string,
"imageurl" : string,
"postedat" : string,
"userid" : primitive.ObecjId,
}
</code></pre>
- GET /posts/users/{id}: To get all posts by user id


92 changes: 92 additions & 0 deletions Instagram API -(GOLang)/Insta Backend/api/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package main

import (
"context"
"fmt"
"log"
"net/http"
"os"
"social/api/routes"
"time"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readpref"
)



func checkMethodType(method string,handler http.HandlerFunc) http.HandlerFunc{

//Checking the request method type and returning the handler function accordingly

return func(w http.ResponseWriter, r *http.Request) {
if r.Method != method {
w.WriteHeader(http.StatusMethodNotAllowed)
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
return
}
handler(w,r)
}
}

func main() {
mux:= http.NewServeMux()

//Database Connection

db,err := DatabaseConnection();
if err != nil {
log.Fatal("Database Connection Error $s",err)
}
fmt.Println("Database connection Success!")

//Sending the database connection to the routes package

routes.DB = db;

//Routes

mux.HandleFunc("/users",checkMethodType("POST",routes.UserHandler));
mux.HandleFunc("/users/",checkMethodType("GET",routes.GetUserHandler));

mux.HandleFunc("/posts",checkMethodType("POST",routes.PostHandler));
mux.HandleFunc("/posts/",checkMethodType("GET",routes.GetPostHandler));
mux.HandleFunc("/posts/users/",checkMethodType("GET",routes.GetUserPostsHandler));

//Server Port Configuration

fmt.Println(os.Getenv("PORT"));
error := http.ListenAndServe(os.Getenv("PORT"), mux);
if error != nil {
log.Fatal(error)
}
}

func DatabaseConnection()(*mongo.Database,error){

/*
Database Connection
Need env variables : [DATABASE_URI,DATABASE_NAME]
Connection is established using mongo driver
*/

ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
fmt.Println(os.Getenv("MONGO_URI"));
client,err := mongo.Connect(ctx,options.Client().ApplyURI(os.Getenv("MONGO_URI")));

if err != nil {
return nil,err
}

err = client.Ping(ctx, readpref.Primary())
if err != nil {
log.Fatal(err)
}
fmt.Println(os.Getenv("DATABASE_NAME"));

//Initialize Database

database := client.Database(os.Getenv("DATABASE_NAME"))

return database,nil
}
55 changes: 55 additions & 0 deletions Instagram API -(GOLang)/Insta Backend/api/routes/getUser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package routes

import (
"context"
"encoding/json"
"fmt"
"net/http"
"strings"
"time"

"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
)

/*
Takes user id as url path parameter and returns the user details
*/

func GetUserHandler(w http.ResponseWriter, r *http.Request) {
uid := strings.TrimPrefix(r.URL.Path, "/users/")
if uid == ""{
http.Error(w, "User ID is required", http.StatusBadRequest)
return
}
ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
uuid,err:= primitive.ObjectIDFromHex(uid);
if err!=nil{
http.Error(w, "Invalid User ID", http.StatusBadRequest)
return
}
fmt.Println("Getting user with id: ", uuid)
getUserResult:=DB.Collection("users").FindOne(ctx, bson.M{"_id":uuid})
if getUserResult.Err() != nil {
http.Error(w, getUserResult.Err().Error(), http.StatusInternalServerError)
return
}
var user User
getUserResult.Decode(&user)

// Not returning user password for security reasons although it is reverse engineering safe

user.Password = ""
json_data2,err:=json.Marshal(user)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

fmt.Println(string(json_data2))
w.WriteHeader(http.StatusFound)
w.Header().Set("Content-Type", "application/json")
w.Write(json_data2)
return;

}
37 changes: 37 additions & 0 deletions Instagram API -(GOLang)/Insta Backend/api/routes/getpost.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package routes

import (
"context"
"encoding/json"
"net/http"
"strings"
"time"

"go.mongodb.org/mongo-driver/bson"
)

/*
Takes a post id as url path variable and returns the post details
For Respose Data Refer README.md
*/

func GetPostHandler(w http.ResponseWriter, r *http.Request) {
pid := strings.TrimPrefix(r.URL.Path, "/posts/")
if pid == ""{
http.Error(w, "Invalid request No Post Id Found", http.StatusBadRequest)
return
}
ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
getUserResult:=DB.Collection("Post").FindOne(ctx, bson.M{"_id":pid})
if getUserResult.Err() != nil {
http.Error(w, getUserResult.Err().Error(), http.StatusBadRequest)
return
}
var post Post
getUserResult.Decode(&post)
json_data2, _ := json.Marshal(post)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(json_data2)
return
}
98 changes: 98 additions & 0 deletions Instagram API -(GOLang)/Insta Backend/api/routes/getuserpost.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package routes

import(
"net/http"
"strings"
"encoding/json"
"fmt"
"context"
"time"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/bson"
)

type GetUserPost struct{
Page int `json:"page"`
Limit int `json:"limit"`
}

type Result struct{
Id string `json:"_id"`
Caption string `json:"caption"`
ImageUrl string `json:"imageurl"`
PostedAt time.Time `json:"postedat"`
UserId primitive.ObjectID `json:"userid"`
}

func GetUserPostsHandler(w http.ResponseWriter, r *http.Request){
uid := strings.TrimPrefix(r.URL.Path, "/posts/users/")
fmt.Println(uid)
if uid == ""{
http.Error(w, "Invalid User Id", http.StatusNotFound)
return
}
// Decode request Body

var details GetUserPost
if err:= json.NewDecoder(r.Body).Decode(&details); err != nil {
http.Error(w, "Bad request", http.StatusBadRequest)
fmt.Println(err)
return
}

fmt.Println(details)
uuid,err:= primitive.ObjectIDFromHex(uid);
fmt.Println(uuid)
fmt.Println(uid)
if err != nil {
http.Error(w, "Invalid User Id", http.StatusNotFound)
return
}

// Set findOptions

findOptions:= options.Find();

findOptions.SetLimit(int64(details.Limit));
findOptions.SetSkip(int64((details.Page-1) * details.Limit));
findOptions.SetSort(bson.M{"postedat": -1});

filter:= bson.M{"userid": uuid};
ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
queryResult,err:= DB.Collection("Post").Find(ctx, filter, findOptions);
if err != nil{
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
fmt.Println(err)
return
}

var results []Result

fmt.Println(queryResult)

for queryResult.Next(ctx){
var result Result
err:= queryResult.Decode(&result);
if err != nil{
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
fmt.Println(err)
return
}
results = append(results, result)
}
if results == nil{
http.Error(w, "No Posts Found", http.StatusNotFound)
return
}
json_data2,error := json.Marshal(results)
if error != nil{
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
fmt.Println(error)
return
}
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
w.Write(json_data2)
return
}
Loading