🙆
prismでmockサーバを立ててみる
背景
こちらの続き。
prismでmockサーバを立てて、外部通信の部分を実装してみたい。
イメージ図
環境
M1 Mac
docker desktop 4.17.0
ファイル構成
.
├── Dockerfile
├── README.md
├── animal
│ └── animal.go
├── docker-compose.yml
├── go.mod
├── go.sum
├── mock
│ └── openapi.yml
├── openyml
├── server.go
├── tmp
│ ├── air.log
│ └── main
└── user
└── user.go
実装
Goを書き換え
・server.go
/animal/dogと/animal/catのエンドポイントを追加
package main
import (
"echo-practice/animal"
"echo-practice/user"
"net/http"
"github.com/labstack/echo/v4"
)
func main() {
e := echo.New()
e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
})
u := user.New(1, "testUser", 20)
e.GET("/user", u.Get)
e.POST("/user", user.Post)
dog := animal.New("dog")
e.GET("/animal/dog", dog.Get)
e.POST("/animal/dog", dog.Post)
cat := animal.New("cat")
e.GET("/animal/cat", cat.Get)
e.POST("/animal/cat", cat.Post)
e.Logger.Fatal(e.Start(":1323"))
}
prismのモックサーバと通信する。
モックサーバのホスト名とポートは環境変数から取得。
とりあえず、動くものを実装。
リファクタリングは別の機会にやれたら・・・
package animal
import (
"bytes"
"encoding/json"
"io"
"log"
"net/http"
"net/url"
"os"
"github.com/labstack/echo/v4"
)
type Animal struct {
Name string `json:"name"`
}
type RequestBody struct {
Name string `json:"name"`
}
type Response struct {
Message string `json:"message"`
Explanation string `json:"explanation"`
}
func New(name string) *Animal {
return &Animal{Name: name}
}
func (a *Animal) Get(c echo.Context) error {
var res Response
animalRes, err := http.Get("http://" + os.Getenv("ANIMAL_API_HOST") + ":" + os.Getenv("ANIMAL_API_PORT") + "/animal/" + a.Name)
if err != nil {
return c.JSON(http.StatusInternalServerError, res)
}
defer animalRes.Body.Close()
body, _ := io.ReadAll(animalRes.Body)
log.Printf("Response:%s", string(body))
return c.String(http.StatusOK, string(body))
}
func (a *Animal) Post(c echo.Context) error {
rbody := &RequestBody{
Name: a.Name,
}
animalData, err := json.Marshal(rbody)
if err != nil {
return echo.NewHTTPError(400, "failed to bind request")
}
log.Printf("Animal:%s", string(animalData))
base, _ := url.Parse("http://" + os.Getenv("ANIMAL_API_HOST") + ":" + os.Getenv("ANIMAL_API_PORT"))
reference, _ := url.Parse("animal/register")
endpoint := base.ResolveReference(reference).String()
req, _ := http.NewRequest("POST", endpoint, bytes.NewBuffer(animalData))
req.Header.Set("Content-Type", "application/json")
q := req.URL.Query()
req.URL.RawQuery = q.Encode()
var client *http.Client = &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Fatalln(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
log.Printf("Response:%s", string(body))
jsonData, _ := json.Marshal(struct {
Message string `json:"message"`
}{
Message: "ok",
})
return c.String(http.StatusCreated, string(jsonData))
}
・openapi.yml
これをprismに渡せばモックサーバ立ててくれる。
書き方はググりながら、とりあえず動くように最低限を記述。
openapi: 3.0.0
info:
title: Animal API
description: This is Sample API.
termsOfService: http://animal-api/
contact:
name: API support
url: http://XXXXX/support
email: support@XXXX.com
version: 1.0.0
servers:
- url: "http://localhost:4010"
description: Development server
paths:
/animal/register:
post:
tags:
- animal
summary: Create a new Animal
description: Create a new Animal
requestBody:
content:
application/json:
schema:
type: object
properties:
name:
type: string
responses:
'201':
description: status
content:
application/json:
schema:
type: "object"
properties:
message:
type: "string"
example: "ok"
/animal/dog:
get:
tags:
- animal
summary: Get Dog.
description: Get Dog.
responses:
'200':
description: A single Animal model
content:
application/json:
schema:
type: "object"
properties:
message:
type: "string"
example: "ok"
explanation:
type: "string"
example: "Dog is very cool"
/animal/cat:
get:
tags:
- animal
summary: Get Cat.
description: Get Cat.
responses:
'200':
description: A single Animal model
content:
application/json:
schema:
type: "object"
properties:
message:
type: "string"
example: "ok"
explanation:
type: "string"
example: "Cat is very cute"
・docker-compose.yml
prism用のコンテナ追加。
4010ポートを開けておく。
version: '3.8'
services:
app:
build:
context: .
target: dev
dockerfile: Dockerfile
env_file: .env
tty: true
container_name: echo-practice
volumes:
- ./:/go/src/app
ports:
- 1323:1323
mock:
image: node:19-alpine3.16
tty: true
container_name: animal-api
working_dir: /tmp
#restart: always
command: >
sh -c '
npm install -g @stoplight/prism-cli
prism mock -h 0.0.0.0 "/tmp/openapi.yml"
'
volumes:
- data-mock:/var/lib/mock/data
- ./mock:/tmp
ports:
- 4010:4010
volumes:
data-mock:
コンテナ起動
docker-compose up -d
動作確認
openapi.ymlで定義したレスポンス返ってくること確認
Discussion