In this post, we will not only cover how to use Go to create a RESTful JSON API, but we will also talk about good RESTful design.

部分内容删减调整,原文请查看: Making a RESTful JSON API in Go,2014Nov

Author:CORY LANOU:a full stack technologist who has specialized in start-ups for the last 17 years. I'm currently working at InfluxDB on their core data team. I also help lead and organizer several community technology meetups and do Go training.

What is a JSON API?

JSON API 是数据交互规范,用以定义客户端如何获取与修改资源,以及服务器如何响应对应请求。JSON API设计用来最小化请求的数量,以及客户端与服务器间传输的数据量。通过遵循共同的约定,可以提高开发效率,利用更普遍的工具,基于 JSON API 的客户端还能够充分利用缓存,以提升性能。(更多:http://jsonapi.org.cn/format/)。

示例:

{
"links": {
"posts.author": {
"href": "http://example.com/people/{posts.author}",
"type": "people"
},
"posts.comments": {
"href": "http://example.com/comments/{posts.comments}",
"type": "comments"
}
},
"posts": [{
"id": "1",
"title": "Rails is Omakase",
"links": {
"author": "9",
"comments": [ "5", "12", "17", "20" ]
}
}]
}

启动一个RESTful服务

$ go run main.go

$ curl http://localhost:8080
Hello,"/"
package main

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

增加路径分发功能

路径又称"终点"(endpoint),表示API的具体网址。在RESTful架构中,每个网址代表一种资源(resource)。 第三方组件(Gorilla Mux package): “github.com/gorilla/mux”

package main

import (
"fmt"
"log"
"net/http"
"github.com/gorilla/mux"
) func main() {
router := mux.NewRouter().StrictSlash(true)
router.HandleFunc("/", 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)
}

访问测试:

$ curl http://localhost:8080/todo
404 page not found
$ curl http://localhost:8080/todos
Todo Index! ,"/todos"
$ curl http://localhost:8080/todos/{123}
TodoShow: ,"123"

抽象数据模型

创建一个数据模型“Todo”、“Routes”。在其它语言中,使用类(class)实现。 在Go语言中,没有class,必须使用结构(struct)。

Todo.go

package main

import "time"

type Todo struct {
Id int `json:"id"`
Name string `json:"name"`
Completed bool `json:"completed"`
Due time.Time `json:"due"`
} type Todos []Todo

Routes.go

package main

import (
"net/http"
"github.com/gorilla/mux"
) type Route struct {
Name string
Method string
Pattern string
HandlerFunc http.HandlerFunc
} type Routes []Route

重构:Handlers & Router

Handlers.go

package main

import (
"encoding/json"
"fmt"
"net/http"
"github.com/gorilla/mux"
) func Index(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Welcome!")
} func TodoIndex(w http.ResponseWriter, r *http.Request) {
todos := Todos{
Todo{Name: "Write presentation"},
Todo{Name: "Host meetup"},
} if err := json.NewEncoder(w).Encode(todos); err != nil {
panic(err)
}
} func TodoShow(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
todoId := vars["todoId"]
fmt.Fprintln(w, "Todo show:", todoId)
}

Router.go

package main

import (
"net/http"
"github.com/gorilla/mux"
) func NewRouter() *mux.Router {
router := mux.NewRouter().StrictSlash(true)
for _, route := range routes {
var handler http.Handler
handler = route.HandlerFunc
handler = Logger(handler, route.Name) router.
Methods(route.Method).
Path(route.Pattern).
Name(route.Name).
Handler(handler) }
return router
}

启动入口是不是清爽很多!

Main.go

Main.go
package main import (
"log"
"net/http"
) func main() {
router := NewRouter()
log.Fatal(http.ListenAndServe(":8080", router))
}

web access:http://localhost:8080/todos

Todo Index! ,"/todos" [ { "id":0, "name":"Write sth ....", "completed":false, "due":"0001-01-01T00:00:00 }, { "id":1, "name":"Host meetup ....", "completed":false, "due":"0001-01-01T00:00:00Z" } ]

增强功能:持久化

func TodoCreate(w http.ResponseWriter, r *http.Request) {
var todo Todo
//add Todo instance
}

增强功能:日志

2017/05/23 15:57:23 http: multiple response.WriteHeader calls
2017/05/23 15:57:23 GET /todos TodoIndex 6.945807ms
2017/05/23 16:18:40 http: multiple response.WriteHeader calls
2017/05/23 16:18:40 GET /todos TodoIndex 2.127435ms

Things We Didn’t Do

  1. 版本控制 API版本迭代 & 跨版本资源访问。常用做法是将版本号放在URL,较为简洁,例如:https://localhost:8080/v1/ 另一种做法是将版本号放在HTTP头信息中。

  2. 授权验证:涉及到OAuth和JWT。 (1)OAuth 2.0,OAuth2 is an authentication framework,RFC 6749 OAuth2是一种授权框架,提供了一套详细的、可供实践的指导性解决方案。OAuth 2.0定义了四种授权方式。授权码模式(authorization code)、简化模式(implicit)、密码模式(resource owner password credentials)、客户端模式(client credentials)。

(2)JSON web tokens,JWT is an authentication protocol,RFC 7519 JWT是一种安全协议。基本思路就是用户提供用户名和密码给认证服务器,服务器验证用户提交信息信息的合法性;如果验证成功,会产生并返回一个Token(令牌),用户可以使用这个token访问服务器上受保护的资源。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

header:定义算法(alg:ALGORITHM)和TOKEN TYPE(typ)

{
"alg": "HS256",
"typ": "JWT"
}

Data:

{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
  1. eTags:关于缓存、性能和用户标识和追踪。

https://my.oschina.net/zijingshanke/blog/907955

基于Go语言快速构建RESTful API服务的更多相关文章

  1. 基于gin web框架搭建RESTful API服务

    这篇主要学习go项目中的项目结构.项目规范等知识,ROM采用的database/sql的写法. 1.技术框架 利用的是ginweb框架,然后ROM层选用database/sql,安装mysql驱动.安 ...

  2. 用 Go 快速开发一个 RESTful API 服务

    何时使用单体 RESTful 服务 对于很多初创公司来说,业务的早期我们更应该关注于业务价值的交付,而单体服务具有架构简单,部署简单,开发成本低等优点,可以帮助我们快速实现产品需求.我们在使用单体服务 ...

  3. 基于jersey和Apache Tomcat构建Restful Web服务(一)

    基于jersey和Apache Tomcat构建Restful Web服务(一) 现如今,RESTful架构已然成为了最流行的一种互联网软件架构,它结构清晰.符合标准.易于理解.扩展方便,所以得到越来 ...

  4. 基于jersey和Apache Tomcat构建Restful Web服务(二)

    基于jersey和Apache Tomcat构建Restful Web服务(二) 上篇博客介绍了REST以及Jersey并使用其搭建了一个简单的“Hello World”,那么本次呢,再来点有趣的东西 ...

  5. 使用 Spring 3 MVC HttpMessageConverter 功能构建 RESTful web 服务

    原文地址:http://www.ibm.com/developerworks/cn/web/wa-restful/ 简介: Spring,构建 Java™ 平台和 Enterprise Edition ...

  6. 使用Express构建RESTful API

    RESTful服务 REST(Representational State Transfer)的意思是表征状态转移,它是一种基于HTTP协议的网络应用接口风格,充分利用HTTP的方法实现统一风格接口的 ...

  7. 用于构建 RESTful Web 服务的多层架构

    作者:Bruce Sun, Java 架构师, IBM 出处:http://www.ibm.com/developerworks/cn/web/wa-aj-multitier/ 用于构建 RESTfu ...

  8. 使用ASP.NET Core 3.x 构建 RESTful API - 2. 什么是RESTful API

    1. 使用ASP.NET Core 3.x 构建 RESTful API - 1.准备工作 什么是REST REST一词最早是在2000年,由Roy Fielding在他的博士论文<Archit ...

  9. 使用ASP.NET Core构建RESTful API的技术指南

    译者荐语:利用周末的时间,本人拜读了长沙.NET技术社区翻译的技术标准<微软RESTFul API指南>,打算按照步骤写一个完整的教程,后来无意中看到了这篇文章,与我要写的主题有不少相似之 ...

随机推荐

  1. gcc新版本号引起的编译错误(命令运行时的外部库输入位置)

    昨天,遇到一个比較bug的错误,用gcc来编译几个简单的文件出错,编译环境为x86_64的Ubuntu12.04.gcc版本号号例如以下: gcc (Ubuntu/Linaro 4.6.3-1ubun ...

  2. [TypeScript] Increase TypeScript's type safety with noImplicitAny

    TypeScript tries to infer as much about your code as it can. But sometimes there really is not enoug ...

  3. 关于使用Timer定时监测网络是否ping通

    项目需要连接某台具体服务端,如果连不上则实时提示,开始使用Timer实时检测 void timer_Tick(object sender, EventArgs e) { Ping pingSender ...

  4. QT类库与Delphi VCL类库的体系结构对比——两者十分类似!

    今天在看QT对象内存管理的一篇文章时:http://blog.csdn.net/dbzhang800/article/details/6300025想到了一个问题:就是QT类库体系结构与Delphi类 ...

  5. Ruby开发环境

    Windows上Ruby开发环境的配置   最近公司项目上有需要,需要开发一个puppet的自动化工具,这个工具需要操作存储设备上的各种资源,而鉴于puppet不是善于完成这个任务的首选语言,于是我们 ...

  6. Python 编程规范 —— TODO 注释(结合 PyCharm)

    编程是代码和注释的统一: TODO 自然表示需要做而未做的一些待完成的事项,有助于事后的检索,以及对整体项目做进一步的修改迭代. # TODO(kl@gmail.com): Use a "* ...

  7. iOS开发 - OC - block的详解 - 基础篇

    深入理解oc中的block 苹果在Mac OS X10.6 和iOS 4之后引入了block语法.这一举动对于许多OC使用者的编码风格改变很大.就我本人而言,感觉block用起来还是很爽的,但一直以来 ...

  8. Java:JSON解析工具-org.json

    一.简介 org.json是Java常用的Json解析工具,主要提供JSONObject和JSONArray类,现在就各个类的使用解释如下. 二.准备 1.在使用org.json之前,我们应该先从该网 ...

  9. Android之高仿手机QQ聊天

    源代码下载 转载请注明出处,谢谢! 最终版已上传.优化下拉刷新.增加来消息声音提示.主界面改成ViewPager,实现左右滑动.新增群组.最近会话显示条数,开始上班了,不再修改了.谢谢! 国庆这几天, ...

  10. &lt;模拟电子学习1&gt;Multisim 12.0 结构和仿真51最小的单芯片系统

    周围环境: 系统环境: win7 64位置 软件平台:Multisim 12.0 目的: 刚毕业,可是模电知识也忘得差点儿相同了,加之自己想搞搞硬件设计.假设仅仅是看模电书.不实践,还是终觉浅.当做兴 ...