欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go快速開(kāi)發(fā)一個(gè)RESTful API服務(wù)

 更新時(shí)間:2022年06月21日 10:31:34   作者:萬(wàn)俊峰Kevin  
這篇文章主要為大家介紹了Go快速開(kāi)發(fā)一個(gè)RESTful API服務(wù),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

何時(shí)使用單體 RESTful 服務(wù)

對(duì)于很多初創(chuàng)公司來(lái)說(shuō),業(yè)務(wù)的早期我們更應(yīng)該關(guān)注于業(yè)務(wù)價(jià)值的交付,而單體服務(wù)具有架構(gòu)簡(jiǎn)單,部署簡(jiǎn)單,開(kāi)發(fā)成本低等優(yōu)點(diǎn),可以幫助我們快速實(shí)現(xiàn)產(chǎn)品需求。我們?cè)谑褂脝误w服務(wù)快速交付業(yè)務(wù)價(jià)值的同時(shí),也需要為業(yè)務(wù)的發(fā)展預(yù)留可能性,所以我們一般會(huì)在單體服務(wù)中清晰的拆分不同的業(yè)務(wù)模塊。

商城單體 RESTful 服務(wù)

我們以商城為例來(lái)構(gòu)建單體服務(wù),商城服務(wù)一般來(lái)說(shuō)相對(duì)復(fù)雜,會(huì)由多個(gè)模塊組成,比較重要的模塊包括賬號(hào)模塊、商品模塊和訂單模塊等,每個(gè)模塊會(huì)有自己獨(dú)立的業(yè)務(wù)邏輯,同時(shí)每個(gè)模塊間也會(huì)相互依賴,比如訂單模塊和商品模塊都會(huì)依賴賬號(hào)模塊,在單體應(yīng)用中這種依賴關(guān)系一般是通過(guò)模塊間方法調(diào)用來(lái)完成。一般單體服務(wù)會(huì)共享存儲(chǔ)資源,比如 MySQL 和 Redis 等。

單體服務(wù)的整體架構(gòu)比較簡(jiǎn)單,這也是單體服務(wù)的優(yōu)點(diǎn),客戶請(qǐng)求通過(guò) DNS 解析后通過(guò) Nginx 轉(zhuǎn)發(fā)到商城的后端服務(wù),商城服務(wù)部署在 ECS 云主機(jī)上,為了實(shí)現(xiàn)更大的吞吐和高可用一般會(huì)部署多個(gè)副本,這樣一個(gè)簡(jiǎn)單的平民架構(gòu)如果優(yōu)化好的話也是可以承載較高的吞吐的。

商城服務(wù)內(nèi)部多個(gè)模塊間存在依賴關(guān)系,比如請(qǐng)求訂單詳情接口 /order/detail,通過(guò)路由轉(zhuǎn)發(fā)到訂單模塊,訂單模塊會(huì)依賴賬號(hào)模塊和商品模塊組成完整的訂單詳情內(nèi)容返回給用戶,在單體服務(wù)中多個(gè)模塊一般會(huì)共享數(shù)據(jù)庫(kù)和緩存。

單體服務(wù)實(shí)現(xiàn)

接下來(lái)介紹如何基于 go-zero 來(lái)快速實(shí)現(xiàn)商城單體服務(wù)。使用過(guò) go-zero 的同學(xué)都知道,我們提供了一個(gè) API 格式的文件來(lái)描述 Restful API,然后可以通過(guò) goctl 一鍵生成對(duì)應(yīng)的代碼,我們只需要在 logic 文件里填寫(xiě)對(duì)應(yīng)的業(yè)務(wù)邏輯即可。商城服務(wù)包含多個(gè)模塊,為了模塊間相互獨(dú)立,所以不同模塊由單獨(dú)的 API 定義,但是所有的 API 的定義都是在同一個(gè) service (mall-api) 下。

在 api 目錄下分別創(chuàng)建 user.api, order.api, product.api 和 mall.api,其中 mall.api 為聚合的 api 文件,通過(guò) import 導(dǎo)入,文件列表如下:

api
|-- mall.api
|-- order.api
|-- product.api
|-- user.api

Mall API 定義

mall.api 的定義如下,其中 syntax = “v1” 表示這是 zero-api 的 v1 語(yǔ)法

syntax = "v1"
import "user.api"
import "order.api"
import "product.api"

賬號(hào)模塊 API 定義

  • 查看用戶詳情
  • 獲取用戶所有訂單
