当前位置:网站首页>在 Golang 中构建 CRUD 应用程序
在 Golang 中构建 CRUD 应用程序
2022-06-12 23:52:00 【InfoQ】
gorilla/mux
go mod init go-postgres
安装依赖
gorilla/mux
go get -u github.com/gorilla/mux
database/sql
go get github.com/lib/pq
.env
.env
go get github.com/joho/godotenv
go.mod
module go-postgres
require (
github.com/gorilla/mux v1.7.4
github.com/joho/godotenv v1.3.0
github.com/lib/pq v1.3.0
)
安装 Postgres
CREATE TABLE users (
userid SERIAL PRIMARY KEY,
name TEXT,
age INT,
location TEXT
);
项目目录结构
|- go-postgres
|- middleware
|- handlers.go
|- models
|- models.go
|- router
|- router.go
|- .env
|- main.go
模型
go-postgres
models.go
package models
// User schema of the user table
type User struct {
ID int64 `json:"id"`
Name string `json:"name"`
Location string `json:"location"`
Age int64 `json:"age"`
}
中间件
middleware
handlers.go
package middleware
import (
"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 format
type response struct {
ID int64 `json:"id,omitempty"`
Message string `json:"message,omitempty"`
}
// create connection with postgres db
func 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 db
func 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 id
func 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 users
func 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 db
func 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 db
func 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 DB
func 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 userid
func 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 userid
func 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 DB
func 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 DB
func 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
}
createConnection
:此函数将创建与 postgreSQL 数据库的连接并返回数据库连接。
// use godotenv to load the .env file
err := godotenv.Load(".env")
// Read the POSTGRES_URL from the .env and connect to the db.
db, err := sql.Open("postgres", os.Getenv("POSTGRES_URL"))
.env
POSTGRES_URL="Postgres connection string"
CreateUser
:这是可以访问 api 的请求和响应对象的处理函数。它将在用户中提取请求正文。然后,它会调用 insertUser 作为参数传递用户。 insertUser 将返回插入 id
insertUser
:此函数将在数据库中执行插入查询。首先建立db连接。
// create the postgres db connection
db := createConnection()
// close the db connection
defer db.Close()
sqlStatement := `INSERT INTO users (name, location, age) VALUES ($1, $2, $3) RETURNING userid`
RETURNING userid
var id int64
err := db.QueryRow(sqlStatement, user.Name, user.Location, user.Age).Scan(&id)
边栏推荐
- How to make maputnik, a vector tile matching artifact, support GeoServer
- Cherry Blossom powder Dudu
- SAP QM qp03 displays an inspection plan with multiple specs inspection features
- Start blogging
- [matlab] two dimensional curve
- Test platform series (97) perfect the case part
- How to package a colorpicker component for color selection?
- Accelerating with Dali modules
- Running of NCF dapr application instance
- Develop a web office suite from scratch (5): mouse hover over text
猜你喜欢
如何让矢量瓦片配图神器maputnik支持 geoserver
AWS lambda: how to store secrets to external APIs- AWS Lambda: How to store secret to external API?
Don't write about the full screen explosion, try the decorator mode, this is the elegant way!!
2022年电工(初级)操作证考试题库及在线模拟考试
What occupation is suitable for PMP?
Based on three JS offshore wind power digital twin 3D effect
2022 electrician (elementary) operation certificate examination question bank and online simulation examination
[leetcode] understanding and usage of map[key]+
Free lottery --- PMP renewal PDU | PMP knowledge map
CV—BaseLine总结(从AlexNet到SENet的发展历程)
随机推荐
SAP UI5 如何通过 manifest.json 文件定义第三方库依赖关系
Printf segment error (core dump): a problem caused by formatted output
Huawei cloud elastic ECS use [Huawei cloud to jianzhiyuan]
Cherry Blossom powder Dudu
【Matlab】矩阵
SAP 业务技术平台(BTP) Workflow(工作流)功能介绍
你真的会用PostGIS中的buffer缓冲吗?
How to publish OSM maps locally and customize the mapping
C # graphic tutorial (Fourth Edition) chapter7-7.6.1 virtual and override
CV - baseline summary (development history from alexnet to senet)
【Matlab】矩阵变换与矩阵求值
Will PM (Project Manager) take the PMP Exam?
The most complete preview! Huawei cloud wonderful agenda collection
Start of u-boot S analysis (IV)
What can PMP bring to you
CV—BaseLine总结(从AlexNet到SENet的发展历程)
Xi'an Jiaotong 22nd autumn e-commerce technology online expansion resources (IV) [standard answer]
How about opening a securities account in flush? Is it safe or not
Why does the PMP certificate need to be renewed and the renewal process?
Develop a web office suite from scratch (5): mouse hover over text