您的位置:首页 > 理论基础 > 计算机网络

Go实战--通过httprouter和redis框架搭建restful api服务(github.com/julienschmidt/httprouter)

2017-08-14 16:35 1051 查看
生命不止,继续 go go go !!!

博客《Go实战–通过gin-gonic框架搭建restful api服务(github.com/gin-gonic/gin)》跟大家介绍了使用gin+mysql搭建一个restful api服务,今天主要介绍的是httprouter+redis搭建restful api服务。

httprouter

HttpRouter is a lightweight high performance HTTP request router (also called multiplexer or just mux for short) for Go.

github地址:

https://github.com/julienschmidt/httprouter

获取:

go get github.com/julienschmidt/httprouter


应用:

package main

import (
"fmt"
"log"
"net/http"

"github.com/julienschmidt/httprouter"
)

func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
fmt.Fprint(w, "Welcome!\n")
}

func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
fmt.Fprintf(w, "hello, %s!\n", ps.ByName("name"))
}

func main() {
router := httprouter.New()
router.GET("/", Index)
router.GET("/hello/:name", Hello)

log.Fatal(http.ListenAndServe(":8080", router))
}




redigo/redis

golang中使用redis这里不再过多的介绍,之前的博客有写过:

Go实战–golang中使用redis(redigo和go-redis/redis)

package main

import (
"fmt"

"github.com/garyburd/redigo/redis"
)

func main() {
c, err := redis.Dial("tcp", "127.0.0.1:6379")
if err != nil {
fmt.Println("Connect to redis error", err)
return
}
defer c.Close()

_, err = c.Do("SET", "mykey", "superWang")
if err != nil {
fmt.Println("redis set failed:", err)
}

username, err := redis.String(c.Do("GET", "mykey"))
if err != nil {
fmt.Println("redis get failed:", err)
} else {
fmt.Printf("Get mykey: %v \n", username)
}
}


搭建rest api

参考地址:

https://medium.com/code-zen/rest-apis-server-in-go-and-redis-66e9cb80a71b

这里创建一个简单的博客系统,具有以下功能:

http://localhost/ 显示欢迎消息,

http://localhost/posts 显示所有posts

http://localhost/posts/id 根据id显示post

首先是写model:

models.go

如果你对于golang中结构体不是很了解,可以看看这篇博客:

Go语言学习之struct(The way to go)

主要是字段标签

package main

import (
"time"
)

type User struct {
Id       int        `json:"id"`
Username string     `json:"username"`
Email    string     `json:"email"`
}

type Comment struct {
Id        int       `json:"id"`
User      User      `json:"user"`
Text      string    `json:"text"`
Timestamp time.Time `json:"timestamp"`
}

type Post struct {
Id        int       `json:"id"`
User      User      `json:"user"`
Topic     string    `json:"topic"`
Text      string    `json:"text"`
Comment   Comment   `json:"comment"`
Timestamp time.Time `json:"timestamp"`
}

type Posts    []Post
type Comments []Comment
type Users    []User


routes.go

列出所有的路由:

package main

import (
mux "github.com/julienschmidt/httprouter"
)

type Route struct {
Name    string
Method  string
Pattern string
Handle  mux.Handle
}

type Routes []Route

var routes = Routes{
Route{
"Index",
"GET",
"/",
Index,
},
Route{
"PostIndex",
"GET",
"/posts",
PostIndex,
},
Route{
"PostShow",
"GET",
"/posts/:postId",
PostShow,
},
Route{
"PostCreate",
"POST",
"/posts",
PostCreate,
},
Route{
"PostDelete",
"POST",
"/posts/del/:postId",
PostDelete,
},
}


handlers.go

有路由就要有handler。

关于io/ioutil请参考下面博客:

《Go语言学习之ioutil包(The way to go)

关于log包请参考下面博客:

Go语言学习之log包(The way to go)

package main

import (
"encoding/json"
"fmt"
"net/http"
"io"
"io/ioutil"
"strconv"
"log"
"time"

mux "github.com/julienschmidt/httprouter"
)

func Logger(r *http.Request) {

start:= time.Now()

log.Printf(
"%s\t%s\t%q\t%s",
r.Method,
r.RequestURI,
r.Header,
time.Since(start),
)
}

