Using Go to Guide API Design Decisions (dotGo 2016)

Using Go to Guide API Design Decisions (dotGo 2016)

Two years ago at DNSimple we started a major redesign of our public API, and we started working on several official API clients in different languages. The Go language played a key role in the development of the API, we promoted the Go client to our primary implementation, and we used it to drive several design and implementation decisions. In this quick talk you'll discover why Go was so important to us and why we used it to guide our API design decisions.

99e0b39c091e10d9c7d4452a34ca52dc?s=128

Simone Carletti

October 10, 2016
Tweet

Transcript

  1. Using Go to Guide
 API Design Decisions dotGo 2016 lightning

    talk
  2. This is Tiny P., our li9le resolver, pretending to be

    a Gopher.
  3. 2 years ago we started to redesign our HTTP API.

  4. We decided to develop official clients in several languages.

  5. None
  6. The Go client was leading the development. My approach was

    to develop a feature in Go, and then in other languages.
  7. WriHng Go is certainly a different way of coding.

  8. Some design decisions we made in the past also made

    the API harder to use with certain kinds of languages.
  9. Let me show a few examples.

  10. Consuming our API with Go allowed us to understand flaws

    in our response formats and design.
  11. // ZoneRecord represents a DNS record in DNSimple.
 type ZoneRecord

    struct {
 ID int `json:"id,omitempty"`
 Type string `json:"type,omitempty"`
 Name string `json:"name",omitempty`
 Content string `json:"content,omitempty"`
 // ...
 Regions []string `json:"regions,omitempty"`
 } {
 "name": "www",
 "type": "A",
 "content": "127.0.0.1",
 "regions": "global"
 }
 
 {
 "name": "www",
 "type": "A",
 "content": "127.0.0.1",
 "regions": ["TKO", "AMS"]
 }
  12. {
 "name": "www",
 "type": "A",
 "content": "127.0.0.1",
 "regions": ["global"]
 }


    
 {
 "name": "www",
 "type": "A",
 "content": "127.0.0.1",
 "regions": ["TKO", "AMS"]
 } // ZoneRecord represents a DNS record in DNSimple.
 type ZoneRecord struct {
 ID int `json:"id,omitempty"`
 Type string `json:"type,omitempty"`
 Name string `json:"name",omitempty`
 Content string `json:"content,omitempty"`
 // ...
 Regions []string `json:"regions,omitempty"`
 }
  13. type Domain struct {
 ID int `json:"id,omitempty"`
 Name string `json:"name,omitempty"`


    // ...
 }
 
 // Both accountIdentifier and domainIdentifier
 // may be either an int ID or string Identifier.
 func (s *DomainsService) GetDomain(accountIdentifier, domainIdentifier string) (*DomainResponse, error) {
 // ...
 }

  14. type Domain struct {
 ID int `json:"id,omitempty"`
 Name string `json:"name,omitempty"`


    // ...
 }
 
 // Both accountIdentifier and domainIdentifier
 // may be either an int ID or string Identifier.
 func (s *DomainsService) GetDomain(accountIdentifier, domainIdentifier string) (*DomainResponse, error) {
 // ...
 }

  15. // ListDomains lists the domains for an account.
 func (s

    *DomainsService) ListDomains(ID string, o *DomainListOptions) (*DomainsResponse, error) {
 // ...
 }
 
 // DomainListOptions specifies the optional parameters you can provide
 // to customize the DomainsService.ListDomains method.
 type DomainListOptions struct {
 NameLike string `url:"name_like,omitempty"`
 RegistrantID int `url:"registrant_id,omitempty"`
 
 ListOptions
 }
 
 // ListOptions contains the common options you can pass to a List method
 // in order to control parameters such as paginations and page number.
 type ListOptions struct {
 Page int `url:"page,omitempty"`
 PerPage int `url:"per_page,omitempty"`
 Sort string `url:"sort,omitempty"`
 }
  16. The simplicity of Go, along with some of its constraints,

    are features that forced us to rethink the way we designed our API.
  17. We used our Go client as the leading implementaHon.

  18. // Get the list of domains in Go
 domainsResponse, err

    := client.Domains.ListDomains(accountID, nil)
 # Get the list of domains in Ruby
 response = client.domains.list_domains(account_id)
 # Get the list of domains in Elixir
 {:ok, response} = Dnsimple.Domains.list_domains(%Dnsimple.Client{}, account_id)
 // Get the list of domains in Node.js
 client.domains.listDomains(accountId).then(function(response) { });
 // Get the list of domains in Java
 ListDomainsResponse response = client.domains.listDomains(accountId);

  19. // Get the list of domains in Go
 domainsResponse, err

    := client.Domains.ListDomains(accountID, nil)
 # Get the list of domains in Ruby
 response = client.domains.list_domains(account_id)
 # Get the list of domains in Elixir
 {:ok, response} = Dnsimple.Domains.list_domains(%Dnsimple.Client{}, account_id)
 // Get the list of domains in Node.js
 client.domains.listDomains(accountId).then(function(response) { });
 // Get the list of domains in Java
 ListDomainsResponse response = client.domains.listDomains(accountId);

  20. Thanks! Simone Carle8 @weppos h=ps:/ /dnsimple.com/dotgo