当前位置:首页 > Windows程序 > 正文

使用Go构建RESTful的JSON API

2021-03-18 Windows程序

原文地址
这篇文章不仅仅讨论如何使用Go构建RESTful的JSON API,同时也会讨论如何设计好的RESTful API。如果你曾经遭遇了未遵循良好设计的API,那么你最终将写烂代码来使用这些垃圾API。希望阅读这篇文章后,你能够对好的API应该是怎样的有更多的认识。

JSON API是啥?

在JSON前,XML是一种主流的文本格式。笔者有幸XML和JSON都使用过,毫无疑问,JSON是明显的赢家。本文不会深入涉及JSON API的概念,在jsonapi.org可以找到的详细的描述。

Sponsor Note

SpringOne2GX是一个专门面向App开发者、解决方案和数据架构师的会议。议题都是专门针对程序猿(媛),架构师所使用的流行的开源技术,如:Spring IO Projects,Groovy & Grails,Cloud Foundry,RabbitMQ,Redis,Geode,,Hadoop and Tomcat等。

一个基本的Web Server

一个RESTful服务本质上首先是一个Web service。下面的是示例是一个最简单的Web server,对于任何请求都简单的直接返回请求链接:

package main import ( "fmt" "html" "log" "net/http" ) func main() { http.HandleFunc("http://www.mamicode.com/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path)) }) log.Fatal(http.ListenAndServe(":8080", nil)) }

编译执行这个示例将运行这个server,监听8080端口。尝试使用:8080访问server。

增加一个路由

当大多数标准库开始支持路由,我发现大多数人都搞不清楚它们是如何工作的。我在项目中使用过几个第三方的router。印象最深的是Gorilla Web Toolkit中的mux router.

另一个比较流行的router是Julien Schmidt贡献的httprouter

package main import ( "fmt" "html" "log" "net/http" "github.com/gorilla/mux" ) func main() { router := mux.NewRouter().StrictSlash(true) router.HandleFunc("http://www.mamicode.com/", Index) log.Fatal(http.ListenAndServe(":8080", router)) } func Index(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path)) }

运行上面的示例,首先需要安装包“github.com/gorilla/mux”.可以直接使用命令go get遍历整个source code安装所有未安装的依赖包。

译者注:

也可以使用go get "github.com/gorilla/mux"直接安装包。

上面的示例创建了一个简单的router,增加了一个“/”路由,并分配Index handler响应针对指定的endpoint的访问。这是你会发现在第一个示例中还能访问的如:8080/foo这类的链接在这个示例中不再工作了,这个示例将只能响应链接:8080.

创建更多的基本路由

上一节我们已经有了一个路由,是时候创建更多的路由了。假设我们将要创建一个基本的TODO app。

package main import ( "fmt" "log" "net/http" "github.com/gorilla/mux" ) func main() { router := mux.NewRouter().StrictSlash(true) router.HandleFunc("http://www.mamicode.com/", Index) router.HandleFunc("/todos", TodoIndex) router.HandleFunc("/todos/{todoId}", TodoShow) log.Fatal(http.ListenAndServe(":8080", router)) } func Index(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Welcome!") } func TodoIndex(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Todo Index!") } func TodoShow(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) todoId := vars["todoId"] fmt.Fprintln(w, "Todo show:", todoId) }

现在我们又在上一个示例的基础上增加了两个routes,分别是:

这就是一个RESTful设计的开始。注意,最后一个路由我们增加了一个名为todoId的变量。这将允许我们向route传递变量,然后获得合适的响应记录。

基本样式

有了路由后,就可以创建一些基本的TODO样式用于发送和检索数据。在一些其他语言中使用类(class)来达到这个目的,Go中使用struct。

package main import “time” type Todo struct { Name string Completed tool Due time.time } type Todos []Todo 注:

最后一行定义的类型Todos是Todo的slice。稍后你将会看到怎么使用它。

返回JSON

基于上面的基本样式,我们可以模拟真实的响应,并基于静态数据列出TodoIndex。

func TodoIndex(w http.ResponseWriter, r *http.Request) { todos := Todos{ Todo{Name: "Write presentation"}, Todo{Name: "Host meetup"}, } json.NewEncoder(w).Encode(todos) }

这样就创建了一个Todos的静态slice,并被编码响应用户请求。如果这时你访问:8080/todos,你将得到如下响应:

[ { "Name": "Write presentation", "Completed": false, "Due": "0001-01-01T00:00:00Z" }, { "Name": "Host meetup", "Completed": false, "Due": "0001-01-01T00:00:00Z" } ] 一个稍微好点的样式

可能你已经发现了,基于前面的样式,todos返回的并不是一个标准的JSON数据包(JSON格式定义中不包含大写字母)。虽然这个问题有那么一点微不足道,但是我们还是可以解决它:

package main import "time" type Todo struct { Name string `json:"name"` Completed bool `json:"completed"` Due time.Time `json:"due"` } type Todos []Todo

上面的代码示例在原来的基础上增加了struct tags,这样可以指定JSON的编码格式。

文件拆分

到此我们需要对这个项目稍微做下重构。现在一个文件包含了太多的内容。我们将创建如下几个文件,并重新组织文件内容:

main.go

handlers.go

routes.go

温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/63035.html