当前位置: 首页 > news >正文

使用 Go 构建一个最小的 API 应用

最近有项目要使用 Go 开发,作为一个. NET Core 选手,准备先撸一个包含 CRUD 的最小 MVP 项目练手。

要创建一个 TODO 应用,会创建下面这些接口:

APIDescriptionRequest bodyResponse body
GET /todoitemsGet all to-do itemsNoneArray of to-do items
GET /todoitems/completeGet completed to-do itemsNoneArray of to-do items
GET /todoitems/{id}Get an item by IDNoneTo-do item
POST /todoitemsAdd a new itemTo-do itemTo-do item
PUT /todoitems/{id}Update an existing itemTo-do itemNone
DELETE /todoitems/{id}Delete an itemNoneNone

我觉得,做这样一个 API 应用,不管是 Go 还是其他语言,思路是一样的,无外乎:SDK 版本、开发工具、服务容器、HTTP 请求和响应处理、数据库对应的语言驱动、实体定义和映射、JSON 处理等等。因此,其他语言怎么做,换成 Go 之后,找对应的工具和实现方案就可以了。

1 、快速搭建开发环境

  • 官方下载 SDK:Download and install - The Go Programming Language
  • 安装 VS Code:Download Visual Studio Code - Mac, Linux, Windows
  • 安装扩展:“Go”
  • 安装 Go 工具包: ctrl+shift+p ,输入 go install 回车后,选择全部工具安装

2、构建 API

2 .1、创建目录,初始化项目
go mod init todo-list-api

安装依赖包:

  • gorilla/mux 是一个强大的 HTTP 路由器和 URL 匹配器,用于构建 Go Web 服务器: gorilla/mux: Package gorilla/mux is a powerful HTTP router and URL matcher for building Go web servers with 🦍 (github.com)
go get -u github.com/gorilla/mux
  • Postgres 数据库的 Go 驱动包:lib/pq: Pure Go Postgres driver for database/sql (github.com)
go get github.com/lib/pq
2.2、入口函数

新增 main.go 文件,内容如下:

func main() {r := mux.NewRouter()r.HandleFunc("/api/todoitems", GetToDoItems).Methods("GET")r.HandleFunc("/api/todoitems/complete", GetToDoItemInCompleted).Methods("GET")r.HandleFunc("/api/todoitems/{id}", GetToDoItemById).Methods("GET")r.HandleFunc("/api/todoitems", CreateToDoItem).Methods("POST")r.HandleFunc("/api/todoitems/{id}", DeleteToDoItem).Methods("DELETE")r.HandleFunc("/api/todoitems/{id}", UpdateToDoItem).Methods("PUT")srv := &http.Server{Handler:      r,Addr:         ":3000",WriteTimeout: 15 * time.Second,ReadTimeout:  15 * time.Second,}log.Fatal(srv.ListenAndServe())
}

HandleFunc 函数第一个参数是路由路径,第二个参数是处理函数,然后链式调用 Methods 指定可以处理的 HTTP 请求类型。

2.3、实体和数据库

新增 db.go 文件,内容如下:

var DB *sql.DB
func ConnectToDatabase() {connStr := "user=postgres dbname=postgres password=Mysoft7789 sslmode=disable"db, err := sql.Open("postgres", connStr)if err != nil {log.Fatal(err)}DB = db
}

这个函数用来打开并获取数据库连接,放在 init 方法中调用

func init() {ConnectToDatabase()
}

定义结构类型 ToDo,内容如下:

type Todo struct {Id         int    `json:"id"`Name       string `json:"name"`IsComplete bool   `json:"is_complete"`
}

创建 postgres 数据表

create table public.t_todo_item  
(  id          integer generated by default as identity,  name        varchar(20),  is_complete boolean  
);
2 .4、实现 API

新增 todo-service.go 实现所有的 API

