Go实战--实现简单的restful api

生命不止,继续 Go go go !!!

今天跟大家介绍一下如何使用go创建一套restful api,我们依托于开源库gorilla/mux。

let’s go~~

何为RESTful API

A RESTful API is an application program interface (API) that uses HTTP requests to GET, PUT, POST and DELETE data.

A RESTful API – also referred to as a RESTful web service – is based on representational state transfer (REST) technology, an architectural style and approach to communications often used in web services development.

Wikipedia: 表征性状态传输(英文:Representational State Transfer,简称REST)是Roy Fielding博士于2000年在他的博士论文中提出来的一种软件架构风格。 Roy Fielding是HTTP协议(1.0版和1.1版)的主要设计者,事实上HTTP 1.1规范正是基于REST架构风格的指导原理来设计的。需要注意的是,REST是一种设计风格而不是标准,如果一个架构符合REST原则,我们就称它为RESTful架构。

gorilla/mux

github地址: https://github.com/gorilla/mux

golang自带的http.SeverMux路由实现简单,本质是一个map[string]Handler,是请求路径与该路径对应的处理函数的映射关系。实现简单功能也比较单一:

  1. 不支持正则路由, 这个是比较致命的
  2. 只支持路径匹配,不支持按照Method,header,host等信息匹配,所以也就没法实现RESTful架构

而gorilla/mux是一个强大的路由,小巧但是稳定高效,不仅可以支持正则路由还可以按照Method,header,host等信息匹配,可以从我们设定的路由表达式中提取出参数方便上层应用,而且完全兼容http.ServerMux

设置好了go的环境变量,直接运行:

go get -u github.com/gorilla/mux

实现

定义结构体,用户构造json

type Person struct {
    ID        string   `json:"id,omitemty"`
    Firstname string   `json:"firstname,omitempty"`
    Lastname  string   `json:"lastname,omitempty"`
    Address   *Address `json:"address,omitempty"`}type Address struct {
    City     string `json:"city,omitempty"`
    Province string `json:"province,omitempty"`}

接下来,定义一个全局变量,用于存储资源(数据):

var people []Person

对这个变量进行赋值:

people = append(people, Person{ID: "1", Firstname: "xi", Lastname: "dada", Address: &Address{City: "Shenyang", Province: "Liaoning"}})
people = append(people, Person{ID: "2", Firstname: "li", Lastname: "xiansheng", Address: &Address{City: "Changchun", Province: "Jinlin"}})

如果对go中的struct不够了解的可以看这里: http://blog.csdn.net/wangshubo1989/article/details/70040022

Get 获取所有person,这里我们叫people:

func GetPeople(w http.ResponseWriter, req *http.Request) {
    json.NewEncoder(w).Encode(people)
}

根据id获取person:

func GetPerson(w http.ResponseWriter, req *http.Request) {
    params := mux.Vars(req)    for _, item := range people {        if item.ID == params["id"] {
            json.NewEncoder(w).Encode(item)            return
        }
    }
    json.NewEncoder(w).Encode(people)
}

然后handle function:

    router := mux.NewRouter()
    router.HandleFunc("/people", GetPeople).Methods("GET")
    router.HandleFunc("/people/{id}", GetPerson).Methods("GET")

post 同样可以,通过post操作向服务器添加数据:

func PostPerson(w http.ResponseWriter, req *http.Request) {
    params := mux.Vars(req)    var person Person
    _ = json.NewDecoder(req.Body).Decode(&person)
    person.ID = params["id"]
    people = append(people, person)
    json.NewEncoder(w).Encode(people)
}

然后handle function:

router.HandleFunc("/people/{id}", PostPerson).Methods("POST")

Delete 根据id进行删除操作:

func DeletePerson(w http.ResponseWriter, req *http.Request) {
    params := mux.Vars(req)          for index, item := range people {                   if item.ID == params["id"] {
            people = append(people[:index], people[index+1:]...)                              break
        }
    }
    json.NewEncoder(w).Encode(people)
}

然后handle function:

router.HandleFunc("/people/{id}", DeletePerson).Methods("DELETE")

