Go實戰--golang中使用echo框架、MongoDB、JWT搭建REST API(labstack/echo、gopkg.in/mgo.v2、dgrijalva/jwt-go)
生命不止,繼續go go go !!!
今天,繼續echo框架,這次加入mongodb作為持久化儲存,使用jwt進行驗證,來搭建一套rest api,類似Twitter。
程式碼結構:
./model
post.go
user.go
./handler
handler.go
post.go
user.go
main.go
model
這裡沒有什麼好說的,就是建立model,需要注意的就是golang中struct中的標籤。
一個使用者user,一個郵箱post。
user.go
package model
import (
"gopkg.in/mgo.v2/bson"
)
type (
User struct {
ID bson.ObjectId `json:"id" bson:"_id,omitempty"`
Email string `json:"email" bson:"email"`
Password string `json:"password,omitempty" bson:"password"`
Token string `json:"token,omitempty" bson:"-"`
Followers []string `json:"followers,omitempty" bson:"followers,omitempty"`
}
)
post.go
package model
import (
"gopkg.in/mgo.v2/bson"
)
type (
Post struct {
ID bson.ObjectId `json:"id" bson:"_id,omitempty"`
To string `json:"to" bson:"to"`
From string `json:"from" bson:"from"`
Message string `json:"message" bson:"message"`
}
)
handler
handler.go
handler中提出出來的公共部分。
package handler
import (
"gopkg.in/mgo.v2"
)
type (
Handler struct {
DB *mgo.Session
}
)
const (
// Key (Should come from somewhere else).
Key = "secret"
)
package handler
import (
"go_echo_examples/twitter/model"
"net/http"
"strconv"
"github.com/labstack/echo"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
func (h *Handler) CreatePost(c echo.Context) (err error) {
u := &model.User{
ID: bson.ObjectIdHex(userIDFromToken(c)),
}
p := &model.Post{
ID: bson.NewObjectId(),
From: u.ID.Hex(),
}
if err = c.Bind(p); err != nil {
return
}
// Validation
if p.To == "" || p.Message == "" {
return &echo.HTTPError{Code: http.StatusBadRequest, Message: "invalid to or message fields"}
}
// Find user from database
db := h.DB.Clone()
defer db.Close()
if err = db.DB("twitter").C("users").FindId(u.ID).One(u); err != nil {
if err == mgo.ErrNotFound {
return echo.ErrNotFound
}
return
}
// Save post in database
if err = db.DB("twitter").C("posts").Insert(p); err != nil {
return
}
return c.JSON(http.StatusCreated, p)
}
func (h *Handler) FetchPost(c echo.Context) (err error) {
userID := userIDFromToken(c)
page, _ := strconv.Atoi(c.QueryParam("page"))
limit, _ := strconv.Atoi(c.QueryParam("limit"))
// Defaults
if page == 0 {
page = 1
}
if limit == 0 {
limit = 100
}
// Retrieve posts from database
posts := []*model.Post{}
db := h.DB.Clone()
if err = db.DB("twitter").C("posts").
Find(bson.M{"to": userID}).
Skip((page - 1) * limit).
Limit(limit).
All(&posts); err != nil {
return
}
defer db.Close()
return c.JSON(http.StatusOK, posts)
}
package handler
import (
"go_echo_examples/twitter/model"
"net/http"
"time"
"github.com/dgrijalva/jwt-go"
"github.com/labstack/echo"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
func (h *Handler) Signup(c echo.Context) (err error) {
// Bind
u := &model.User{ID: bson.NewObjectId()}
if err = c.Bind(u); err != nil {
return
}
// Validate
if u.Email == "" || u.Password == "" {
return &echo.HTTPError{Code: http.StatusBadRequest, Message: "invalid email or password"}
}
// Save user
db := h.DB.Clone()
defer db.Close()
if err = db.DB("twitter").C("users").Insert(u); err != nil {
return
}
return c.JSON(http.StatusCreated, u)
}
func (h *Handler) Login(c echo.Context) (err error) {
// Bind
u := new(model.User)
if err = c.Bind(u); err != nil {
return
}
// Find user
db := h.DB.Clone()
defer db.Close()
if err = db.DB("twitter").C("users").
Find(bson.M{"email": u.Email, "password": u.Password}).One(u); err != nil {
if err == mgo.ErrNotFound {
return &echo.HTTPError{Code: http.StatusUnauthorized, Message: "invalid email or password"}
}
return
}
//-----
// JWT
//-----
// Create token
token := jwt.New(jwt.SigningMethodHS256)
// Set claims
claims := token.Claims.(jwt.MapClaims)
claims["id"] = u.ID
claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
// Generate encoded token and send it as response
u.Token, err = token.SignedString([]byte(Key))
if err != nil {
return err
}
u.Password = "" // Don't send password
return c.JSON(http.StatusOK, u)
}
func (h *Handler) Follow(c echo.Context) (err error) {
userID := userIDFromToken(c)
id := c.Param("id")
// Add a follower to user
db := h.DB.Clone()
defer db.Close()
if err = db.DB("twitter").C("users").
UpdateId(bson.ObjectIdHex(id), bson.M{"$addToSet": bson.M{"followers": userID}}); err != nil {
if err == mgo.ErrNotFound {
return echo.ErrNotFound
}
}
return
}
func userIDFromToken(c echo.Context) string {
user := c.Get("user").(*jwt.Token)
claims := user.Claims.(jwt.MapClaims)
return claims["id"].(string)
}
main
最後的main.go就相對很簡單了。
main.go
package main
import (
"go_echo_examples/twitter/handler"
"github.com/labstack/echo"
"github.com/labstack/echo/middleware"
"github.com/labstack/gommon/log"
"gopkg.in/mgo.v2"
)
func main() {
e := echo.New()
e.Logger.SetLevel(log.ERROR)
e.Use(middleware.Logger())
e.Use(middleware.JWTWithConfig(middleware.JWTConfig{
SigningKey: []byte(handler.Key),
Skipper: func(c echo.Context) bool {
// Skip authentication for and signup login requests
if c.Path() == "/login" || c.Path() == "/signup" {
return true
}
return false
},
}))
// Database connection
db, err := mgo.Dial("localhost")
if err != nil {
e.Logger.Fatal(err)
}
// Create indices
if err = db.Copy().DB("twitter").C("users").EnsureIndex(mgo.Index{
Key: []string{"email"},
Unique: true,
}); err != nil {
log.Fatal(err)
}
// Initialize handler
h := &handler.Handler{DB: db}
// Routes
e.POST("/signup", h.Signup)
e.POST("/login", h.Login)
e.POST("/follow/:id", h.Follow)
e.POST("/posts", h.CreatePost)
e.GET("/feed", h.FetchPost)
// Start server
e.Logger.Fatal(e.Start(":1323"))
}
測試
啟動mongodb服務
mongod.exe --dbpath d:\mongodb_data\db
成功的話,結果:
2017-11-27T00:17:22.201-0700 I CONTROL [initandlisten] MongoDB starting : pid=17792 port=27017 dbpath=d:\mongodb_data\db 64-bit host=LAPTOP-MNU6522J
2017-11-27T00:17:22.202-0700 I CONTROL [initandlisten] targetMinOS: Windows 7/Windows Server 2008 R2
2017-11-27T00:17:22.202-0700 I CONTROL [initandlisten] db version v3.4.6
2017-11-27T00:17:22.203-0700 I CONTROL [initandlisten] git version: c55eb86ef46ee7aede3b1e2a5d184a7df4bfb5b5
2017-11-27T00:17:22.203-0700 I CONTROL [initandlisten] OpenSSL version: OpenSSL 1.0.1u-fips 22 Sep 2016
2017-11-27T00:17:22.204-0700 I CONTROL [initandlisten] allocator: tcmalloc
2017-11-27T00:17:22.204-0700 I CONTROL [initandlisten] modules: none
2017-11-27T00:17:22.204-0700 I CONTROL [initandlisten] build environment:
2017-11-27T00:17:22.204-0700 I CONTROL [initandlisten] distmod: 2008plus-ssl
2017-11-27T00:17:22.205-0700 I CONTROL [initandlisten] distarch: x86_64
2017-11-27T00:17:22.205-0700 I CONTROL [initandlisten] target_arch: x86_64
2017-11-27T00:17:22.205-0700 I CONTROL [initandlisten] options: { storage: { dbPath: "d:\mongodb_data\db" } }
2017-11-27T00:17:22.261-0700 I - [initandlisten] Detected data files in d:\mongodb_data\db created by the 'wiredTiger' storage engine, so setting the active storage engine to 'wiredTiger'.
2017-11-27T00:17:22.271-0700 I STORAGE [initandlisten] wiredtiger_open config: create,cache_size=3540M,session_max=20000,eviction=(threads_min=4,threads_max=4),config_base=false,statistics=(fast),log=(enabled=true,archive=true,path=journal,compressor=snappy),file_manager=(close_idle_time=100000),checkpoint=(wait=60,log_size=2GB),statistics_log=(wait=0),
2017-11-27T00:17:24.247-0700 I CONTROL [initandlisten]
2017-11-27T00:17:24.248-0700 I CONTROL [initandlisten] ** WARNING: Access control is not enabled for the database.
2017-11-27T00:17:24.259-0700 I CONTROL [initandlisten] ** Read and write access to data and configuration is unrestricted.
2017-11-27T00:17:24.260-0700 I CONTROL [initandlisten]
2017-11-27T15:17:25.037+0800 I FTDC [initandlisten] Initializing full-time diagnostic data capture with directory 'd:/mongodb_data/db/diagnostic.data'
2017-11-27T15:17:25.046+0800 I NETWORK [thread1] waiting for connections on port 27017
執行main.go
mongodb控制檯:
2017-11-27T15:23:39.223+0800 I NETWORK [thread1] connection accepted from 127.0.0.1:51150 #2 (1 connection now open)
2017-11-27T15:23:39.501+0800 I INDEX [conn2] build index on: twitter.users properties: { v: 2, unique: true, key: { email: 1 }, name: "email_1", ns: "twitter.users" }
2017-11-27T15:23:39.501+0800 I INDEX [conn2] building index using bulk method; build may temporarily use up to 500 megabytes of RAM
2017-11-27T15:23:39.529+0800 I INDEX [conn2] build index done. scanned 0 total records. 0 secs
2017-11-27T15:23:39.530+0800 I COMMAND [conn2] command twitter.$cmd command: createIndexes { createIndexes: "users", indexes: [ { name: "email_1", ns: "twitter.users", key: { email: 1 }, unique: true } ] } numYields:0 reslen:113 locks:{ Global: { acquireCount: { r: 1, w: 1 } }, Database: { acquireCount: { W: 1 } }, Collection: { acquireCount: { w: 1 } } } protocol:op_query 303ms
使用者註冊
使用postman或是curl命令,這裡使用curl命令了:
curl -X POST http://localhost:1323/signup -H "Content-Type:application/json" -d '{"email" :"[email protected]"m", "password":"test"}'
登入
curl -X POST http://localhost:1323/login -H "Content-Type:application/json" -d '{"email" :"[email protected]", "password":"test"}'
返回:
{"id":"5a1bbe92271c7c5ac875e40e","email":"[email protected]","token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MTIwMjcwOTgsImlkIjoiNWExYmJlOTIyNzFjN2M1YWM4NzVlNDBlIn0.V__5q0fipKfPhcGop1rDiOX5lFc7qSVz9bVfJ5zycvo"}
Follow使用者
curl -X POST http://localhost:1323/follow/5a1bbe92271c7c5ac875e40e -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MTIwMjcwOTgsImlkIjoiNWExYmJlOTIyNzFjN2M1YWM4NzVlNDBlIn0.V__5q0fipKfPhcGop1rDiOX5lFc7qSVz9bVfJ5zycvo"
傳送訊息(郵件)
curl -X POST http://localhost:1323/posts -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MTIwMjcwOTgsImlkIjoiNWExYmJlOTIyNzFjN2M1YWM4NzVlNDBlIn0.V__5q0fipKfPhcGop1rDiOX5lFc7qSVz9bVfJ5zycvo" -H "Content-Type: application/json" -d '{"to":"58465b4ea6fe886d3215c6df","message":"hello"}'
相關推薦
Go實戰--golang中使用echo框架、MongoDB、JWT搭建REST API(labstack/echo、gopkg.in/mgo.v2、dgrijalva/jwt-go)
生命不止,繼續go go go !!! 今天,繼續echo框架,這次加入mongodb作為持久化儲存,使用jwt進行驗證,來搭建一套rest api,類似Twitter。 程式碼結構: ./model post.go user.
Go實戰--golang中使用Goji微框架(Goji+Mongodb構建微服務)
生命不止,繼續 go go go!!! 今天跟大家分享一個web微框架Goji. Goji What is Goji? 枸杞? Goji is a HTTP request multiplexer, similar to net/http.Serv
Go實戰--golang中操作PDF(rsc.io/pdf、jung-kurt/gofpdf、signintech/gopdf)
生命不止,繼續 go go go !!! 那麼今天就跟大家分享一下,golang中如何操作PDF。 PDF簡介 The Portable Document Format (PDF) is a file format used to present do
Go實戰--golang中使用HTTPS以及TSL(.crt、.key、.pem區別以及crypto/tls包介紹)
HTTP與HTTPS 在WWDC 2016上,蘋果在釋出iOS 9的同時也向開發者傳遞了一個訊息,那就是到2017年1月1日時App Store中所有應用都必須啟用 App Transport Security應用程式安全傳輸協議,從而提升應用和系統安全性。 HTTP
Go實戰--golang中讀寫檔案的幾種方式
讀寫檔案應該是在開發過程中經常遇到的,今天要跟大家一起分享的就是在golang的世界中,如何讀寫檔案。 使用io/ioutil進行讀寫檔案 其中提到了兩個方法: func ReadFile func ReadFile(filename string) ([]by
Go實戰 golang中生成讀取二維碼 skip2/go qrcode和boombuler/barcode
生命不止,繼續go go go!!!這裡介紹一下,golang如何生成二維碼,當然是面向github程式設計了。QRCode百度百科: QR Code碼,是由Denso公司於1994年9月研製的一種矩陣二維碼符號,它具有一維條碼及其它二維條碼所具有的資訊容量大、可靠性
Go實戰 golang中使用WebSocket實時聊天室 gorilla/websocket nkovacs/go s
生命不止,繼續 go go go!!!其實,早就應該跟大家分享golang中關於websocket的使用,但是一直不知道從何入手,也不能夠很清晰的描述出來。今天就淺嘗輒止,通過第三方庫實現websocket。WebSocketWebSocket協議是基於TCP的一種新
Go實戰--golang中檔案以及資料夾路徑相關操作
生命不止,繼續 go go go!!! 之前介紹過golang的標準庫:path/filepath, os 今天就跟大家分享幾個關於檔案以及資料夾的相關操作。 獲取目錄中所有檔案 使用包: io/ioutil 使用方法: ioutil.Re
Go實戰--golang中使用JWT(JSON Web Token)
今天就來跟大家簡單介紹一下golang中如何使用token,當然是要依賴一下github上的優秀的開源庫了。 首先,要搞明白一個問題,token、cookie、session的區別。 token、cookie、session的區別Cookie Cookie總是儲存在客戶端中,按在
Go實戰--golang中使用firebase實時資料庫(zabawaba99/firego)
生命不止,繼續 go go go !!! 今天,就跟大家一起學習分享一下golang中如何使用firebase的實時資料庫。 Firebase 實時資料庫 利用我們的 NoSQL 雲端資料庫儲存和同步資料。資料會跨所有客戶端進行實時同步,無論您的應用是
Go實戰--golang中使用redis(redigo和go-redis/redis)
生命不止,繼續 go go go !!! 今天跟大家分享的是如何在golang中使用redis資料庫。 何為redis Redis is an in-memory database open-source software project impl
Go實戰--golang使用ssl連線MongoDB(mgo)
生命不止,繼續 go go go!!! 文中主要介紹了Windows下如何安裝mongodb,mongodb的簡單命令,golang如何操作mongodb,以及使用golang+mongodb建立的微服務。 今天繼續深深耕一點。 Windows下mon
[轉]Go語言(Golang)的Web框架比較:gin VS echo
所謂框架 框架一直是敏捷開發中的利器,能讓開發者很快的上手並做出應用,甚至有的時候,脫離了框架,一些開發者都不會寫程式了。成長總不會一蹴而就,從寫出程式獲取成就感,再到精通框架,快速構造應用,當這些方面都得心應手的時候,可以嘗試改造一些框架,或是自己創造一個。 曾經我以為Python世界裡的框架已經夠多了,後
Go實戰--通過gin-gonic框架搭建restful api服務(github.com/gin-gonic/gin)
users .post sage 事先 eat mas routes pac 操作mysql 生命不止,繼續 go go go !!! 先插播一條廣告,給你堅持學習golang的理由: 《2017 軟件開發薪酬調查:Go 和 Scala 是最賺錢的語言》 言歸正傳!
golang中gin框架的基礎學習和運用
1.安裝 go get gopkg.in/gin-gonic/gin.v1 2.基本的架構 2.1 直接呼叫方案 package main import ( "github.com/gin-gonic/gin" "net/http" )
Go實戰--golang上傳檔案到七牛雲物件儲存(github.com/qiniu/api.v7)
生命不止,繼續 go go go !!! 在國內,七牛絕對是golang的領導者。 七牛雲 關於七牛: (七牛雲)隸屬於上海七牛資訊科技有限公司,七牛雲是國內領先的企業級雲服務商,專注於以資料管理為中心的雲端計算業務研發和運營,圍繞富媒體場景推出了物件儲
mongodb副本集介紹、mongodb副本集搭建、mongodb副本集測試
早期 exe 編輯 ODB linu 51cto 運行 負責 自動切換 一:mongodb副本集介紹 早期版本使用master-slave,一主一從和MySQL類似,但slave在此架構中為只讀,當主庫宕機後,從庫不能自動切換為主目前已經淘汰master-slave模式,改
[實戰Google深度學習框架]Tensorflow(1)TF環境搭建+入門學習
本篇blog主要以code+markdown的形式介紹tf這本實戰書。(建議使用jupyter來學習) 第三章 TF入門學習 3.1 TF計算模型——計算圖 3.2
mongodb副本集介紹、mongodb副本集搭建、 mongodb副本集測試
mongodb副本集介紹 MongoDB早期版本使用master-slave,一主一從和MySQL主從基本是一致的,但s
Go語言環境安裝,驗證go語言環境、使用文字編輯器編寫一個go hello world,Go lang IDE安裝,在golang中新建一個go程式
1 Golang語言環境安裝包下載 https://www.golangtc.com/ 下載: go1.9.2.windows-amd64.msi 和 go1.9.2.windows-amd64.zip 2 golang語言環境安裝 本筆記使用go1.10.2.window