当前位置:网站首页>在 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)
边栏推荐
- SAP Business Technology Platform (BTP) workflow function introduction
- Leaflet that supports canvas Path. Dashflow dynamic flow direction line
- C # graphic tutorial (Fourth Edition) chapter7-7.6.1 virtual and override
- Leetcode 2200. Find all k nearest neighbor subscripts in the array (yes, one pass)
- scala中的隐式转换和隐式参数讲解与实践
- 线上真实排队系统重构案例分享——实战篇
- Develop a web office suite from scratch (5): mouse hover over text
- SAP 业务技术平台(BTP) Workflow(工作流)功能介绍
- [SciPy optimization tutorial] v. quick solution of univariate function optimization
- VHDL编程实验练习题合集
猜你喜欢
Is the revised PMP worth testing?
Leaflet that supports canvas Path. Dashflow dynamic flow direction line
Start of u-boot_ Armboot analysis (I)
Is the PMP training organization an actual training?
2022 electrician (elementary) operation certificate examination question bank and online simulation examination
【Matlab】符号计算
SAP QM qp03 displays an inspection plan with multiple specs inspection features
2022年危险化学品经营单位安全管理人员考试试题及在线模拟考试
Enterprise wechat H5_ Authentication, PC website, enterprise wechat scanning code, authorized login
2022年电工(初级)操作证考试题库及在线模拟考试
随机推荐
Enterprise wechat H5_ Authentication, H5 application web page authorization login to obtain identity
PMP renewal | PDU specific operation diagram
你真的会用PostGIS中的buffer缓冲吗?
2022年G3锅炉水处理考题模拟考试平台操作
Start of u-boot S analysis (III)
Lower interest rates lead to higher bond prices
Is divicon still used in leaflet in H5 era?
【Matlab】矩阵操作
基于Three.js海上风电数字孪生三维效果
Talent Weekly - 5
vs studio_ How to use scanf in 2022
Do you have to read for PMP?
H5时代leaflet中还在用DivIcon?
How to make maputnik, a vector tile matching artifact, support GeoServer
Deep feature synthesis and genetic feature generation, comparison of two automatic feature generation strategies
[SciPy optimization tutorial] v. quick solution of univariate function optimization
SAP UI5 如何通过 manifest.json 文件定义第三方库依赖关系
Pytorch loading model error resolution
[issue 30] shopee golang development experience
CS for mobile security [nethunter]