syntax = "v1"
type (
    UserRequest {
        ID int64 `path:"id"`
    }
    UserReply {
        ID      int64   `json:"id"`
        Name    string  `json:"name"`
        Balance float64 `json:"balance"`
    }
    UserOrdersRequest {
        ID int64 `path:"id"`
    }
    UserOrdersReply {
        ID       string `json:"id"`
        State    uint32 `json:"state"`
        CreateAt string `json:"create_at"`
    }
)
service mall-api {
    @handler UserHandler
    get /user/:id (UserRequest) returns (UserReply)
    @handler UserOrdersHandler
    get /user/:id/orders (UserOrdersRequest) returns (UserOrdersReply)
}

訂單模塊 API 定義

  • 獲取訂單詳情
  • 生成訂單
syntax = "v1"
type (
    OrderRequest {
        ID string `path:"id"`
    }
    OrderReply {
        ID       string `json:"id"`
        State    uint32 `json:"state"`
        CreateAt string `json:"create_at"`
    }
    OrderCreateRequest {
        ProductID int64 `json:"product_id"`
    }
    OrderCreateReply {
        Code int `json:"code"`
    }
)
service mall-api {
    @handler OrderHandler
    get /order/:id (OrderRequest) returns (OrderReply)
    @handler OrderCreateHandler
    post /order/create (OrderCreateRequest) returns (OrderCreateReply)
}

商品模塊 API 定義

  • 查看商品詳情
syntax = "v1"
type ProductRequest {
    ID int64 `path:"id"`
}
type ProductReply {
    ID    int64   `json:"id"`
    Name  string  `json:"name"`
    Price float64 `json:"price"`
    Count int64   `json:"count"`
}
service mall-api {
    @handler ProductHandler
    get /product/:id (ProductRequest) returns (ProductReply)
}

生成單體服務(wù)

已經(jīng)定義好了 API,接下來(lái)用 API 生成服務(wù)就會(huì)變得非常簡(jiǎn)單,我們使用 goctl 生成單體服務(wù)代碼。

$ goctl api go -api api/mall.api -dir .

生成的代碼結(jié)構(gòu)如下:

.
├── api
│   ├── mall.api
│   ├── order.api
│   ├── product.api
│   └── user.api
├── etc
│   └── mall-api.yaml
├── internal
│   ├── config
│   │   └── config.go
│   ├── handler
│   │   ├── ordercreatehandler.go
│   │   ├── orderhandler.go
│   │   ├── producthandler.go
│   │   ├── routes.go
│   │   ├── userhandler.go
│   │   └── userordershandler.go
│   ├── logic
│   │   ├── ordercreatelogic.go
│   │   ├── orderlogic.go
│   │   ├── productlogic.go
│   │   ├── userlogic.go
│   │   └── userorderslogic.go
│   ├── svc
│   │   └── servicecontext.go
│   └── types
│       └── types.go
└── mall.go

解釋一下生成的代碼結(jié)構(gòu):

  • api:存放 API 描述文件
  • etc:用來(lái)定義項(xiàng)目配置,所有的配置項(xiàng)都可以寫(xiě)在 mall-api.yaml 中
  • internal/config:服務(wù)的配置定義
  • internal/handler:API 文件中定義的路由對(duì)應(yīng)的 handler 的實(shí)現(xiàn)
  • internal/logic:用來(lái)放每個(gè)路由對(duì)應(yīng)的業(yè)務(wù)邏輯,之所以區(qū)分 handler 和 logic 是為了讓業(yè)務(wù)處理部分盡可能減少依賴,把 HTTP requests 和邏輯處理代碼隔離開(kāi),便于后續(xù)拆分成 RPC service
  • internal/svc:用來(lái)定義業(yè)務(wù)邏輯處理的依賴,我們可以在 main 函數(shù)里面創(chuàng)建依賴的資源,然后通過(guò) ServiceContext 傳遞給 handler 和 logic
  • internal/types:定義了 API 請(qǐng)求和返回?cái)?shù)據(jù)結(jié)構(gòu)
  • mall.go:main 函數(shù)所在文件,文件名和 API 定義中的 service 同名,去掉了后綴 -api

生成的服務(wù)不需要做任何修改就可以運(yùn)行:

$ go run mall.go
Starting server at 0.0.0.0:8888...

實(shí)現(xiàn)業(yè)務(wù)邏輯

接下來(lái)我們來(lái)一起實(shí)現(xiàn)一下業(yè)務(wù)邏輯,出于演示目的邏輯會(huì)比較簡(jiǎn)單,并非真正業(yè)務(wù)邏輯。

首先,我們先來(lái)實(shí)現(xiàn)用戶獲取所有訂單的邏輯,因?yàn)樵谟脩裟K并沒(méi)有訂單相關(guān)的信息,所以我們需要依賴訂單模塊查詢用戶的訂單,所以我們?cè)?UserOrdersLogic 中添加對(duì) OrderLogic 依賴

