twirp ์์ํ๊ธฐ ๐ฆ
ํ๋์ protobuf ํ์ผ
*.proto
์์ ๊ฒฝ๋ก, ์์ฒญ ๋ฐ ์๋ต์ ์ ์ํฉ๋๋ค.๊ทธ๋ฐ ๋ค์ API์ ๋ชจ๋ ์๋น์๋ protobuf ํ์ผ์ ๊ฐ์ ธ์ค๊ณ ์ ํํ ์ธ์ด๋ก ์์ฒด ํด๋ผ์ด์ธํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์์ฑํ ์ ์์ต๋๋ค.
๋น ๋ฅด๊ณ ์์ ๋ฅผ ์ค์ ํด ๋ด ์๋ค.
๋จผ์ protobuf๋ฅผ ์ค์นํด์ผ ํ๋ฏ๋ก Mac์์๋
brew install protobuf
์ด๋ฅผ ์ค์นํ์ผ๋ฉด golang ์ค์ ๊ณผ
GOBIN
๊ฐ ์ ์๋์ด ์๋์ง ํ์ธํด์ผ ํฉ๋๋ค. ๋ค์์ .zshrc
์ ์ถ๊ฐํ ํฉ๋ฆฌ์ ์ธ ๊ธฐ๋ณธ๊ฐ์
๋๋ค.GOBIN="~/go/bin"
PATH="$PATH:~/go/bin"
๋ค์์ผ๋ก protobuf ๋ฐ์ด๋๋ฆฌ ํ๋ฌ๊ทธ์ธ์ ์ค์นํ์ฌ twirp ๋ฐ golang์ฉ ํ์ผ์ ์์ฑํด์ผ ํฉ๋๋ค.
go install github.com/twitchtv/twirp/protoc-gen-twirp@latest
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
"ProxyMe"๋ผ๋ ํ๋ก์ ํธ๋ฅผ ๋ง๋ค๊ณ ์์ผ๋ฏ๋ก ์ด๋ฅผ ์๋ก ์ฌ์ฉํ๊ฒ ์ต๋๋ค. ์์ํ ๊ฒฝ๋ก๋ฅผ ์ ์ํ๊ธฐ ์ํด ๊ฐ๋จํ protobuf ํ์ผ๋ถํฐ ์์ํ๊ฒ ์ต๋๋ค.
syntax = "proto3";
package reaz.io.proxyme;
option go_package = "reaz.io/proxyme";
service ProxyMe {
rpc ListProxies(ListReq) returns (ListRes);
}
message ListReq {
string subject = 1;
}
message ListRes {
string text = 1;
}
์ฃผ๋ชฉํด์ผ ํ ์ค์ํ ๊ฒ์;
# We'll need this later, this is just a namespace for my projects, yours might be more like '{username}.com.{project_name}'
package reaz.io.proxyme;
๊ทธ๋ฐ ๋ค์ ๋๋จธ์ง ํ์ผ์
ListProxies
(๋ชฉ๋ก ์์ฒญ)์ ์๋ฝํ๊ณ ListReq
๋ชฉ๋ก ์๋ต์ ๋ฐํํ๋ ๋จ์ผListReq
์๋ํฌ์ธํธ๋ฅผ ์ค๋ช
ํฉ๋๋ค.์ด์ twirp์ protobuf๋ฅผ ์ฌ์ฉํ์ฌ ์ผ๋ถ ์ฝ๋๋ฅผ ์๋์ผ๋ก ์ค์บํด๋ฉํด ๋ณด๊ฒ ์ต๋๋ค.
protoc --go_out=. --twirp_out=. ProxyMe.proto
์ด ์์ ์์ ์ฐ๋ฆฌ๋ ๋ค์๊ณผ ๊ฐ์ ๊ฒ์ ๊ฐ๊ฒ ๋ ๊ฒ์ ๋๋ค.
โโโ ProxyMe.proto
โโโ reaz.io
โโโ proxyme
โโโ ProxyMe.pb.go
โโโ ProxyMe.twirp.go
2 directories, 3 files
์ฐ๋ฆฌ๊ฐ ์์ฑํ ์๋ณธ ํ์ผ
ProxyMe.proto
๊ณผ go ์์ฑ ๋ถ๋ถ์ธ .pb.go
์ HTTP ์๋น์ค๋ฅผ ํฌํจํ๋ twirp ๋งค์ง์ธ *.twirp.go
๋ฅผ ๊ฐ๋ฆฌํค๋ ๋ฐ ์ฌ์ฉํ ๋ค์์คํ์ด์ค์
๋๋ค.์ด๋ฅผ ํตํด ์๋ํฌ์ธํธ๋ฅผ ์ค์ ๋ก ๊ตฌํํ๊ธฐ ์ํด
server.go
๋ฅผ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค.package main
import (
"context"
"log"
"net/http"
pb "proxyme/reaz.io/proxyme"
)
type ProxyMeServer struct{}
func (s *ProxyMeServer) ListProxies(ctx context.Context, req *pb.ListReq) (*pb.ListRes, error) {
return &pb.ListRes{Text: "Hello " + req.Subject}, nil
}
const PORT = "8011"
// Run the implementation in a local server
func main() {
twirpHandler := pb.NewProxyMeServer(&ProxyMeServer{})
// You can use any mux you like - NewHelloWorldServer gives you an http.Handler.
mux := http.NewServeMux()
// The generated code includes a method, PathPrefix(), which
// can be used to mount your service on a mux.
mux.Handle(twirpHandler.PathPrefix(), twirpHandler)
log.Println("Listening on http://0.0.0.0:" + PORT + twirpHandler.PathPrefix())
err := http.ListenAndServe(":"+PORT, mux)
if err != nil {
log.Fatal(err)
return
}
}
๊ทธ๊ฒ ์ ๋ถ์ ๋๋ค. ์ฐ๋ฆฌ๋ ๋๋ถ๋ถ ์์ฑ๋ ์ฝ๋๋ฅผ ๊ฐ์ ธ์ค๊ณ
ListProxies
, ListReq
๋ฅผ ์ฌ์ฉํ๋ ListRes
๋ฅผ ์ถ๊ฐํฉ๋๋ค.์ด์ ๋ค์๊ณผ ๊ฐ์ด ์คํํฉ๋๋ค.
$ go run server.go
2022/04/18 07:07:16 Listening on http://0.0.0.0:8011/twirp/reaz.io.proxyme.ProxyMe/
์คํ ์ค์ธ ์ํ์์ ๋ค์์ ์ฌ์ฉํ์ฌ ํ ์คํธํ ์ ์์ต๋๋ค.
curl --request POST \
--url http://0.0.0.0:8011/twirp/reaz.io.proxyme.ProxyMe/ListProxies \
--header 'Content-Type: application/json' \
--data '{
"subject": "mike"
}'
# Should see the following for a response
{
"text": "Hello mike"
}
์ด์ ๋ค๋ฅธ ์ธ์ด๋ก ํด๋ผ์ด์ธํธ ์ฝ๋๋ฅผ ์์ฑํ๊ณ ์ ์๋น์ค๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค!
Clients in other languages can also be generated by using the respective protoc plugins defined by their languages, for example --twirp_ruby_out.
๊ทธ๋ฆฌ๊ณ ํ๋์ protobuf ํ์ผ์์ ์์ฑ๋ protobuf ๋๋ json์ ์ฌ์ฉํ ์ ์์ต๋๋ค!
how to generate client code here์ ๋ํด ์์ธํ ์์๋ณด์ธ์.
Reference
์ด ๋ฌธ์ ์ ๊ดํ์ฌ(twirp ์์ํ๊ธฐ ๐ฆ), ์ฐ๋ฆฌ๋ ์ด๊ณณ์์ ๋ ๋ง์ ์๋ฃ๋ฅผ ๋ฐ๊ฒฌํ๊ณ ๋งํฌ๋ฅผ ํด๋ฆญํ์ฌ ๋ณด์๋ค https://dev.to/gjrdiesel/getting-started-with-twirp-2155ํ ์คํธ๋ฅผ ์์ ๋กญ๊ฒ ๊ณต์ ํ๊ฑฐ๋ ๋ณต์ฌํ ์ ์์ต๋๋ค.ํ์ง๋ง ์ด ๋ฌธ์์ URL์ ์ฐธ์กฐ URL๋ก ๋จ๊ฒจ ๋์ญ์์ค.
์ฐ์ํ ๊ฐ๋ฐ์ ์ฝํ ์ธ ๋ฐ๊ฒฌ์ ์ ๋ (Collection and Share based on the CC Protocol.)
์ข์ ์นํ์ด์ง ์ฆ๊ฒจ์ฐพ๊ธฐ
๊ฐ๋ฐ์ ์ฐ์ ์ฌ์ดํธ ์์ง
๊ฐ๋ฐ์๊ฐ ์์์ผ ํ ํ์ ์ฌ์ดํธ 100์ ์ถ์ฒ ์ฐ๋ฆฌ๋ ๋น์ ์ ์ํด 100๊ฐ์ ์์ฃผ ์ฌ์ฉํ๋ ๊ฐ๋ฐ์ ํ์ต ์ฌ์ดํธ๋ฅผ ์ ๋ฆฌํ์ต๋๋ค