当前位置:网站首页>Building crud applications in golang
Building crud applications in golang
2022-06-27 12:02:00 【Hua Weiyun】
In this tutorial , We will be in Golang Build a CRUD Applications . We will use gorilla/mux Ku as api and PostgreSQL DB To store data .
stay $GOPATH Create a new project directory go-postgres.
stay go-postgres Open the terminal in the project . Instantiation go modular .
go mod init go-postgresInstallation dependency
We will use... In this project 3 A package , stay go-postgres Open the terminal in the project .
1. gorilla/mux router
gorilla/mux Packet implements a request router and scheduler , Used to match incoming requests to their respective handlers .
go get -u github.com/gorilla/mux2. lib/pq driver
Go Of database/sql Purity of package Go postgres The driver .
go get github.com/lib/pq We will use godotenv Package to read .env file . .env File to save environment variables . Environment variables are used to protect the security of sensitive data .
go get github.com/joho/godotenv Now? , open go.mod And check . All installed dependencies list the installed versions .
A similar , Versions can be different .
module go-postgresrequire ( github.com/gorilla/mux v1.7.4 github.com/joho/godotenv v1.3.0 github.com/lib/pq v1.3.0)install Postgres
PostgreSQL Is a powerful open source object relational database system . It is based on reliability 、 Known for functional robustness and performance .
After creating the instance . Now? , We have to create a table . go to ElephantSQL Medium Browser Tab and paste the following create table query and execute it . We use SERIAL Type as user ID. SERIAL Each insert is incremented automatically .
CREATE TABLE users ( userid SERIAL PRIMARY KEY, name TEXT, age INT, location TEXT);Project directory structure
The project is divided into 4 Parts of , To keep the code modular and clean .
The directory structure is :
|- go-postgres |- middleware |- handlers.go |- models |- models.go |- router |- router.go |- .env |- main.goModel
The model package will store the database schema . We will use struct Type to represent or map golang Database schema in .
stay go-postgres Create a new folder model in the project .
Create a new file in the model models.go And paste the following code .
package models// User schema of the user tabletype User struct { ID int64 `json:"id"` Name string `json:"name"` Location string `json:"location"` Age int64 `json:"age"`}User The structure is what we created above users Representation of tables .
middleware
The middleware package is API And database . This package will handle all database operations , If inserted 、 choice 、 Update and delete (CRUD).
Create a new folder middleware And create a new file in it handlers.go.
Paste the following code .
package middlewareimport ( "database/sql" "encoding/json" // package to encode and decode the json into struct and vice versa "fmt" "go-postgres/models" // models package where User schema is defined "log" "net/http" // used to access the request and response object of the api "os" // used to read the environment variable "strconv" // package used to covert string into int type "github.com/gorilla/mux" // used to get the params from the route "github.com/joho/godotenv" // package used to read the .env file _ "github.com/lib/pq" // postgres golang driver)// response formattype response struct { ID int64 `json:"id,omitempty"` Message string `json:"message,omitempty"`}// create connection with postgres dbfunc createConnection() *sql.DB { // load .env file err := godotenv.Load(".env") if err != nil { log.Fatalf("Error loading .env file") } // Open the connection db, err := sql.Open("postgres", os.Getenv("POSTGRES_URL")) if err != nil { panic(err) } // check the connection err = db.Ping() if err != nil { panic(err) } fmt.Println("Successfully connected!") // return the connection return db}// CreateUser create a user in the postgres dbfunc CreateUser(w http.ResponseWriter, r *http.Request) { // set the header to content type x-www-form-urlencoded // Allow all origin to handle cors issue w.Header().Set("Context-Type", "application/x-www-form-urlencoded") w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "POST") w.Header().Set("Access-Control-Allow-Headers", "Content-Type") // create an empty user of type models.User var user models.User // decode the json request to user err := json.NewDecoder(r.Body).Decode(&user) if err != nil { log.Fatalf("Unable to decode the request body. %v", err) } // call insert user function and pass the user insertID := insertUser(user) // format a response object res := response{ ID: insertID, Message: "User created successfully", } // send the response json.NewEncoder(w).Encode(res)}// GetUser will return a single user by its idfunc GetUser(w http.ResponseWriter, r *http.Request) { w.Header().Set("Context-Type", "application/x-www-form-urlencoded") w.Header().Set("Access-Control-Allow-Origin", "*") // get the userid from the request params, key is "id" params := mux.Vars(r) // convert the id type from string to int id, err := strconv.Atoi(params["id"]) if err != nil { log.Fatalf("Unable to convert the string into int. %v", err) } // call the getUser function with user id to retrieve a single user user, err := getUser(int64(id)) if err != nil { log.Fatalf("Unable to get user. %v", err) } // send the response json.NewEncoder(w).Encode(user)}// GetAllUser will return all the usersfunc GetAllUser(w http.ResponseWriter, r *http.Request) { w.Header().Set("Context-Type", "application/x-www-form-urlencoded") w.Header().Set("Access-Control-Allow-Origin", "*") // get all the users in the db users, err := getAllUsers() if err != nil { log.Fatalf("Unable to get all user. %v", err) } // send all the users as response json.NewEncoder(w).Encode(users)}// UpdateUser update user's detail in the postgres dbfunc UpdateUser(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/x-www-form-urlencoded") w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "PUT") w.Header().Set("Access-Control-Allow-Headers", "Content-Type") // get the userid from the request params, key is "id" params := mux.Vars(r) // convert the id type from string to int id, err := strconv.Atoi(params["id"]) if err != nil { log.Fatalf("Unable to convert the string into int. %v", err) } // create an empty user of type models.User var user models.User // decode the json request to user err = json.NewDecoder(r.Body).Decode(&user) if err != nil { log.Fatalf("Unable to decode the request body. %v", err) } // call update user to update the user updatedRows := updateUser(int64(id), user) // format the message string msg := fmt.Sprintf("User updated successfully. Total rows/record affected %v", updatedRows) // format the response message res := response{ ID: int64(id), Message: msg, } // send the response json.NewEncoder(w).Encode(res)}// DeleteUser delete user's detail in the postgres dbfunc DeleteUser(w http.ResponseWriter, r *http.Request) { w.Header().Set("Context-Type", "application/x-www-form-urlencoded") w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "DELETE") w.Header().Set("Access-Control-Allow-Headers", "Content-Type") // get the userid from the request params, key is "id" params := mux.Vars(r) // convert the id in string to int id, err := strconv.Atoi(params["id"]) if err != nil { log.Fatalf("Unable to convert the string into int. %v", err) } // call the deleteUser, convert the int to int64 deletedRows := deleteUser(int64(id)) // format the message string msg := fmt.Sprintf("User updated successfully. Total rows/record affected %v", deletedRows) // format the reponse message res := response{ ID: int64(id), Message: msg, } // send the response json.NewEncoder(w).Encode(res)}//------------------------- handler functions ----------------// insert one user in the DBfunc insertUser(user models.User) int64 { // create the postgres db connection db := createConnection() // close the db connection defer db.Close() // create the insert sql query // returning userid will return the id of the inserted user sqlStatement := `INSERT INTO users (name, location, age) VALUES ($1, $2, $3) RETURNING userid` // the inserted id will store in this id var id int64 // execute the sql statement // Scan function will save the insert id in the id err := db.QueryRow(sqlStatement, user.Name, user.Location, user.Age).Scan(&id) if err != nil { log.Fatalf("Unable to execute the query. %v", err) } fmt.Printf("Inserted a single record %v", id) // return the inserted id return id}// get one user from the DB by its useridfunc getUser(id int64) (models.User, error) { // create the postgres db connection db := createConnection() // close the db connection defer db.Close() // create a user of models.User type var user models.User // create the select sql query sqlStatement := `SELECT * FROM users WHERE userid=$1` // execute the sql statement row := db.QueryRow(sqlStatement, id) // unmarshal the row object to user err := row.Scan(&user.ID, &user.Name, &user.Age, &user.Location) switch err { case sql.ErrNoRows: fmt.Println("No rows were returned!") return user, nil case nil: return user, nil default: log.Fatalf("Unable to scan the row. %v", err) } // return empty user on error return user, err}// get one user from the DB by its useridfunc getAllUsers() ([]models.User, error) { // create the postgres db connection db := createConnection() // close the db connection defer db.Close() var users []models.User // create the select sql query sqlStatement := `SELECT * FROM users` // execute the sql statement rows, err := db.Query(sqlStatement) if err != nil { log.Fatalf("Unable to execute the query. %v", err) } // close the statement defer rows.Close() // iterate over the rows for rows.Next() { var user models.User // unmarshal the row object to user err = rows.Scan(&user.ID, &user.Name, &user.Age, &user.Location) if err != nil { log.Fatalf("Unable to scan the row. %v", err) } // append the user in the users slice users = append(users, user) } // return empty user on error return users, err}// update user in the DBfunc updateUser(id int64, user models.User) int64 { // create the postgres db connection db := createConnection() // close the db connection defer db.Close() // create the update sql query sqlStatement := `UPDATE users SET name=$2, location=$3, age=$4 WHERE userid=$1` // execute the sql statement res, err := db.Exec(sqlStatement, id, user.Name, user.Location, user.Age) if err != nil { log.Fatalf("Unable to execute the query. %v", err) } // check how many rows affected rowsAffected, err := res.RowsAffected() if err != nil { log.Fatalf("Error while checking the affected rows. %v", err) } fmt.Printf("Total rows/record affected %v", rowsAffected) return rowsAffected}// delete user in the DBfunc deleteUser(id int64) int64 { // create the postgres db connection db := createConnection() // close the db connection defer db.Close() // create the delete sql query sqlStatement := `DELETE FROM users WHERE userid=$1` // execute the sql statement res, err := db.Exec(sqlStatement, id) if err != nil { log.Fatalf("Unable to execute the query. %v", err) } // check how many rows affected rowsAffected, err := res.RowsAffected() if err != nil { log.Fatalf("Error while checking the affected rows. %v", err) } fmt.Printf("Total rows/record affected %v", rowsAffected) return rowsAffected}Let's break down the functions :
createConnection: This function will create a connection to postgreSQL Database connection and return the database connection .
Check the code in the function :
// use godotenv to load the .env fileerr := godotenv.Load(".env")// Read the POSTGRES_URL from the .env and connect to the db.db, err := sql.Open("postgres", os.Getenv("POSTGRES_URL")) stay go-postgres Create a new file in .env:
POSTGRES_URL="Postgres connection string"CreateUser: This is accessible api Request and response object handler for . It will extract the request body from the user . then , It will be called insertUser Pass the user as a parameter . insertUser Will return to insert idinsertUser: This function will execute an insert query in the database . First set up db Connect .
// create the postgres db connectiondb := createConnection()// close the db connectiondefer db.Close()establish SQL Inquire about :
sqlStatement := `INSERT INTO users (name, location, age) VALUES ($1, $2, $3) RETURNING userid`We didn't pass on users ID, Because the user ID yes SERIAL type . Its scope is 1 To 2,147,483,647.
Each insertion will add .
RETURNING userid This means that once the database is successfully inserted , Return to the user ID.
Execute insert query
var id int64err := db.QueryRow(sqlStatement, user.Name, user.Location, user.Age).Scan(&id)stay QueryRow Accept in sql Queries and parameters . stay sqlStatement in ,VALUES As a variable $1、$2、$3 Pass on . user.Name Is the first parameter , So it will replace $1. Again , All parameters will be replaced according to their position .
Use the scan to return to the user ID Decode as id
边栏推荐
- FileOutputStream
- 怎么找相同台词的影视片段?这8个电影搜索神器,一句台词找到对应片段
- Daily leetcode force deduction (21~25)
- matlab习题 —— 创建 50 行 50 列全零矩阵、全 1 矩阵、单位矩阵、对角矩阵,输出矩阵第135号元素。
- i.mx6ull(单片机) c语言环境搭建
- I.MX6ULL启动方式
- Excel中输入整数却总是显示小数,如何调整?
- Mqtt protocol stack principle and interaction flow chart
- 如何修改 node_modules 里的文件
- 盘点一些好用且小众的 Markdown 编辑器
猜你喜欢

Mqtt protocol stack principle and interaction flow chart
![[tcapulusdb knowledge base] Introduction to tcapulusdb general documents](/img/04/b1194ca3340b23a4fb2091d1b2a44d.png)
[tcapulusdb knowledge base] Introduction to tcapulusdb general documents

Wechat applet realizes five-star evaluation

Heap heap sort TOPK

C语言0长度数组的妙用

数学知识——博弈论(巴什博奕、尼姆博奕、威佐夫博奕)思路及例题

QStyle类用法总结(三)

如何修改 node_modules 裏的文件

Qstype implementation of self drawing interface project practice (I)

QStyle类用法总结(二)
随机推荐
杰理之DAC输出方式设置【篇】
Challenges of machine learning system in production
Four memory areas (stack, heap, global, code area)
Precautions for use of IO interface interrupt of Jerry [chapter]
JSP自定义标签
The R language uses the follow up The plot function visualizes the longitudinal follow-up map of multiple ID (case) monitoring indicators, and uses stress The labels parameter adds label information t
56. Core principle of flutter - flutter startup process and rendering pipeline
Don't miss it. New media operates 15 treasure official account to share
Salesforce 容器化 ISV 场景下的软件供应链安全落地实践
Jerry's seamless looping [chapter]
Go Web 编程入门:验证器
$15.8 billion! 2021 the world's top15 most profitable hedge fund giant
面试突击60:什么情况会导致 MySQL 索引失效?
[tcapulusdb knowledge base] tcapulusdb doc acceptance - create business introduction
Thinkphp6 interface limits user access frequency
R语言使用epiDisplay包的poisgof函数对泊松回归(Poisson Regression)执行拟合优度检验、检验是否存在过度离散问题(overdispersion)
The DBSCAN function of FPC package in R language performs density clustering analysis on data, and the plot function visualizes the clustering graph
Wechat applet payment password input
MapReduce principle analysis (in-depth source code)
"Internet +" contest topic hot docking | I figure to understand 38 propositions of Baidu