func GetToDoItems(w http.ResponseWriter, r *http.Request) {rows, err := DB.Query("select id,name,is_complete from t_todo_item")if err != nil {panic(err.Error())}var todos []Todofor rows.Next() {var todo Todoerr = rows.Scan(&todo.Id, &todo.Name, &todo.IsComplete)if err != nil {log.Printf("Error happened in scan row. Err: %s", err)w.WriteHeader(http.StatusInternalServerError)return}todos = append(todos, todo)}jsonResp, err := json.Marshal(todos)if err != nil {log.Fatalf("Error happened in JSON marshal. Err: %s", err)w.WriteHeader(http.StatusInternalServerError)return}w.Header().Set("Content-Type", "application/json")w.Write(jsonResp)
}func GetToDoItemInCompleted(w http.ResponseWriter, r *http.Request) {rows, err := DB.Query("select id,name,is_complete from t_todo_item where is_complete = true")if err != nil {panic(err.Error())}var todos []Todofor rows.Next() {var todo Todoerr = rows.Scan(&todo.Id, &todo.Name, &todo.IsComplete)if err != nil {log.Printf("Error happened in scan row. Err: %s", err)w.WriteHeader(http.StatusInternalServerError)return}todos = append(todos, todo)}jsonResp, err := json.Marshal(todos)if err != nil {log.Fatalf("Error happened in JSON marshal. Err: %s", err)w.WriteHeader(http.StatusInternalServerError)return}w.Header().Set("Content-Type", "application/json")w.Write(jsonResp)
}func CreateToDoItem(w http.ResponseWriter, r *http.Request) {// convert todo struct from bodyvar todo Todoerr := json.NewDecoder(r.Body).Decode(&todo)if err != nil {log.Printf("Error happened in JSON unmarshal. Err: %s", err)return}// insert into dberr = DB.QueryRow("insert into t_todo_item (name, is_complete) values ($1, $2) RETURNING id", todo.Name, false).Scan(&todo.Id)if err != nil {log.Printf("Error happened in insert into db. Err: %s", err)w.WriteHeader(http.StatusInternalServerError)return}// return created todojsonResp, _ := json.Marshal(todo)w.Header().Set("Content-Type", "application/json")w.Write(jsonResp)
}func GetToDoItemById(w http.ResponseWriter, r *http.Request) {vars := mux.Vars(r)id := vars["id"]row := DB.QueryRow("select id,name, is_complete from t_todo_item where id = $1", id)var todo Todorow.Scan(&todo.Id, &todo.Name, &todo.IsComplete)jsonResp, err := json.Marshal(todo)if err != nil {log.Fatalf("Error happened in JSON marshal. Err: %s", err)w.WriteHeader(http.StatusInternalServerError)return}w.Header().Set("Content-Type", "application/json")w.Write(jsonResp)
}func DeleteToDoItem(w http.ResponseWriter, r *http.Request) {// check id from urlvars := mux.Vars(r)// convert id to intid, err := strconv.Atoi(vars["id"])if err != nil {log.Printf("Error happened in convert id to int. Err: %s", err)w.WriteHeader(http.StatusBadRequest)return}// if id less then 0, return 400if condition := id < 0; condition {w.WriteHeader(http.StatusBadRequest)return}// delete from db_, err = DB.Exec("delete from t_todo_item where id = $1", id)if err != nil {log.Printf("Error happened in delete from db. Err: %s", err)w.WriteHeader(http.StatusInternalServerError)return}w.WriteHeader(http.StatusOK)
}func UpdateToDoItem(w http.ResponseWriter, r *http.Request) {// check id from urlvars := mux.Vars(r)// convert id to intid, err := strconv.Atoi(vars["id"])if err != nil {log.Printf("Error happened in convert id to int. Err: %s", err)w.WriteHeader(http.StatusBadRequest)return}// if id less then 0, return 400if condition := id < 0; condition {w.WriteHeader(http.StatusBadRequest)return}// convert todo struct from bodyvar todo Todoerr = json.NewDecoder(r.Body).Decode(&todo)if err != nil {log.Printf("Error happened in JSON unmarshal. Err: %s", err)}todo.Id = id// update db_, err = DB.Exec("update t_todo_item set name = $1, is_complete = $2 where id = $3", todo.Name, todo.IsComplete, id)if err != nil {log.Printf("Error happened in update db. Err: %s", err)w.WriteHeader(http.StatusInternalServerError)return}w.WriteHeader(http.StatusOK)
}
2.5、测试验证

