├── .gitignore ├── LICENSE ├── README.md ├── client.go ├── connect.go ├── create.go ├── db.go ├── delete.go ├── http.go ├── select.go └── update.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Pourya 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Building-basic-RESTful-CRUD-with-Golang-MySQL 2 | Building basic RESTful (CRUD) with Golang & MySQL 3 | 4 | 5 | # Introduction 6 | 7 | We would be developing an application that exposes a basic REST-API server for CRUD operations for managing Persons (id,firstName,lastName, age) 8 | Before we start, lets us make a check that the reader might have basic knowledge of SQL and Golang. 9 | 10 | ``` 11 | mkdir rest-go-demo && cd rest-go-example 12 | ``` 13 | 14 | This will create a folder named “rest-go-demo”. 15 | Now, let’s start with initializing and adding the go-modules required for our application 16 | 17 | ``` 18 | go mod init 19 | go get github.com/gorilla/mux 20 | go get github.com/jinzhu/gorm 21 | go get github.com/go-sql-driver/mysql 22 | ``` 23 | 24 | We will be utilizing the dependency management provided by Golang in form of go-modules. 25 | “go mod init” is used to initialize the root application and dependencies can be tracked with the go.mod created after the execution of the above command. 26 | We would need certain packages to help with our journey: 27 | 1. gorilla/mux:= For creating routes and HTTP handlers for our endpoints 28 | 2. jinzhu/gorm:= An ORM tool for MySQL. 29 | 3. go-sql-driver/mysql:= MYSQL driver. 30 | 31 | # Setting MySQL: 32 | 33 | As we would be using MySQL as our backing database to persist our user data. 34 | let’s start with creating a database specific to our needs. 35 | 36 | ``` 37 | CREATE DATABASE learning; 38 | ``` 39 | 40 | Let’s create a struct for managing our database configuration which would be utilized to create a connection to the database. 41 | 42 | Now, let’s create a client to manage and create connections to our Database 43 | 44 | Let’s test whether our client can connect with our database or not!! 45 | 46 | ``` 47 | vishal@vishal:~/go/src/rest-go-demo$ go run main.go 48 | 2021/02/14 16:56:34 Connection was successful!! 49 | vishal@vishal:~/go/src/rest-go-demo$ 50 | ``` 51 | 52 | Now, let’s create our simple Person struct which would be our object in reference. 53 | 54 | ``` 55 | type Person struct { 56 | ID string `json:"id"` 57 | FirstName string `json:"firstName"` 58 | LastName string `json:"lastName"` 59 | Age string `json:"age"` 60 | } 61 | ``` 62 | 63 | # Create a Simple HTTP Server 64 | 65 | We would be using “gorilla/mux” to create a simple server for handling our HTTP requests. 66 | 67 | 68 | An HTTP server, operating on port 8090 will be initiated for our usage. 69 | Now let’s add our REST endpoint’s and move further in our journey 70 | POST / CREATE endpoint 71 | We will start by adding a route “/create/” to our router to serve an endpoint which will create a new person whenever triggered 72 | 73 | ``` 74 | router.HandleFunc("/create",createPerson).Methods("POST") 75 | ``` 76 | 77 | Let’s create a respective createPerson(), the function that will take the POST request data and create a new person entry in DB. 78 | We will do the same by first Unmarsahlling the JSON data retrieved from the body into our Person struct created above and later insert the data by creating a new record. 79 | 80 | 81 | GET / SELECT endpoint 82 | Similarly, we added handler and respective function for POST, we will all “/get/{id}” to our router to retrieve data 83 | 84 | ``` 85 | router.HandleFunc("/get/{id}", getPersonByID).Methods("GET") 86 | ``` 87 | 88 | Let’s add the respective getPersonByID() function, which will utilize the request parameter “id” to retrieve the respective data and return a JSON response. 89 | Here we would be reversing the procedure we did while creating POST endpoint, we would be Marshalling the person struct retrieved from the database to JSON and create an HTTP response. 90 | 91 | PUT / UPDATE endpoint 92 | Now I might assume you might have guessed what comes next in our router and respective functions 93 | 94 | ``` 95 | router.HandleFunc("/update/{id}", updatePersonByID).Methods("PUT") 96 | ``` 97 | 98 | updatePersonByID() will take up the POST request data, Unmarshall the JSON to person struct, and update respectively 99 | 100 | DELETE / DELETE endpoint 101 | 102 | ``` 103 | router.HandleFunc("/delete/{id}", deletPersonByID).Methods("DELETE") 104 | ``` 105 | 106 | deletePersonByID() will delete the “id” passed in the request parameter and deletes the respective record from the database. 107 | Now, as all our endpoints are in place let's integrate all of them and test out our CRUD operations. 108 | We will do this by executing the below commands 109 | 110 | ``` 111 | go mod tidy 112 | go build 113 | ./rest-go-demo 114 | ``` 115 | 116 | -------------------------------------------------------------------------------- /client.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/jinzhu/gorm" 7 | ) 8 | 9 | //Connector variable used for CRUD operation's 10 | var Connector *gorm.DB 11 | 12 | //Connect creates MySQL connection 13 | func Connect(connectionString string) error { 14 | var err error 15 | Connector, err = gorm.Open("mysql", connectionString) 16 | if err != nil { 17 | return err 18 | } 19 | log.Println("Connection was successful!!") 20 | return nil 21 | } 22 | -------------------------------------------------------------------------------- /connect.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "rest-go-demo/database" 5 | 6 | _ "github.com/jinzhu/gorm/dialects/mysql" //Required for MySQL dialect 7 | ) 8 | 9 | func main() { 10 | config := 11 | database.Config{ 12 | ServerName: "localhost:3306", 13 | User: "root", 14 | Password: "root", 15 | DB: "learning", 16 | } 17 | 18 | connectionString := database.GetConnectionString(config) 19 | err := database.Connect(connectionString) 20 | if err != nil { 21 | panic(err.Error()) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /create.go: -------------------------------------------------------------------------------- 1 | 2 | func createPerson(w http.ResponseWriter, r *http.Request) { 3 | requestBody, _ := ioutil.ReadAll(r.Body) 4 | var person entity.Person 5 | json.Unmarshal(requestBody, &person) 6 | 7 | database.Connector.Create(person) 8 | w.Header().Set("Content-Type", "application/json") 9 | w.WriteHeader(http.StatusCreated) 10 | json.NewEncoder(w).Encode(person) 11 | } 12 | -------------------------------------------------------------------------------- /db.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import "fmt" 4 | 5 | //Config to maintain DB configuration properties 6 | type Config struct { 7 | ServerName string 8 | User string 9 | Password string 10 | DB string 11 | } 12 | 13 | var getConnectionString = func(config Config) string { 14 | connectionString := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&collation=utf8mb4_unicode_ci&parseTime=true&multiStatements=true", config.User, config.Password, config.ServerName, config.DB) 15 | return connectionString 16 | } 17 | -------------------------------------------------------------------------------- /delete.go: -------------------------------------------------------------------------------- 1 | func deletPersonByID(w http.ResponseWriter, r *http.Request) { 2 | vars := mux.Vars(r) 3 | key := vars["id"] 4 | 5 | var person entity.Person 6 | id, _ := strconv.ParseInt(key, 10, 64) 7 | database.Connector.Where("id = ?", id).Delete(&person) 8 | w.WriteHeader(http.StatusNoContent) 9 | } 10 | -------------------------------------------------------------------------------- /http.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | 7 | "github.com/gorilla/mux" 8 | ) 9 | 10 | func main() { 11 | log.Println("Starting the HTTP server on port 8090") 12 | router := mux.NewRouter().StrictSlash(true) 13 | log.Fatal(http.ListenAndServe(":8090", router)) 14 | } 15 | -------------------------------------------------------------------------------- /select.go: -------------------------------------------------------------------------------- 1 | func getPersonByID(w http.ResponseWriter, r *http.Request) { 2 | vars := mux.Vars(r) 3 | key := vars["id"] 4 | 5 | var person entity.Person 6 | database.Connector.First(&person, key) 7 | w.Header().Set("Content-Type", "application/json") 8 | json.NewEncoder(w).Encode(person) 9 | } 10 | -------------------------------------------------------------------------------- /update.go: -------------------------------------------------------------------------------- 1 | func updatePersonByID(w http.ResponseWriter, r *http.Request) { 2 | requestBody, _ := ioutil.ReadAll(r.Body) 3 | var person entity.Person 4 | json.Unmarshal(requestBody, &person) 5 | database.Connector.Save(&person) 6 | 7 | w.Header().Set("Content-Type", "application/json") 8 | w.WriteHeader(http.StatusOK) 9 | json.NewEncoder(w).Encode(person) 10 | } 11 | --------------------------------------------------------------------------------