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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

  5. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  9. Let me show a few examples.

    View Slide

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

    View Slide

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

    }

    View Slide

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

    }

    View 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 Slide

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

    // ...

    }


    View Slide

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

    }

    View Slide

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

    View Slide

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

    View 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 Slide

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


    View Slide

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

    View Slide