新增一个 todo.http 文件,内容如下:

# GET request to retrieve all todo itemsGET http://localhost:3000/api/todoitems HTTP/1.1#### GET request to retrieve a specific todo item by idGET http://localhost:3000/api/todoitems/20 HTTP/1.1#### GET request to retrieve all completed todo itemsGET http://localhost:3000/api/todoitems/complete HTTP/1.1  #### POST request to create a new todo itemPOST http://localhost:3000/api/todoitems HTTP/1.1Content-Type: application/json  {"name": "Buy grocerie1"
}#### PUT request to update an existing todo itemPUT http://localhost:3000/api/todoitems/20 HTTP/1.1Content-Type: application/json{"name": "Buy groceries","is_complete": true
}#### DELETE request to delete a todo itemDELETE http://localhost:3000/api/todoitems/2 HTTP/1.1

完工了。

相关文章:

使用 Go 构建一个最小的 API 应用

最近有项目要使用 Go 开发&#xff0c;作为一个. NET Core 选手&#xff0c;准备先撸一个包含 CRUD 的最小 MVP 项目练手。 要创建一个 TODO 应用&#xff0c;会创建下面这些接口&#xff1a; APIDescriptionRequest bodyResponse bodyGET /todoitemsGet all to-do itemsNone…...

MySQL 日常维护指南:常见任务、频率及问题解决

MySQL 作为一种广泛使用的开源关系型数据库&#xff0c;随着数据量和应用复杂性的增加&#xff0c;定期的数据库维护对于保持系统高效运行至关重要。通过合理的日常维护&#xff0c;数据库管理员能够确保 MySQL 数据库的稳定性、性能以及数据的完整性。本文将介绍 MySQL 的常见…...

oracle ORA-24920:列大小对于客户机过大

问题描述 在一次读取某个视图数据过程中&#xff0c;当数据读取到x条时&#xff0c;报错ORA-24920&#xff1a;列大小对于客户机过大。 通过查询资料得知&#xff0c;oracle 数据库升级到了12c&#xff0c;VARCHAR2的容量也从4000升级到了32767。 所以猜测某个字段的长度超过4…...

使用 Docker compose 部署 Nacos(达梦数据库)

1. 制作镜像的源码地址 https://github.com/wangsilingwsl/nacos-dm.git 参考的开源项目&#xff1a;https://github.com/jeecgboot/JeecgBoot/tree/master/jeecg-boot/jeecg-server-cloud/jeecg-cloud-nacos &#xff08;master分支&#xff1b;tag&#xff1a;v3.7.1&#…...

人工智能 | 阿里通义千问大模型

简介 通义千问系列模型为阿里云研发的大语言模型。千问模型基于 Transformer 架构&#xff0c;在超大规模的预训练数据上进行训练得到。预训练数据类型多样&#xff0c;覆盖广泛&#xff0c;包括大量网络文本、专业书籍、代码等。同时&#xff0c;在预训练模型的基础之上&…...

Windows环境下Qt Creator调试模式下qDebug输出中文乱码问题

尝试修改系统的区域设置的方法&#xff1a; 可以修复问题。但会出现其它问题&#xff1a; 比如某些软件打不开&#xff0c;或者一些软件界面的中文显示乱码&#xff01; 暂时没有找到其它更好的办法。...

java防止表单重复提交的注解@RepeatSubmit

代码解释 RepeatSubmit 是一个自定义注解&#xff0c;通常用于防止表单重复提交。这个注解可以应用于控制器方法上&#xff0c;以确保同一个请求在一定时间内不会被多次提交。以下是一些常见的参数和用法&#xff1a; value: 注解的名称或描述。 interval: 两次请求之间的最小间…...

