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

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.

Simone Carletti

October 10, 2016
Tweet

More Decks by Simone Carletti

Other Decks in Programming

Transcript

  1. Using Go to Guide

    API Design Decisions
    dotGo 2016 lightning talk

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  5. The Go client was leading the
    development.
    My approach was to develop a feature
    in Go, and then in other languages.

    View full-size slide

  6. WriHng Go is certainly a different
    way of coding.

    View full-size slide

  7. Some design decisions we made
    in the past also made the API
    harder to use with certain kinds
    of languages.

    View full-size slide

  8. Let me show a few examples.

    View full-size slide

  9. Consuming our API with Go
    allowed us to understand flaws in
    our response formats and design.

    View full-size slide

  10. // 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"]

    }

    View full-size slide

  11. {

    "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"`

    }

    View full-size slide

  12. 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) {

    // ...

    }


    View full-size slide

  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) {

    // ...

    }


    View full-size slide

  14. // 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"`

    }

    View full-size slide

  15. The simplicity of Go,
    along with some of its constraints,
    are features that forced us to rethink
    the way we designed our API.

    View full-size slide

  16. We used our Go client as the
    leading implementaHon.

    View full-size slide

  17. // 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);


    View full-size slide

  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);


    View full-size slide

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

    View full-size slide