$30 off During Our Annual Pro Sale. View Details »

Challenge to Advanced API Architecture in Go

Challenge to Advanced API Architecture in Go

The presentation slides on golang.tokyo#9 by @__timakin__

Seiji Takahashi

September 29, 2017
Tweet

More Decks by Seiji Takahashi

Other Decks in Programming

Transcript

  1. Challenge to
    Advanced API
    Architecture in Go
    Seiji Takahashi (@__timakin__ ) / Gunosy Inc.
    September 29th, 2017
    golang.tokyo#9

    View Slide

  2. About me
    • Seiji Takahashi
    • Github: timakin / Twitter: @__timakin__
    • Gunosy Inc. Business Development Team
    • Go / Swift
    • Just a little bit contributed to Go.

    View Slide

  3. Preface
    • Finding the sample projects of API server, based on
    maintainable and feature-rich Go code is so hard.
    • So I’ve tried to write an operable API server with
    plain and standard packages like 

    net/http on myself.
    • This is just the result of my best-effort challenge,
    and not the collective opinion of Go community.

    View Slide

  4. Agenda
    • General problems when you write API server
    in Go.
    • Advanced API architecture in Go,

    which is adaptable for your production
    environment.
    • The introductions of simple & practical 

    packages you can use in your team tomorrow.

    View Slide

  5. How do you write API in ɹɹ
    ɹɹ
    ʁ

    View Slide

  6. How do you write API in Go?
    • Use Frameworks?

    View Slide

  7. How do you write API in Go?
    • Use Frameworks?
    • echo / gin / goji / goa

    View Slide

  8. How do you write API in Go?
    • Use Frameworks?
    • echo / gin / goji / goa
    • net/http

    View Slide

  9. How do you write API in Go?
    • Use Frameworks?
    • echo / gin / goji / goa
    • net/http
    • Use ORMs?

    View Slide

  10. How do you write API in Go?
    • Use Frameworks?
    • echo / gin / goji / goa
    • net/http
    • Use ORMs?
    • gorm / xorm / gorp / dbr

    View Slide

  11. How do you write API in Go?
    • Use Frameworks?
    • echo / gin / goji / goa
    • net/http
    • Use ORMs?
    • gorm / xorm / gorp / dbr
    • database/sql

    View Slide

  12. How do you write API in Go?
    • Use Frameworks?
    • echo / gin / goji / goa
    • net/http
    • Use ORMs?
    • gorm / xorm / gorp / dbr
    • database/sql
    • Which platform?

    View Slide

  13. How do you write API in Go?
    • Use Frameworks?
    • echo / gin / goji / goa
    • net/http
    • Use ORMs?
    • gorm / xorm / gorp / dbr
    • database/sql
    • Which platform?
    • AWS / GCP

    View Slide

  14. General problems when you
    write API server in Go
    • It’s easy to encounter circular import.

    View Slide

  15. General problems when you
    write API server in Go
    • It’s easy to encounter circular import.
    • context.Context handling

    View Slide

  16. General problems when you
    write API server in Go
    • It’s easy to encounter circular import.
    • context.Context handling
    • error handling

    View Slide

  17. General problems when you
    write API server in Go
    • It’s easy to encounter circular import.
    • context.Context handling
    • error handling
    • Passing middleware objects without
    context.Context pollution

    View Slide

  18. General problems when you
    write API server in Go
    • It’s easy to encounter circular import.
    • context.Context handling
    • error handling
    • Passing middleware objects without
    context.Context pollution
    • Mature Go hackers say “your shouldn’t use a
    framework. Just use net/http.”, however, it
    sounds there are too much stuff to do.

    View Slide

  19. Any good sample?

    View Slide

  20. Inspirations from goddd
    • marcusolsson/goddd

    View Slide

  21. Inspirations from goddd
    • marcusolsson/goddd
    • Well-capsuled repository with Interface

    View Slide

  22. Inspirations from goddd
    • marcusolsson/goddd
    • Well-capsuled repository with Interface
    • encoder / decoder for req / res payload.

    View Slide

  23. Inspirations from goddd
    • marcusolsson/goddd
    • Well-capsuled repository with Interface
    • encoder / decoder for req / res payload.
    • DDD-based architecture enables you to
    easily avoid a circular import.

    View Slide

  24. How to write API inspired
    by goddd with 

    plain packages?

    View Slide

  25. Background
    • I wrote the sample project: “govod”.
    • Sorry, it’s a closed project because it includes some secrets.ʕ>ϖ<ʔ
    • Go video on demand API.
    • Deploy to Google App Engine
    • Features (≒ domains)
    • Authentication
    • Streaming

    View Slide

  26. ex) /api/videos
    with paging interface

    View Slide

  27. Directory tree
    Isolate main.go to app directory with 

    app.yaml (GAE config) to 

    avoid the go-app-builder error.

    View Slide

  28. Directory tree
    `domain` and `repository` are main
    directories that have the business
    logics and data accessors.
    `middleware` has the http.Handler
    implementations.

    View Slide

  29. Inside of domain
    - Payload en/decoder
    - Error types
    - DI object
    - Business Logic
    - Interface of Repository
    - Routing
    - Paging token parset
    - etc…

    View Slide

  30. View Slide

  31. Initializes the router with `gorilla/mux`

    View Slide

  32. Combine middlewares for the simple
    declaration of http.Handler with `justinas/alice`.
    You can get stats with kicking the endpoint 

    “/api/stats” (`fukata/golang-stats-api-handler`)

    View Slide

  33. Initialize repository, service (business logic),
    and dependency injector for HTTP Handler.

    View Slide

  34. View Slide

  35. Declare the dependency injected to the custom handler.
    (If it’s not GAE `Dependency` may have `Logger`, or other
    middlewares…)
    Handler with DI enables you to handle middleware 

    without setting them in context.Context.

    View Slide

  36. Registration of the routings with CustomHandler and DI object.

    View Slide

  37. Request handler with payload decoder/encoder.
    Decoder contains the validator.
    (`go-playground/validator.v9`)
    Response payload will be wrapped 

    with `unrolled/render`.
    It may results to return the error object
    given a detail context with `pkg/errors`

    View Slide

  38. Paging token parser which returns
    pager cursor required by Datastore.

    View Slide

  39. Call StreamingService with context and paging
    opts, and if it succeeded, return the encoded
    payload.

    View Slide

  40. GetVideoCollection will return
    1. videos
    2. JWT which contains a pager cursor.
    3. error
    JWT is generated by using `dgrijalva/jwt-go`

    View Slide

  41. Access to data storage, with repository 

    which implements GetVideos.

    View Slide

  42. Repository is an Interface.
    It hides which data adapter you depend on.
    This means you can define MockRepository
    and replace to them in test code.

    View Slide

  43. Access to Datastore on Google Cloud Platform.
    (with `mjibson/goon`)
    You can switch the adapter to the clients of
    MySQL, Postgres, or in-memory database etc…

    View Slide

  44. Conclusion
    • DDD-like architecture is good for Go API
    development. You can cleverly escape from
    hell of circular imports.
    • Repository Interface makes the way to
    access data pluggable.
    • In combination with some packages, 

    net/http is surely enough to implement API
    server. (But there are few samples so it looks
    hard at first.)

    View Slide

  45. Thanks!
    • Questions? Come talk to me or 

    contact to the following accounts!
    • @__timakin__
    [email protected]

    View Slide