HTTP快速入门

HTTP报文结构 HTTP 协议主要由三大部分组成&#xff1a; ● 起始行&#xff08;start line&#xff09;&#xff1a;描述请求或响应的基本信息&#xff1b; ● 头部字段&#xff08;header&#xff09;&#xff1a;使用 key-value 形式更详细地说明报文&#xff1b; ● 消息正…...

Nacos简介

Nacos是一个开源的动态服务发现、配置管理和服务管理平台&#xff0c;由阿里巴巴集团开发并开源。它提供了服务注册与发现、配置管理、动态DNS服务、服务健康监测、权重和流量管理等核心特性&#xff0c;非常适合构建云原生应用和微服务架构。 Nacos的核心功能包括&#xff1a…...

基于深度学习的稳健的模型推理与不确定性建模

基于深度学习的稳健模型推理与不确定性建模&#xff0c;是现代AI系统中至关重要的研究方向。随着深度学习在各类应用中的成功&#xff0c;如何保证模型在面对未知或不确定性输入时仍能做出稳健的推理&#xff0c;并能够量化这种不确定性&#xff0c;成为关键问题。稳健性与不确…...

C语言 sizeof 的介绍,以及sizeof计算数组名、 数组首地址、数组的元素之间的区别

一、sizeof 介绍 sizeof 是 C 语言中的一个运算符&#xff0c;用于计算数据类型或变量在内存中占用的字节数。用于计算数据类型或变量所占的内存大小&#xff0c;以字节为单位。它可以在编译时计算其操作数的大小&#xff0c;并返回一个 size_t 类型的值。它可以帮助了解不同类…...

深入理解Oracle闪回技术

引言&#xff1a; Oracle 闪回&#xff08;Flashback&#xff09;是一组强大的功能&#xff0c;用于恢复数据库中的数据或对象到过去的某个时间点或状态&#xff0c;而无需进行传统的基于备份和恢复的操作。 Oracle 闪回的主要类型 1. 闪回查询&#xff08;Flashback Query&…...

Go 语言初探

Google 公司有一个传统,允许员工利用 20% 的工作时间开发自己的实验项目。2007 年 9月,UTF-8 的设计者之一 Rob Pike(罗布.皮克)在 Google 的分布式编译平台上进行 C++ 编译时,与同事 Robert Griesemer (罗布.格里泽默)在漫长的等待中讨论了编程语言面临的主要问题。他们一…...

使用ROS资源编排一键部署LNMP建站环境,手动整理教程

LNMP是目前主流的网站服务器架构之一&#xff0c;适合运行大型和高并发的网站应用&#xff0c;例如电子商务网站、社交网络、内容管理系统等。LNMP分别代表Linux、Nginx、MySQL和PHP。本文阿里云服务器网aliyunfuwuqi.com介绍如何使用阿里云资源编排服务&#xff08;ROS&#x…...

猎板PCB镍钯金工艺你了解多少?

PCB镍钯金工艺&#xff0c;也称为ENEPIG&#xff08;Electroless Nickel Electroless PALLADIum Gold&#xff09;工艺&#xff0c;是一种在PCB表面处理中使用的先进工艺。这种工艺通过在PCB线路板上形成一层镍钯合金层&#xff0c;有效地提高了线路板的耐氧化性、耐腐蚀性和可…...

热更新解决方案2 —— Lua语法相关知识点

概述 开发环境搭建 Lua语法 1.第一个Lua程序 2.变量 print("******变量*******"); --lua当中的简单变量类型 -- nil number string boolean -- lua 中所有的变量声明 都不需要声明变量类型 它会自动的判断类型 -- 类似C# 中的var --lua中的一个变量 可以随便赋值 ——…...

【c++ arx选项板】

