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

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


生命不止,继续 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(
        "%st%st%qt%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")
    }
}

最后运行结果:
这里写图片描述

这里写图片描述

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/wangshubo1989/article/details/77163336
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2019-09-05 13:21:18
  • 阅读 ( 1714 )
  • 分类:Redis

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