type UserOrdersLogic struct {
    logx.Logger
    ctx        context.Context
    svcCtx     *svc.ServiceContext
    orderLogic *OrderLogic
}
func NewUserOrdersLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserOrdersLogic {
    return &UserOrdersLogic{
        Logger:     logx.WithContext(ctx),
        ctx:        ctx,
        svcCtx:     svcCtx,
        orderLogic: NewOrderLogic(ctx, svcCtx),
    }
}

在 OrderLogic 中實(shí)現(xiàn)根據(jù) 用戶id 查詢所有訂單的方法

func (l *OrderLogic) ordersByUser(uid int64) ([]*types.OrderReply, error) {
    if uid == 123 {
        // It should actually be queried from database or cache
        return []*types.OrderReply{
            {
                ID:       "236802838635",
                State:    1,
                CreateAt: "2022-5-12 22:59:59",
            },
            {
                ID:       "236802838636",
                State:    1,
                CreateAt: "2022-5-10 20:59:59",
            },
        }, nil
    }
    return nil, nil
}

在 UserOrdersLogic 的 UserOrders 方法中調(diào)用 ordersByUser 方法

func (l *UserOrdersLogic) UserOrders(req *types.UserOrdersRequest) (*types.UserOrdersReply, error) {
    orders, err := l.orderLogic.ordersByUser(req.ID)
    if err != nil {
        return nil, err
    }
    return &types.UserOrdersReply{
        Orders: orders,
    }, nil
}

這時(shí)候我們重新啟動(dòng) mall-api 服務(wù),在瀏覽器中請(qǐng)求獲取用戶所有訂單接口

http://localhost:8888/user/123/orders

返回結(jié)果如下,符合我們的預(yù)期

{
    "orders": [
        {
            "id": "236802838635",
            "state": 1,
            "create_at": "2022-5-12 22:59:59"
        },
        {
            "id": "236802838636",
            "state": 1,
            "create_at": "2022-5-10 20:59:59"
        }
    ]
}

接下來(lái)我們?cè)賮?lái)實(shí)現(xiàn)創(chuàng)建訂單的邏輯,創(chuàng)建訂單首先需要查看該商品的庫(kù)存是否足夠,所以在訂單模塊中需要依賴商品模塊。

type OrderCreateLogic struct {
    logx.Logger
    ctx    context.Context
    svcCtx *svc.ServiceContext
    productLogic *ProductLogic
}
func NewOrderCreateLogic(ctx context.Context, svcCtx *svc.ServiceContext) *OrderCreateLogic {
    return &OrderCreateLogic{
        Logger:       logx.WithContext(ctx),
        ctx:          ctx,
        svcCtx:       svcCtx,
        productLogic: NewProductLogic(ctx, svcCtx),
    }
}

創(chuàng)建訂單的邏輯如下

const (
    success = 0
    failure = -1
)
func (l *OrderCreateLogic) OrderCreate(req *types.OrderCreateRequest) (*types.OrderCreateReply, error) {
    product, err := l.productLogic.productByID(req.ProductID)
    if err != nil {
        return nil, err
    }
    if product.Count > 0 {
        return &types.OrderCreateReply{Code: success}, nil
    }
    return &types.OrderCreateReply{Code: failure}, nil
}

依賴的商品模塊邏輯如下

func (l *ProductLogic) Product(req *types.ProductRequest) (*types.ProductReply, error) {
    return l.productByID(req.ID)
}
func (l *ProductLogic) productByID(id int64) (*types.ProductReply, error) {
    return &types.ProductReply{
        ID:    id,
        Name:  "apple watch 3",
        Price: 3333.33,
        Count: 99,
    }, nil
}

以上可以看出使用 go-zero 開(kāi)發(fā)單體服務(wù)還是非常簡(jiǎn)單的,有助于我們快速開(kāi)發(fā)上線,同時(shí)我們還做了模塊的劃分,為以后做微服務(wù)的拆分也打下了基礎(chǔ)。

總結(jié)

通過(guò)以上的示例可以看出使用 go-zero 實(shí)現(xiàn)單體服務(wù)非常簡(jiǎn)單,只需要定義 api 文件,然后通過(guò) goctl 工具就能自動(dòng)生成項(xiàng)目代碼,我們只需要在logic中填寫(xiě)業(yè)務(wù)邏輯即可,這里只是為了演示如何基于 go-zero 快速開(kāi)發(fā)單體服務(wù)并沒(méi)有涉及數(shù)據(jù)庫(kù)和緩存的操作,其實(shí)我們的 goctl 也可以一鍵生成 CRUD 代碼和 cache 代碼,對(duì)于開(kāi)發(fā)單體服務(wù)來(lái)說(shuō)可以起到事半功倍的效果。