func Index(w http.ResponseWriter, r *http.Request, _ mux.Params) {

fmt.Fprintf(w, "<h1 style=\"font-family: Helvetica;\">Hello, welcome to blog service</h1>")
}

func PostIndex(w http.ResponseWriter, r *http.Request, _ mux.Params) {

w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)

var posts Posts

posts = FindAll()

if err := json.NewEncoder(w).Encode(posts); err != nil {
panic(err)
}

}

func PostShow(w http.ResponseWriter, r *http.Request, ps mux.Params) {

id, err := strconv.Atoi(ps.ByName("postId"))

HandleError(err)

post := FindPost(id)

if err := json.NewEncoder(w).Encode(post); err != nil {
panic(err)
}
}

func PostCreate(w http.ResponseWriter, r *http.Request, _ mux.Params) {

Logger(r)

var post Post
body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1048576))
HandleError(err)

if err := r.Body.Close(); err != nil {
panic(err)
}

// Save JSON to Post struct
if err := json.Unmarshal(body, &post); err != nil {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(422) // unprocessable entity
if err := json.NewEncoder(w).Encode(err); err != nil {
panic(err)
}
}

CreatePost(post)
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusCreated)
}

func PostDelete(w http.ResponseWriter, r *http.Request, ps mux.Params) {

id, err := strconv.Atoi(ps.ByName("postId"))
HandleError(err)

DeletePost(id)
}


router.go

package main

import (
mux "github.com/julienschmidt/httprouter"
)

func NewRouter() *mux.Router {

router := mux.New()

for _, route := range routes {

router.Handle(route.Method, route.Pattern, route.Handle)
}

return router
}


db.go

最后就是数据库相关操作了,这里使用redis。

这里需要注意的就是string到json的转换。

关于strconv的用法可以参考博客:

Go语言学习之strconv包(The way to go)

例如,将整数转换为十进制字符串形式

func Itoa(i int) string

关于json的用法可以参考博客:

Go语言学习之encoding/json包(The way to go)

关于time包的用法可以参考博客:

Go语言学习之time包(获取当前时间戳等)(the way to go)

例如:获取当前时间

func Now() Time


下面是db的完整代码:

package main

import (
"fmt"
"time"
"encoding/json"
"strconv"

"github.com/garyburd/redigo/redis"
)

var currentPostId int
var currentUserId int

func RedisConnect() redis.Conn {
c, err := redis.Dial("tcp", ":6379")
HandleError(err)
return c
}

// Give us some seed data
func init() {

CreatePost(Post{
User: User{
Username: "wangshubo",
Email: "wangshubo1989@126.com",
},
Topic: "My First Post",
Text:  "Hello everyone! This is awesome.",
})

CreatePost(Post{
User: User{
Username: "superWang",
Email: "wangshubo@gmail.com",
},
Topic: "Greeting",
Text: "Greetings from Ironman",
})
}

func FindAll() Posts {

c := RedisConnect()
defer c.Close()

keys, err := c.Do("KEYS", "post:*")

HandleError(err)

var posts Posts

for _, k := range keys.([]interface{}) {

var post Post

reply, err := c.Do("GET", k.([]byte))

HandleError(err)

if err := json.Unmarshal(reply.([]byte), &post); err != nil {
panic(err)
}
posts = append(posts, post)
}
return posts
}

func FindPost(id int) Post {

var post Post

c := RedisConnect()
defer c.Close()

reply, err := c.Do("GET", "post:" + strconv.Itoa(id))

HandleError(err)

fmt.Println("GET OK")

if err = json.Unmarshal(reply.([]byte), &post); err != nil {
panic(err)
}
return post
}

func CreatePost(p Post) {

currentPostId += 1
currentUserId += 1

p.Id = currentPostId
p.User.Id = currentUserId
p.Timestamp = time.Now()

c := RedisConnect()
defer c.Close()

b, err := json.Marshal(p)

HandleError(err)

// Save JSON blob to Redis
reply, err := c.Do("SET", "post:" + strconv.Itoa(p.Id), b)

HandleError(err)

fmt.Println("GET ", reply)

}

func DeletePost(id int) {

c := RedisConnect()
defer c.Close()

reply, err := c.Do("DEL", "post:" + strconv.Itoa(id))
HandleError(err)

if reply.(int) != 1 {
fmt.Println("No post removed")
} else {
fmt.Println("Post removed")
}
}


最后运行结果:



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