完整代码与运行结果

代码:

package main

import (           "encoding/json"
    "log"
    "net/http"

    "github.com/gorilla/mux")

type Person struct {
    ID        string   `json:"id,omitemty"`
    Firstname string   `json:"firstname,omitempty"`
    Lastname  string   `json:"lastname,omitempty"`
    Address   *Address `json:"address,omitempty"`
}

type Address struct {
    City     string `json:"city,omitempty"`
    Province string `json:"province,omitempty"`
}

var people []Person

func GetPerson(w http.ResponseWriter, req *http.Request) {
    params := mux.Vars(req)
    for _, item := range people {
        if item.ID == params["id"] {
            json.NewEncoder(w).Encode(item)
            return
        }
    }
    json.NewEncoder(w).Encode(people)
}

func GetPeople(w http.ResponseWriter, req *http.Request) {
    json.NewEncoder(w).Encode(people)
}

func PostPerson(w http.ResponseWriter, req *http.Request) {
    params := mux.Vars(req)
    var person Person
    _ = json.NewDecoder(req.Body).Decode(&person)
    person.ID = params["id"]
    people = append(people, person)
    json.NewEncoder(w).Encode(people)
}

func DeletePerson(w http.ResponseWriter, req *http.Request) {
    params := mux.Vars(req)
    for index, item := range people {
        if item.ID == params["id"] {
            people = append(people[:index], people[index+1:]...)            break
        }
    }
    json.NewEncoder(w).Encode(people)
}

func main() {
    router := mux.NewRouter()
    people = append(people, Person{ID: "1", Firstname: "xi", Lastname: "dada", Address: &Address{City: "Shenyang", Province: "Liaoning"}})
    people = append(people, Person{ID: "2", Firstname: "li", Lastname: "xiansheng", Address: &Address{City: "Changchun", Province: "Jinlin"}})
    router.HandleFunc("/people", GetPeople).Methods("GET")
    router.HandleFunc("/people/{id}", GetPerson).Methods("GET")
    router.HandleFunc("/people/{id}", PostPerson).Methods("POST")
    router.HandleFunc("/people/{id}", DeletePerson).Methods("DELETE")
    log.Fatal(http.ListenAndServe(":12345", router))
}

运行结果: Get People

package mainimport (          "fmt"
    "net/http"
    "io/ioutil")func main() {

    url := "http://localhost:12345/people"

    req, _ := http.NewRequest("GET", url, nil)

    req.Header.Add("accept", "application/json")
    req.Header.Add("authorization", "Basic d2FuZ3NodWJvOndhbmdzaHVibw==")
    req.Header.Add("cache-control", "no-cache")
    req.Header.Add("postman-token", "18774413-0c11-e312-7ed6-7bc4f8151f5a")

    res, _ := http.DefaultClient.Do(req)          defer res.Body.Close()
    body, _ := ioutil.ReadAll(res.Body)

    fmt.Println(res)
    fmt.Println(string(body))

}

Get Person

package mainimport (          "fmt"
    "strings"
    "net/http"
    "io/ioutil")func main() {

    url := "http://localhost:12345/people/1"

    payload := strings.NewReader("{\n  \"firstname\": \"wang\",\n  \"lastname\": \"shubo\",\n  \"address\": {\n    \"city\": \"Beijing\",\n    \"state\": \"Beijng\"\n  }\n}")

    req, _ := http.NewRequest("DELETE", url, payload)

    req.Header.Add("content-type", "application/json")
    req.Header.Add("cache-control", "no-cache")
    req.Header.Add("postman-token", "4a894ad6-2887-259a-c953-5d26fed70963")

    res, _ := http.DefaultClient.Do(req)          defer res.Body.Close()
    body, _ := ioutil.ReadAll(res.Body)

    fmt.Println(res)
    fmt.Println(string(body))

}

Post Person

