Upgrade to Pro — share decks privately, control downloads, hide ads and more …

grapi: Bulding JSON API server with grpc-gateway for microservices

grapi: Bulding JSON API server with grpc-gateway for microservices

Masayuki Izumi

April 15, 2018
Tweet

More Decks by Masayuki Izumi

Other Decks in Programming

Transcript

  1. ©2018 Wantedly, Inc.
    grapi: Building JSON API server
    with grpc-gateway for microservices
    Go Conference 2018 Spring
    13.Apr.2018 - @izumin5210

    View Slide

  2. ©2018 Wantedly, Inc.
    "HFOEB
    .JDSPTFSWJDFTͱ(P
    8FC"1*XJUI(Pߟ͑ͳ͍ͱ͍͚ͳ͍໰୊
    H31$8):8)"5
    HSQDHBUFXBZ8):8)"5
    HSBQJNJDSPTFSWJDFTΛޮ཰Α͘࡞͍ͬͯͨ͘Ίʹ

    View Slide

  3. ©2018 Wantedly, Inc.
    $ whoami a.k.a. usamimi engineer
    izumin5210
    Engineer at Wantedly, Inc.
    Wantedly People
    ‣ Web Application Engineer
    - Profile Data Strategy Group
    ‣ Interests in developer productivity on microservices
    Gopher, Rubyist, JavaScripter and Androider

    View Slide

  4. ©2018 Wantedly, Inc.
    grapi: Building JSON API server
    with grpc-gateway for microservices
    Go Conference 2018 Spring
    13.Apr.2018 - @izumin5210

    View Slide

  5. ©2018 Wantedly, Inc.
    WHY Go ? Microservices and Go in Wantedly
    ͋ΘͤͯΑΈ͍ͨ
    Why microservices ? Why Rails and Go ?
    ‣ %PDLFS͕ૣ͔͘Β1SPEVDUJPOͰ࢖ΘΕ͍ͯͨ
    .JDSPTFSWJDFTPO,VCFSOFUFTΛೖΕ΍͍͢
    ‣ ΍Γ͍ͨ͜ͱʹ࠷దͳٕज़બఆΛ
    ઐ໳৬1ZUIPO $
    υϝΠϯ͕ݟ͑ͯΔ(Pʕ◔ϖ◔ʔ
    ͦΕҎ֎3BJMT
    Rails Developer Meetup 2018: Microservices on "Rails"

    https://www.wantedly.com/companies/wantedly/post_articles/113554

    View Slide

  6. ©2018 Wantedly, Inc.
    WHY Go ? Microservices and Go in Wantedly
    ͋ΘͤͯΑΈ͍ͨ
    Why microservices ? Why Rails and Go ?
    ‣ %PDLFS͕ૣ͔͘Β1SPEVDUJPOͰ࢖ΘΕ͍ͯͨ
    .JDSPTFSWJDFTPO,VCFSOFUFTΛೖΕ΍͍͢
    ‣ ΍Γ͍ͨ͜ͱʹ࠷దͳٕज़બఆΛ
    ઐ໳৬1ZUIPO $
    υϝΠϯ͕ݟ͑ͯΔ(Pʕ◔ϖ◔ʔ
    ͦΕҎ֎3BJMT
    Rails Developer Meetup 2018: Microservices on "Rails"

    https://www.wantedly.com/companies/wantedly/post_articles/113554

    View Slide

  7. ©2018 Wantedly, Inc.
    WHY Go ? Microservices and Go in Wantedly
    Microservices and Go
    Wantedly People ❤ Go
    ‣ ܰྔɾϋΠύϑΥʔϚϯε
    ,VCFSOFUFTͱͷ૬ੑ˕
    ‣ αʔϏεؒ௨৴ͳͲͰ*0͕૿͕͑ͪ
    go͚ͬͯͭΔ͚ͩͰඇಉظʹͳͬͯศར
    sync errgroup chanͳͲ΋ศར
    Rails Developer Meetup 2018: Microservices on "Rails"

    https://www.wantedly.com/companies/wantedly/post_articles/113554

    View Slide

  8. ©2018 Wantedly, Inc.
    WHY Go ? Microservices and Go in Wantedly
    Microservices and Go
    Wantedly People ❤ Go
    ‣ ܰྔɾϋΠύϑΥʔϚϯε
    ,VCFSOFUFTͱͷ૬ੑ˕
    ‣ αʔϏεؒ௨৴ͳͲͰ*0͕૿͕͑ͪ
    go͚ͬͯͭΔ͚ͩͰඇಉظʹͳͬͯศར
    sync errgroup chanͳͲ΋ศར
    Rails Developer Meetup 2018: Microservices on "Rails"

    https://www.wantedly.com/companies/wantedly/post_articles/113554

    View Slide

  9. ©2018 Wantedly, Inc.
    Web API with Go
    How do you build Web API with Go?

    View Slide

  10. ©2018 Wantedly, Inc.
    Web API with Go
    How do you build Web API with Go ?
    ‣ Stdlib net/http
    ‣ Lightweight / High-performance package
    - e.g. gin, echo, ...
    ‣ (Full-stack) web-app framework
    - e.g. Revel, beego, ...
    The Go gopher was designed by Renée French.

    View Slide

  11. ©2018 Wantedly, Inc.
    Go in Wantedly
    We uses github.com/gin-gonic/gin
    ‣ ॳظ͔ΒHJOΛར༻͖ͯͨ͠
    ʢৄࡉ͸஌Βͳ͍ʣ
    ൺֱత͸΍͔͘Βcontext.Contextϕʔεͩͬͨʁ
    ػೳɾੑೳͷόϥϯεʁ
    ͔ΜͨΜͳWBMJEBUJPOͱ͔΋͍ͭͯΔ
    ύϑΥʔϚϯε΋ѱ͘ͳ͍
    ඇৗʹ੎͍͕͋ͬͨʢվળ΋௒ૣ͍ʣ
    Rails Developer Meetup 2018: Microservices on "Rails"

    https://www.wantedly.com/companies/wantedly/post_articles/113554
    gin
    gin
    gin
    gin
    gin
    ?
    Web API with Go in Wantedly

    View Slide

  12. ©2018 Wantedly, Inc.
    ೰·͍͠໰୊
    ຊ౰ʹͭΒ͍

    View Slide

  13. ©2018 Wantedly, Inc.
    // Boilerplate code for JSON API server in net/http
    // ちょっとした誇張表現がはいっているかも
    func CreateBook(w http.ResponseWriter, r *http.Request) {
    data, err := ioutil.ReadAll(r)
    if err != nil {
    http.Error(w, err.Error(), http.StatusBadRequest)
    return
    }
    req := &CreateBookRequest{}
    if err = json.Unmarshal(data, book); err != nil {
    http.Error(w, err.Error(), http.StatusBadRequest)
    return
    }
    // ここが本当に実現したいロジック
    w.WriteHeader(http.StatusCreated)
    if err := json.NewEncoder(w).Encode(book); err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
    }
    }
    (PͷͭΒ͞
    Boilerplate in net/http
    FH$36%ͷ$ʢ$SFBUFʣͷ࣮૷XJUInet/http
    IUUQ3FRVFTU͔ΒCPEZಡΈग़͠
    ΤϥʔϋϯυϦϯά
    CPEZΛTUSVDUʹVONBSTIBM
    ΤϥʔϋϯυϦϯά
    ຊ౰ʹ࣮ݱ͍ͨ͠ϩδοΫΛॻ͘
    ΤϥʔϋϯυϦϯά
    +40/ʹNBSTIBMͯ͠SFTQPOTFʹॻ͘
    ΤϥʔϋϯυϦϯά

    View Slide

  14. ©2018 Wantedly, Inc.
    (PͷͭΒ͞
    Boilerplate in gin
    FH$36%ͷ$ʢ$SFBUFʣͷ࣮૷XJUIgin
    SFRVFTUCPEZΛTUSVDUʹVONBSTIBM
    ΤϥʔϋϯυϦϯά
    ຊ౰ʹ࣮ݱ͍ͨ͠ϩδοΫΛॻ͘
    ΤϥʔϋϯυϦϯά
    Ϩεϙϯεͭ͘Δ
    // Boilerplate code for JSON API server in gin-gonic/gin
    func CreateBook(c *gin.Context) {
    req := &CreateBookRequest{}
    if err := c.BindJSON(req) {
    c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
    return
    }
    // ここが本当に実現したいロジック
    c.JSON(200, book)
    }

    View Slide

  15. ©2018 Wantedly, Inc.
    // GET /@:user_id/books?page=2&per=10
    func ListBooks(c *gin.Context) {
    userID, err := strconv.Atoi(c.Param("user_id"))
    // TOOD: Should handle errors
    page, err := strconv.Atoi(c.Query("page"))
    // TOOD: Should handle errors
    per, err := strconv.Atoi(c.Query("per"))
    // TOOD: Should handle errors
    // ...
    c.JSON(200, books)
    }
    (PͷͭΒ͞
    query/path params
    "MMRVFSZQBUIQBSBNTBSFTUSJOH
    ‣ 63-༝དྷͷύϥϝλ͸͢΂ͯstringʹͳΔ
    ݩσʔλ͕จࣈྻͳͷͰ

    ౰ͨΓલͬͪΌ౰ͨΓલ͕ͩʜ
    ‣ ύϥϝλͻͱͭͻͱͭܕม׵ʁ
    ৬ਓͷखʹΑΔ͔͋ͨͨΈͷ͋Δ

    View Slide

  16. ©2018 Wantedly, Inc.
    (PͷͭΒ͞
    type BookService interface {
    ListBooks(context.Context, *ListBooksRequest) ([]*Book, error)
    CreateBook(context.Context, *CreateBookRequest) (*Book, error)
    // ...
    }
    ࣮૷͍ͨ͠ͷ͸͜Ε͚ͩͷ͸ͣ

    View Slide

  17. ©2018 Wantedly, Inc.
    ͦ͏ͩɺH31$Λ࢖͓͏

    View Slide

  18. ©2018 Wantedly, Inc.
    gRPC: WHY & WHAT
    H31$ͬͯͲ͕͜خ͍͠ͷʁ

    View Slide

  19. ©2018 Wantedly, Inc.
    gRPC WHAT is gRPC?
    gRPC?
    (PPHMF࡞ͬͨ31$GSBNFXPSL͕044ʹͳͬͨ΋ͷ
    ҎԼHSQDJPΑΓҾ༻
    4JNQMFTFSWJDFEFpOJUJPO
    8PSLTBDSPTTMBOHVBHFTBOEQMBUGPSNT
    4UBSURVJDLMZBOETDBMF
    #JEJSFDUJPOBMTUSFBNJOHBOEJOUFHSBUFEBVUI

    View Slide

  20. ©2018 Wantedly, Inc.
    gRPC WHAT is gRPC?
    gRPC?
    (PPHMF࡞ͬͨ31$GSBNFXPSL͕044ʹͳͬͨ΋ͷ
    ҎԼHSQDJPΑΓҾ༻
    4JNQMFTFSWJDFEFpOJUJPO
    8PSLTBDSPTTMBOHVBHFTBOEQMBUGPSNT
    4UBSURVJDLMZBOETDBMF
    #JEJSFDUJPOBMTUSFBNJOHBOEJOUFHSBUFEBVUI

    View Slide

  21. ©2018 Wantedly, Inc.
    gRPC "Simple service definition"
    service BookService {
    rpc CreateBook (CreateBookRequest) returns (Book) {}
    }
    message Book {
    string book_id = 1;
    }
    message CreateBookRequest {
    Book book = 1;
    }
    ͜Ε͕

    View Slide

  22. ©2018 Wantedly, Inc.
    gRPC "Simple service definition"
    ͜͏ͳΔ
    type BookServiceServer interface {
    CreateBook(context.Context, *CreateBookRequest) (*Book, error)
    }
    type Book struct {
    BookId string `protobuf:"..." json:"book_id,omitempty"`
    }
    type CreateBookRequest struct {
    Book *Book `protobuf:"..." json:"book,omitempty"`
    }

    View Slide

  23. ©2018 Wantedly, Inc.
    gRPC "Simple service definition"
    ͜Ε͚࣮ͩ૷͢Ε͹0,
    type BookServiceServer interface {
    CreateBook(context.Context, *CreateBookRequest) (*Book, error)
    }
    type Book struct {
    BookId string `protobuf:"..." json:"book_id,omitempty"`
    }
    type CreateBookRequest struct {
    Book *Book `protobuf:"..." json:"book,omitempty"`
    }

    View Slide

  24. ©2018 Wantedly, Inc.
    gRPC "Simple service definition"
    ϦΫΤετ಺༰΋ͪΌΜͱߏ଄ମʹϚοϐϯάͯ͘͠ΕΔ
    type BookServiceServer interface {
    CreateBook(context.Context, *CreateBookRequest) (*Book, error)
    }
    type Book struct {
    BookId string `protobuf:"..." json:"book_id,omitempty"`
    }
    type CreateBookRequest struct {
    Book *Book `protobuf:"..." json:"book,omitempty"`
    }

    View Slide

  25. ©2018 Wantedly, Inc.
    service BookService {
    rpc CreateBook (CreateBookRequest) returns (Book) {}
    }
    message Book {
    string book_id = 1;
    }
    message CreateBookRequest {
    Book book = 1;
    }
    gRPC WHY gRPC?
    Code generation
    To use protobuf as IDL (Interface Definition Language)
    ‣ protocprotoc-gen-go
    1SPUPDPM#VGGFSTͷεΩʔϚ͔Β

    αʔόɾΫϥΠΞϯτͷ*'ͱ࣮૷Λੜ੒
    ‣ ੜ੒͞ΕΔαʔόͷ*'ͷ࣮૷Λొ࿥
    grpc.Server͕ϦΫΤετΛTUSVDUʹόΠϯυ
    ొ࿥࣮ͨ͠૷Λݺͼग़ͯ͘͠ΕΔ
    type BookServiceServer interface {
    CreateBook(context.Context, *CreateBookRequest) (*Book, error)
    }
    type Book struct {
    BookId string `protobuf:"..." json:"book_id,omitempty"`
    }
    type CreateBookRequest struct {
    Book *Book `protobuf:"..." json:"book,omitempty"`
    }

    View Slide

  26. ©2018 Wantedly, Inc.
    service BookService {
    rpc CreateBook (CreateBookRequest) returns (Book) {}
    }
    message Book {
    string book_id = 1;
    }
    message CreateBookRequest {
    Book book = 1;
    }
    gRPC WHY gRPC?
    Code generation
    with protoc
    ‣ QSPUPDQSPUPDHFOHP
    1SPUPDPM#VGGFSTͷεΩʔϚ͔Β

    αʔόɾΫϥΠΞϯτͷ*'ͱ࣮૷Λੜ੒
    ‣ ੜ੒͞ΕΔαʔόͷ*'ͷ࣮૷Λొ࿥
    grpc.Server͕ϦΫΤετΛTUSVDUʹόΠϯυ
    ొ࿥࣮ͨ͠૷Λݺͼग़ͯ͘͠ΕΔ
    type BookServiceServer interface {
    CreateBook(context.Context, *CreateBookRequest) (*Book, error)
    }
    type Book struct {
    BookId string `protobuf:"..." json:"book_id,omitempty"`
    }
    type CreateBookRequest struct {
    Book *Book `protobuf:"..." json:"book,omitempty"`
    }
    ࣗ෼͕ͨͪॻ͘ͷ͸αʔόͷ࣮૷
    ຊ౰ʹඞཁͳϩδοΫͷΈʹूதͰ͖Δʂ

    View Slide

  27. ©2018 Wantedly, Inc.
    Why NOT gRPC?
    gRPC ͷϜζΧγ͞
    H31$͸)551ͷίωΫγϣϯΛுΓͬͺͳ͠ʹ͢Δ
    Πϯϑϥ·ΘΓͷϜζΧγ͞(SBDFGVMͳ%FQMPZ -PBE#BMBODJOH FUD
    1SPUPCVGόΠφϦΛ΍ΓͱΓ͢Δ
    DVSM΋࢖͑ͳ͍ʜ
    ΫϥΠΞϯτ΋͍··Ͱͱશ͘ҟͳΔٕज़Λ࢖͏͜ͱʹ
    ߟ͑Δ͜ͱ͕ଟ͍ʂ
    ΍Δ͚ͩͰ͸͋Δ͚ͲɼՔಇதͷαʔϏεʹυΧοͱ͍ΕΔͷ͸େม
    gRPC WHY gRPC?

    View Slide

  28. ©2018 Wantedly, Inc.
    Why NOT gRPC?
    gRPC ͷϜζΧγ͞
    H31$͸)551ͷίωΫγϣϯΛுΓͬͺͳ͠ʹ͢Δ
    Πϯϑϥ·ΘΓͷϜζΧγ͞(SBDFGVMͳ%FQMPZ -PBE
    #BMBODJOH FUD
    1SPUPCVGόΠφϦΛ΍ΓͱΓ͢Δ
    DVSM΋࢖͑ͳ͍ʜ
    ΫϥΠΞϯτ΋͍··Ͱͱશ͘ҟͳΔٕज़Λ࢖͏͜ͱʹ
    ߟ͑Δ͜ͱ͕ଟ͍ʂ
    ΍Δ͚ͩͰ͸͋Δ͚ͲɼՔಇதͷαʔϏεʹυΧοͱ͍ΕΔͷ͸େม
    ύϑΥʔϚϯε໘͸Ұ୴ஔ͍͓͍ͯͯɼ*%-ͱDPEFHFOFSBUJPOʹΑΔੜ࢈ੑ޲্Λૂ͍͍ͨ
    Ώ͘Ώ͘͸H31$Λ࢖͍͖͍ͬͯͨ෍ڭɾݕূͷͨΊɼͱΓ͋͑ͣϛχϚϜʹಋೖ͍ͨ͠
    gRPC WHY gRPC?

    View Slide

  29. ©2018 Wantedly, Inc.
    grpc-gateway: WHY & WHAT
    HSQDHBUFXBZͷૉ੖Β͠͞ʹ͍ͭͯޠΔ࣌ؒ

    View Slide

  30. ©2018 Wantedly, Inc.
    grpc-gateway WHAT is grpc-gateway?
    WHAT is grpc-gateway?
    ‣ H31$αʔόͷલஈʹཱͭSFWFSTFQSPYZ
    ‣ )551+40/H31$ʹม׵͢Δ
    ‣ ࠾༻ࣄྫ
    FUDEʢ,VCFSOFUFTͷόοΫΤϯυʹ͍Δ෼ࢄ,74ʣ
    8BOUFEMZ1FPQMFͰ΋ڈ೥ळ͘Β͍͔Βͬͦ͜Γ࢖͍ͬͯΔ
    Ϣʔβ͝ͱͷઃఆ஋Λ൚༻తͳײ͡Ͱ֨ೲ͢Δαʔό
    ݁ߏΆ͜Ά͜ୟ͔ΕΔ͚ͲɼݩؾʹϨεϙϯεΛฦ͍ͯ͠Δ

    View Slide

  31. ©2018 Wantedly, Inc.
    grpc-gateway WHAT is grpc-gateway?
    https://github.com/grpc-ecosystem/grpc-gateway

    View Slide

  32. ©2018 Wantedly, Inc.
    grpc-gateway WHAT is grpc-gateway?
    H31$αʔόͷલஈʹཱͭ
    3FWFSTF1SPYZHSQDHBUFXBZ
    https://github.com/grpc-ecosystem/grpc-gateway

    View Slide

  33. ©2018 Wantedly, Inc.
    grpc-gateway WHAT is grpc-gateway?
    "1*Λୟ͘ਓ͔Β͸
    )551+40/Λ஻͍ͬͯΔΑ͏ʹΈ͑Δ
    ैདྷ௨Γͷ؀ڥͰ"1*Λར༻Ͱ͖Δ
    https://github.com/grpc-ecosystem/grpc-gateway

    View Slide

  34. ©2018 Wantedly, Inc.
    grpc-gateway WHAT is grpc-gateway?
    1SPYZͷ࣮૷
    protocprotoc-gen-grpc-gatewayͰੜ੒
    https://github.com/grpc-ecosystem/grpc-gateway

    View Slide

  35. ©2018 Wantedly, Inc.
    grpc-gateway WHY grpc-gateway?
    WHY grpc-gateway?
    ͳͥHSQDHBUFXBZΛ࢖͍͍͔ͨ
    ‣ ؀ڥɾJOUFSGBDF͸ͦͷ··ʹ

    H31$ͷ*%-ͱDPEFHFOSBUJPOΛར༻Ͱ͖Δʂ
    ‣ ʮͲ͜ʹʯʮԿΛ౤͛Ε͹ʯʮԿ͕ฦͬͯ͘Δ͔ʯ

    *%-ΛಡΊ͹ͻͱ໨Ͱ෼͔Δ
    ͍ΘΏΔʮυΩϡϝϯτʯ͕ಘΒΕΔ
    service BookService {
    rpc CreateBook (CreateBookRequest) returns (Book) {
    option (google.api.http) = {
    post: "/books"
    body: "book"
    };
    }
    }
    H31$)551ͷϚοϐϯά΋୯७໌շ

    View Slide

  36. ©2018 Wantedly, Inc.
    grpc-gateway WHY grpc-gateway?
    WHY grpc-gateway?
    ͳͥHSQDHBUFXBZΛ࢖͍͍͔ͨ
    ͍ΘΏΔʮυΩϡϝϯτʯ͕ಘΒΕΔ
    *OUFSGBDF%SJWFO%FWFMPQNFOU͕࣮ݱͰ͖Δ
    ʢ4XBHHFS΍+40/4DIFNB͕໨ࢦͨ͠ੈքʣ
    service BookService {
    rpc CreateBook (CreateBookRequest) returns (Book) {
    option (google.api.http) = {
    post: "/books"
    body: "book"
    };
    }
    }
    H31$)551ͷϚοϐϯά΋୯७໌շ

    View Slide

  37. ©2018 Wantedly, Inc.
    grpc-gateway ͭΒ͍ͱ͜Ζ
    ͭΒ͍ͱ͜Ζᶃ
    QSPUPDͷίϚϯυ͕௒Ή͔͍ͣ͠
    # gRPC サーバ & クライアント生成
    protoc \
    -I ./vendor/github.com/grpc-ecosystem-grpc-gateway \
    -I ./vendor/github.com/grpc-ecosystem-grpc-gateway/thrid_party/googleapis \
    --go_out=plugins=grpc:. api/protos/book.proto
    # grpc-gateway の reverse proxy 生成
    protoc \
    -I ./vendor/github.com/grpc-ecosystem-grpc-gateway \
    -I ./vendor/github.com/grpc-ecosystem-grpc-gateway/thrid_party/googleapis \
    --grpc-gateway_out=logtostderr=true:grpc:. api/protos/book.proto

    View Slide

  38. ©2018 Wantedly, Inc.
    grpc-gateway ͭΒ͍ͱ͜Ζ
    ͭΒ͍ͱ͜Ζᶄ
    ʮαʔόΛىಈ͢Δ·Ͱʯ͕௕͍
    ‣ αʔόΛͭಈ͔͢ͷͰ౰ͨΓલͰ͸͋Δ͕ʜ
    ճͷnet.Listen
    ͭαʔόͷηοτΞοϓɾىಈ
    ͭͷαʔόͷTIVUEPXOॲཧʜ
    ‣ ࠓճͷείʔϓ͸͋͘·Ͱʮੜ࢈ੑΛ্͛Δʯ͜ͱ
    ֤ΤϯυϙΠϯτ࣮૷ͷੜ࢈ੑ͸্͕ͬͯ΋ɼ࠷ॳ͕ͩΔ͍ͱαʔϏε࡞Δ͜ͱࣗମ͕ԯ߷ʹͳΔʜ

    View Slide

  39. ©2018 Wantedly, Inc.
    grapi: Building JSON API with gRPC
    ϚΠΫϩαʔϏεΛޮ཰Α࣮͘૷͢ΔͨΊͷઓུ

    View Slide

  40. ©2018 Wantedly, Inc.
    8SJUJOH+40/"1*JO(P
    ຊ࣭͡Όͳ͍ίʔυΛͨ͘͞Μॻ͔ͳ͍ͱ͍͚ͳ͍
    H31$*%- $PEFHFOFSBUJPO )JHIQFSGPSNBODF
    ҰํͰɼ͍ΖΜͳલ४උ͕ඞཁʹͳΔ
    ੜ࢈ੑΛ্͛Δ͜ͱΛ༏ઌ͍ͨ͠*%-ͱDPEFHFOFSBUJPO͚ͩ࢖͏
    HSQDHBUFXBZNBQTH31$UP)551+40/
    H31$Λ͍ͭ΋ͷ؀ڥͰར༻Մೳ
    ͔͠͠ɼϓϩδΣΫτͷελʔτμογϡ͕ಷ͘ͳͬͯ͠·͏ʜ
    grapi ͜͜·Ͱͷ໰୊੔ཧ

    View Slide

  41. ©2018 Wantedly, Inc.
    8SJUJOH+40/"1*JO(P
    ຊ࣭͡Όͳ͍ίʔυΛͨ͘͞Μॻ͔ͳ͍ͱ͍͚ͳ͍
    H31$*%- $PEFHFOFSBUJPO )JHIQFSGPSNBODF
    ҰํͰɼ͍ΖΜͳલ४උ͕ඞཁʹͳΔ
    ੜ࢈ੑΛ্͛Δ͜ͱΛ༏ઌ͍ͨ͠*%-ͱDPEFHFOFSBUJPO͚ͩ࢖͏
    HSQDHBUFXBZNBQTH31$UP)551+40/
    H31$Λ͍ͭ΋ͷ؀ڥͰར༻Մೳ
    ͔͠͠ɼϓϩδΣΫτͷελʔτμογϡ͕ಷ͘ͳͬͯ͠·͏ʜ
    grapi ͜͜·Ͱͷ໰୊੔ཧ

    View Slide

  42. ©2018 Wantedly, Inc.
    HSQDHBUFXBZελʔτμογϡ͕஗͘ͳΔ
    H31$ੜ࢈ੑΛ্͍͛ͨ
    ͜ͷΪϟοϓΛຒΊΔԿ͔͕ඞཁ

    View Slide

  43. ©2018 Wantedly, Inc.
    ཁ͢Δʹʮ࠷ॳʹॻ͘ίʔυྔ͕ଟ͍ෳࡶʯͳͷ͕໰୊
    HSQDHBUFXBZελʔτμογϡ͕஗͘ͳΔ

    View Slide

  44. ©2018 Wantedly, Inc.
    ཁ͢Δʹʮ࠷ॳʹॻ͘ίʔυྔ͕ଟ͍ෳࡶʯͳͷ͕໰୊
    HSQDHBUFXBZελʔτμογϡ͕஗͘ͳΔ
    ͦ΋ͦ΋ਓྨ͕ॻ͘ඞཁ͸ͳ͍ͷͰ͸ʁʂ

    View Slide

  45. ©2018 Wantedly, Inc.
    grapi WHAT is grapi?
    grapi
    ಡΈํ͸ʮ͙ΒͬͽʯΒ͍͠
    ‣ IUUQTHJUIVCDPNJ[VNJOHSBQJ
    ‣ ʮߟ͑Δ͜ͱΛݮΒ͢ʯ͜ͱͰ

    ੜ࢈ੑΛ͋͛ΔͨΊͷ$-*QBDLBHF
    (FOFSBUFTQSPKFDUTLFMFUPO
    (FOFSBUFTTFSWJDFTLFMFUPOT
    8SBQTQSPUPD

    View Slide

  46. ©2018 Wantedly, Inc.
    grapi WHAT is grapi?
    grapi init
    SBJMTOFXతͳ
    ‣ ϓϩδΣΫτͷεέϧτϯੜ੒
    ‣ ׬ྃޙʹʮHSBQJTFSWFSʯΛ࣮ߦ͢Ε͹

    αʔό͕ىಈ͢Δঢ়ଶʹͳΔ
    [~/src/github.com/izumin5210-sandbox/sampleapp]
    :) % grapi init .
    ➜ Initialize project
    ✔ .gitignore
    ✔ Gopkg.toml
    ✔ grapi.toml
    ✔ api/protos/.keep
    ✔ app/run.go
    ✔ app/server/.keep
    ✔ cmd/server/run.go
    ▸ Install dependencies
    Root project is "github.com/izumin5210-sandbox/sampleapp"
    2 transitively valid internal packages
    4 external packages imported from 3 projects
    (0) ✓ select (root)
    (1) ? attempt github.com/golang/protobuf with 1 pkgs; 3
    (1) try github.com/golang/[email protected]

    View Slide

  47. ©2018 Wantedly, Inc.
    grapi WHAT is grapi?
    grapi g service
    SBJMTHDPOUSPMMFSతͳ
    ‣ H31$TFSWJDFͷεέϧτϯੜ੒
    1SPUPCVGͱ(Pͷαʔό࣮૷ͷ࿮͕Ͱ͖Δ
    QSPUPDͷ࣮ߦ΋΍ͬͯ͘ΕΔʢޙड़ʣ
    ‣ ͋ͱ͸࿮ΛຒΊΔ͚ͩΈ͍ͨͳঢ়ଶ
    ‣ grapi g scaffold-serviceʹ͢Δͱ

    "1*ઃܭΨΠυͷඪ४ϝιου͕

    શͯἧͬͨঢ়ଶʹͳΔʢޙड़ʣ
    [~/src/github.com/izumin5210-sandbox/sampleapp]
    :) % grapi g scaffold-service book
    ➜ Scaffold service
    ✔ api/protos/book.proto
    ✔ app/server/book_server.go
    ✔ app/server/book_server_register_funcs.go
    ✔ app/server/book_server_test.go
    ➜ Execute protoc
    ▸ Install plugins
    ✔ protoc-gen-go
    ✔ protoc-gen-grpc-gateway
    ✔ protoc-gen-swagger
    ▸ Execute protoc
    ✔ api/protos/book.proto

    View Slide

  48. ©2018 Wantedly, Inc.
    grapi WHAT is grapi?
    API Design Guide
    ͍͍"1*࡞ΔͨΊͷΨΠυϥΠϯCZ(PPHMF
    ‣ ͍͍"1*Λ࡞ΔͨΊͷΞϨίϨ͕ॻ͍ͯ͋Δ
    H31$ϕʔεH31$ʹ׳Εͯͳ͍ਓ͸ಡΉͱྑ͍
    ‣ ඪ४ϝιου
    ͍ΘΏΔ$36%࣮ݱʹඞཁͳϝιου܈
    /BNJOH 3FRVFTU 3FTQPOTFͷܗࣜͳͲΛఆٛ
    API ઃܭΨΠυ
    https://cloud.google.com/apis/design/

    View Slide

  49. ©2018 Wantedly, Inc.
    grapi WHAT is grapi?
    grapi protoc
    ΋͏QSPUPDͷҾ਺͸֮͑ͳͯ͘େৎ෉
    ‣ grapi.tomlΈ͍͍ͯײ͡ʹ
    QMVHJOͷϏϧυ
    api/protos/**/*.protoAʹରͯ͠protoc࣮ߦ
    Ҿ਺΋͍͍ײ͡ʹ૊ΈཱͯΒΕΔ
    [protoc]
    protos_dir = "./api/protos"
    out_dir = "./api"
    import_dirs = [
    "./vendor/github.com/grpc-ecosystem/grpc-gateway",
    "./vendor/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis",
    ]
    [[protoc.plugins]]
    path = "./vendor/github.com/golang/protobuf/protoc-gen-go"
    name = "go"
    args = { plugins = "grpc" }
    [[protoc.plugins]]
    path = "./vendor/github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gat
    name = "grpc-gateway"
    args = { logtostderr = true }
    [[protoc.plugins]]
    path = "./vendor/github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger"
    name = "swagger"
    args = { logtostderr = true }

    View Slide

  50. ©2018 Wantedly, Inc.
    grapi WHAT is grapi?
    αʔόͷىಈ
    αʔό࣮૷ͷొ࿥͸ճͰ͍͍Α
    ‣ grapiserver.New()Έ͍͍ͯײ͡ʹઃఆ
    ىಈϙʔτͱ͔
    *OUFSDFQUPSͱ͔
    ‣ ࣮૷ͷొ࿥͸A8JUI4FSWFSTAʹ౉͚ͩ͢
    ͦΕ͚ͩͰ͍͍Α͏ʹίʔυ͕ੜ੒͞Ε͍ͯΔ
    func Run() error {
    s := grapiserver.New(
    grapiserver.WithDefaultLogger(),
    grapiserver.WithServers(
    server.NewBookServiceServer(), // <= これ
    ),
    )
    return s.Serve()
    }

    View Slide

  51. ©2018 Wantedly, Inc.
    grapi WHAT is grapi?
    αʔόͷىಈ
    Ωϛ͚ͩͷ࠷ڧͷΦϓγϣϯΛ࡞Ζ͏
    ‣ ΊͬͪΌ͍Ζ͍Ζ΍ͬͯ͘ΕΔຐ๏ͷΦϓγϣϯ
    Λఏڙ͢Δύοέʔδ͕ଘࡏʢQSJWBUFʣ
    ΞΫηεϩΪϯάͱ͔
    ϝτϦΫεͱ͔
    ΤϥʔϨϙʔςΟϯάͱ͔
    ‣ ͜Ε͸·ͨͷػձʹ͓࿩͠·͢

    ؾʹͳΔਓ͸࿩Λฉ͖ʹདྷ͍ͯͩ͘͞ʣ
    func Run() error {
    defer servicex.Close()
    s := grapiserver.New(
    servicex.WithDefault(), // <= これ
    grapiserver.WithServers(
    server.NewBookServiceServer(),
    ),
    )
    return s.Serve()
    }

    View Slide

  52. ©2018 Wantedly, Inc.
    grapi WHY grapi?
    Design philosophy of grapi
    HSBQJͷࢥ૝ͱ͔
    ‣ ໨ࢦ͢͸rails newͱrails g create-react-app
    ֤ΤϯυϙΠϯτͷ࣮૷͚ͩॻ͚͹͍͍ੈք
    ‣ ʮϑϧελοΫʯʹ͸͠ͳ͍
    .JDSPTFSWJDFͰ࢖͏ͨΊʹ࡞ͬͨ
    ͳΔ΂͘খ͍͞΋ͷ͕Ͱ͖ΔΑ͏ʹͳ͍ͬͯΕ͹ɼ෗ͬͯ΋ؾܰʹࣺͯΒΕΔ
    4NBMMJT#FBVUJGVM

    View Slide

  53. ©2018 Wantedly, Inc.
    grapi WHY grapi?
    Design philosophy of grapi
    HSBQJͷࢥ૝ͱ͔
    ‣ ҰํͰɼ03.΍)551$MJFOUͷΑ͏ͳࡉ͔͍࿩ʹ͸౿Έࠐ·ͳ͍
    .JDSPTFSWJDF޲͚ͳͷͰɼ3%#͡Όͳ͍͓΋͠ΖόοΫΤϯυΛ࣋ͬͯΔέʔε΋͋Δ
    03.ʹݶͬͯݴ͑͹ɼσϑΝΫτ͕ͳ͍
    3BJMTͷ"DUJWF3FDPSEͷΑ͏ͳҟৗͳੜ࢈ੑ޲্͕ݟࠐΊΔ΋ͷ͕ͳ͍
    ʢҰํͰɼQMVHJOػߏ͚ͭͯ֎෇͚ରԠ͸΍ͬͯ΋͍͍͔΋ʣ

    View Slide

  54. ©2018 Wantedly, Inc.
    Next actions & Conclusion
    ͭ͗΍Δ͜ͱ·ͱΊ

    View Slide

  55. ©2018 Wantedly, Inc.
    αʔϏεؒ௨৴Λগͣͭ͠H31$ʹ
    w ͍·͸HSQDHBUFXBZט·͍ͤͯΔ͚Ͳɼͳ͍ʹӽͨ͜͠ͱ͸ͳ͍
    w *TUJP͕ೖΔͷͰΠϯϑϥपΓ͸໰୊ͳ͍ʁ
    Next actions ΍͍ͬͯͧ͘

    View Slide

  56. ©2018 Wantedly, Inc.
    8SJUJOH+40/"1*JO(P
    ຊ࣭͡Όͳ͍ίʔυΛͨ͘͞Μॻ͔ͳ͍ͱ͍͚ͳ͍
    H31$*%- $PEFHFOFSBUJPO )JHIQFSGPSNBODF
    ҰํͰɼ͍ΖΜͳલ४උ͕ඞཁʹͳΔ
    ੜ࢈ੑΛ্͛Δ͜ͱΛ༏ઌ͍ͨ͠*%-ͱDPEFHFOFSBUJPO͚ͩ࢖͏
    HSQDHBUFXBZNBQTH31$UP)551+40/
    H31$Λ͍ͭ΋ͷ؀ڥͰར༻Մೳ
    ͔͠͠ɼϓϩδΣΫτͷελʔτμογϡ͕ಷ͘ͳͬͯ͠·͏ʜ
    Conclusion ղܾ͔ͨͬͨ͠໰୊

    View Slide

  57. ©2018 Wantedly, Inc.
    HSBQJ$PEFHFOSBUPSBOEHPQBDLBHFUPSFEVDFCPJMFSQMBUFT
    CPJMFQMBUFΛ๾໓QSPUPD·ΘΓͷ൥ࡶ͞ΛӅṭ
    ͍͍ײ͡ͷίʔυδΣωϨʔλ
    ߟ͑Δ͜ͱΛݮΒͤΔͷͰɼຊ࣭తͳ࣮૷ʹूதͰ͖Δ
    ં֯ͷϚΠΫϩαʔϏεΞʔΩςΫνϟͳͷͰɼ
    ಛੑΛཧղ͠ద੾ͳٕज़બఆΛ৺͕͚ͯ)BQQZ)BDLJOH͠Α͏
    Conclusion ՝୊ղܾ & ·ͱΊ

    View Slide