static void xlArx_gmenu(void) {if (!g_pPaletteSetEx){g_pPaletteSetEx=CTunnelSectionPaletteSetEx::Instance(...

新时代下吉林省城乡流动人才就业问题及路径探析

摘要&#xff1a;新时代背景下&#xff0c;中国经济快速发展&#xff0c;城乡融合发展成为缩小城乡差距&#xff0c;推动共同富裕的重要方式。吉林省作为东北老工业基地&#xff0c;传统产业竞争优势减弱&#xff0c;城乡流动人才就业规模增加&#xff0c;并呈现“农村-城市”的…...

Go 1.19.4 命令调用、日志、包管理、反射-Day 17

1. 系统命令调用 所谓的命令调用&#xff0c;就是通过os&#xff0c;找到系统中编译好的可执行文件&#xff0c;然后加载到内存中&#xff0c;变成进程。 1.1 exec.LookPath&#xff08;寻找命令&#xff09; 作用&#xff1a; exec.LookPath 函数用于在系统的环境变量中搜索可…...

Unity 2d UI 实时跟随场景3d物体

2d UI 实时跟随场景3d物体位置&#xff0c;显示 3d 物体头顶信息&#xff0c;看起来像是场景中的3dUI&#xff0c;实质是2d UIusing System.Collections; using System.Collections.Generic; using UnityEngine; using DG.Tweening; using UnityEngine.UI; /// <summary>…...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

(十)学生端搭建

本次旨在将之前的已完成的部分功能进行拼装到学生端&#xff0c;同时完善学生端的构建。本次工作主要包括&#xff1a; 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解

【关注我&#xff0c;后续持续新增专题博文&#xff0c;谢谢&#xff01;&#xff01;&#xff01;】 上一篇我们讲了&#xff1a; 这一篇我们开始讲&#xff1a; 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下&#xff1a; 一、场景操作步骤 操作步…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?

在建筑行业&#xff0c;项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升&#xff0c;传统的管理模式已经难以满足现代工程的需求。过去&#xff0c;许多企业依赖手工记录、口头沟通和分散的信息管理&#xff0c;导致效率低下、成本失控、风险频发。例如&#…...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...

Web 架构之 CDN 加速原理与落地实践

文章目录 一、思维导图二、正文内容&#xff08;一&#xff09;CDN 基础概念1. 定义2. 组成部分 &#xff08;二&#xff09;CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 &#xff08;三&#xff09;CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 &#xf…...

深度学习习题2

1.如果增加神经网络的宽度&#xff0c;精确度会增加到一个特定阈值后&#xff0c;便开始降低。造成这一现象的可能原因是什么&#xff1f; A、即使增加卷积核的数量&#xff0c;只有少部分的核会被用作预测 B、当卷积核数量增加时&#xff0c;神经网络的预测能力会降低 C、当卷…...

什么是VR全景技术

VR全景技术&#xff0c;全称为虚拟现实全景技术&#xff0c;是通过计算机图像模拟生成三维空间中的虚拟世界&#xff0c;使用户能够在该虚拟世界中进行全方位、无死角的观察和交互的技术。VR全景技术模拟人在真实空间中的视觉体验&#xff0c;结合图文、3D、音视频等多媒体元素…...

Java详解LeetCode 热题 100(26):LeetCode 142. 环形链表 II(Linked List Cycle II)详解

文章目录 1. 题目描述1.1 链表节点定义 2. 理解题目2.1 问题可视化2.2 核心挑战 3. 解法一&#xff1a;HashSet 标记访问法3.1 算法思路3.2 Java代码实现3.3 详细执行过程演示3.4 执行结果示例3.5 复杂度分析3.6 优缺点分析 4. 解法二&#xff1a;Floyd 快慢指针法&#xff08;…...

[USACO23FEB] Bakery S

题目描述 Bessie 开了一家面包店! 在她的面包店里&#xff0c;Bessie 有一个烤箱&#xff0c;可以在 t C t_C tC​ 的时间内生产一块饼干或在 t M t_M tM​ 单位时间内生产一块松糕。 ( 1 ≤ t C , t M ≤ 10 9 ) (1 \le t_C,t_M \le 10^9) (1≤tC​,tM​≤109)。由于空间…...