package mainimport (           "fmt"
    "strings"
    "net/http"
    "io/ioutil")func main() {

    url := "http://localhost:12345/people/3"

    payload := strings.NewReader("{\n  \"firstname\": \"wang\",\n  \"lastname\": \"shubo\",\n  \"address\": {\n    \"city\": \"Beijing\",\n    \"state\": \"Beijng\"\n  }\n}")

    req, _ := http.NewRequest("POST", url, payload)

    req.Header.Add("content-type", "application/json")
    req.Header.Add("cache-control", "no-cache")
    req.Header.Add("postman-token", "a9d590dd-1819-15f6-962e-0eabf4b7e707")

    res, _ := http.DefaultClient.Do(req)          defer res.Body.Close()
    body, _ := ioutil.ReadAll(res.Body)

    fmt.Println(res)
    fmt.Println(string(body))

}

Delete Person

package mainimport (          "fmt"
    "strings"
    "net/http"
    "io/ioutil")func main() {

    url := "http://localhost:12345/people/1"

    payload := strings.NewReader("{\n  \"firstname\": \"wang\",\n  \"lastname\": \"shubo\",\n  \"address\": {\n    \"city\": \"Beijing\",\n    \"state\": \"Beijng\"\n  }\n}")

    req, _ := http.NewRequest("DELETE", url, payload)

    req.Header.Add("content-type", "application/json")
    req.Header.Add("cache-control", "no-cache")
    req.Header.Add("postman-token", "4c8d290e-4c6c-53f7-64e9-1d1f6ed19b09")

    res, _ := http.DefaultClient.Do(req)          defer res.Body.Close()
    body, _ := ioutil.ReadAll(res.Body)

    fmt.Println(res)
    fmt.Println(string(body))

}

原文发布于微信公众号 - 程序员的酒和故事(cppdabaojian)

原文发表时间:2017-05-04

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏BinarySec

一些pwn题目的解题思路[pwnable.kr] II

目录 以下是solution的目录 #mistake #shellshock #coin1 #blackjack #lotto #cmd1 Other 一些pw...

3745
来自专栏游戏杂谈

as3+php上传图片的三种方式

1)设置FlashDevelop使用flash player10(debug版本,因为有一个demo使用了本地预览)

1444
来自专栏菩提树下的杨过

Silverlight Telerik控件学习:弹出窗口RadWindow

几乎所有的业务系统都有弹出窗口,典型场景有二种 : 1、简单的弹出一个对话框显示信息,比如下面这样: ? 这个很简单,代码示例如下: DialogParamet...

2005
来自专栏落影的专栏

Audio Unit播放aac/m4a/mp3等文件

前言 相关文章: 使用VideoToolbox硬编码H.264 使用VideoToolbox硬解码H.264 使用AudioToolbox编码AAC 使...

80710
来自专栏Golang语言社区

Golang语言 实现线程池

1 type GoroutinePool struct { 2 Queue chan func() error 3 Number int ...

5225
来自专栏Ryan Miao

MongoDB - basic

mongoDB basic from:http://www.tutorialspoint.com/mongodb prject:https://github....

3196
来自专栏小尘哥的专栏

【springboot+easypoi】大数据量excel导出

上次写了一行代码解决导出导入,没看的小伙伴建议先看下《一行代码做Excel导入导出》,但是实际业务中遇到一个问题,如果数据里比较大的时候,例如10w+数据一次导...

1423
来自专栏Java3y

JsChart组件使用

JsChart是什么? JSChart能够在网页上生成图标,常用于统计信息,十分好用的一个JS组件。 使用JsChart 一。导入jscharts.js 二。编...

3829
来自专栏向治洪

React Native调用Android相机图库

概述 在很多的React Native开发中,我们需要调用原生的api实现调用相机和图库的功能,网上用的最多的开源库如:react-native-image-p...

2889
来自专栏ASP.NET MVC5 后台权限管理系统

ASP.NET MVC5+EF6+EasyUI 后台管理系统(7)-MVC与EasyUI DataGrid

本节知识点 为了符合后面更新后的重构系统,文章于2016-11-1日重写 EasyUI读取MVC后台Json数据 开始实现 我们的系统似乎越来越有趣了 首先...

3606

扫码关注云+社区