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. PHP移动互联网开发笔记(4)——自定义函数及数组

    一.自定义函数 自定义函数就是我们自己定义的函数,在PHP中自定义函数格式如下: function funname(arg1, arg2, arg3......){ //TODO return val ...

  2. 线程基础:JDK1.5+(9)——线程新特性(中)

    (接上文<线程基础:JDK1.5+(8)--线程新特性(上)>) 3.工作在多线程环境下的"计数器": 从这个小节開始,我们将以一个"赛跑"的样例. ...

  3. js时间和时间戳之间如何转换(汇总)

    js时间和时间戳之间如何转换(汇总) 一.总结 一句话总结: 1.js中通过new Date()来获取时间对象, 2.这个时间对象可以通过getTime()方法获取时间戳, 3.也可以通过getYea ...

  4. Erlang与ActionScript3采用JSON格式进行Socket通讯

    http://hideto.iteye.com/blog/235811 需要下载as3corelib来为ActionScript3处理JSON codec server.erl -module(ser ...

  5. erlang中如何调试程序

    学习一门语言,当学习那些基本语法的时候,我们常常会忽略它的程序调试,当程序稍微复杂一点的时候,我们不能保证程序的完全正确,我们会为其发愁,这时,程序的调试就变得相当重要了.    在erlang环境搭 ...

  6. 英文构词法 —— circum- 前缀

    1. - circum-:表示环绕,周围,圆周: circle:圆:循环: circumference:圆周,周长,胸围: circumstance:环境: circumnavigation:环球航行 ...

  7. MapReduce 切片机制源码分析

    总体来说大概有以下2个大的步骤 1.连接集群(yarnrunner或者是localjobrunner) 2.submitter.submitJobInternal()在该方法中会创建提交路径,计算切片 ...

  8. spring boot jar包 linux 部署

    前提: jar包路径:/usr/local/lib/app/app.jar 1.首先先用vi创建文件 命令: cd /usr/local/lib/app/vi app-start.sh 2.在文件ap ...

  9. apt-get install 的参数(add-apt-repository)

    apt-get install 是 ubuntu 下的软件安装命令. sudo apt-get -y install: -y:yes,在命令行交互提示中,直接输入 yes: 1. 使用 add-apt ...

  10. vue 百度地图

    <template lang="pug"> #select-area-in-map-content #show-message-info el-popover(plac ...