并且針對(duì)不同的業(yè)務(wù)場(chǎng)景,定制化的需求也可以通過(guò)自定義模板來(lái)實(shí)現(xiàn),還可以在團(tuán)隊(duì)內(nèi)通過(guò)遠(yuǎn)程 git 倉(cāng)庫(kù)共享自定義業(yè)務(wù)模板,可以很好的實(shí)現(xiàn)團(tuán)隊(duì)協(xié)同。

項(xiàng)目地址 github.com/zeromicro/g…

以上就是Go快速開(kāi)發(fā)一個(gè)RESTful API服務(wù)的詳細(xì)內(nèi)容,更多關(guān)于Go開(kāi)發(fā)RESTful API服務(wù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Go定時(shí)器的三種實(shí)現(xiàn)方式示例詳解

    Go定時(shí)器的三種實(shí)現(xiàn)方式示例詳解

    這篇文章主要為大家介紹了Go定時(shí)器的三種實(shí)現(xiàn)方式示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • HTTP服務(wù)壓力測(cè)試工具及相關(guān)術(shù)語(yǔ)講解

    HTTP服務(wù)壓力測(cè)試工具及相關(guān)術(shù)語(yǔ)講解

    這篇文章主要為大家介紹了HTTP服務(wù)壓力測(cè)試工具使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪
    2022-04-04
  • Go語(yǔ)言使用net/http實(shí)現(xiàn)簡(jiǎn)單登錄驗(yàn)證和文件上傳功能

    Go語(yǔ)言使用net/http實(shí)現(xiàn)簡(jiǎn)單登錄驗(yàn)證和文件上傳功能

    這篇文章主要介紹了Go語(yǔ)言使用net/http實(shí)現(xiàn)簡(jiǎn)單登錄驗(yàn)證和文件上傳功能,使用net/http模塊編寫(xiě)了一個(gè)簡(jiǎn)單的登錄驗(yàn)證和文件上傳的功能,在此做個(gè)簡(jiǎn)單記錄,需要的朋友可以參考下
    2023-07-07
  • Go語(yǔ)言中的Struct結(jié)構(gòu)體

    Go語(yǔ)言中的Struct結(jié)構(gòu)體

    這篇文章介紹了Go語(yǔ)言中的Struct結(jié)構(gòu)體,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • Golang的第一個(gè)程序-Hello?World

    Golang的第一個(gè)程序-Hello?World

    這篇文章主要介紹了第一個(gè)Go程序-Hello?World,在編寫(xiě)第一個(gè)go程序之前,我們要將系統(tǒng)的環(huán)境變量配好,下面來(lái)看具體的編一過(guò)程吧,需要的小伙伴可以參考一下
    2022-01-01
  • Golang之sync.Pool對(duì)象池對(duì)象重用機(jī)制總結(jié)

    Golang之sync.Pool對(duì)象池對(duì)象重用機(jī)制總結(jié)

    這篇文章主要對(duì)Golang的sync.Pool對(duì)象池對(duì)象重用機(jī)制做了一個(gè)總結(jié),文中有相關(guān)的代碼示例和圖解,具有一定的參考價(jià)值,需要的朋友可以參考下
    2023-07-07
  • golang圖片處理庫(kù)image基本操作

    golang圖片處理庫(kù)image基本操作

    這篇文章主要介紹了golang圖片處理庫(kù)image簡(jiǎn)介,主要包括圖片的基本讀取與保存及圖片的修改,本文通過(guò)通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-07-07
  • 完美解決golang go get私有倉(cāng)庫(kù)的問(wèn)題

    完美解決golang go get私有倉(cāng)庫(kù)的問(wèn)題

    這篇文章主要介紹了完美解決golang go get私有倉(cāng)庫(kù)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-05-05
  • Go語(yǔ)言實(shí)現(xiàn)遍歷文件夾

    Go語(yǔ)言實(shí)現(xiàn)遍歷文件夾

    這篇文章主要為大家詳細(xì)介紹了Go語(yǔ)言實(shí)現(xiàn)遍歷文件夾的相關(guān)方法,文中的示例代碼講解詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴可以了解一下
    2023-05-05
  • go語(yǔ)言中json數(shù)據(jù)的讀取和寫(xiě)出操作

    go語(yǔ)言中json數(shù)據(jù)的讀取和寫(xiě)出操作

    這篇文章主要介紹了go語(yǔ)言中json數(shù)據(jù)的讀取和寫(xiě)出操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-04-04

最新評(píng)論