SlideShare una empresa de Scribd logo
1 de 29
Descargar para leer sin conexión
How to build SDKs in Go
Lessons from the
Go SDK for Dropbox
Diwaker Gupta
● Infrastructure @
Dropbox
● Metadata Services,
Multihoming, Search,
Messaging, Email,
Notifications, Machine
Learning etc
● Authored Dropbox Go
SDK and dbxcli
● Twitter/Github:
@diwakergupta
users businesses
● Gophercon ‘17 Keynote by @tammybutow:
https://bit.ly/gophercon17dbx
● Dozens of Go services, many with millions of RPS!
● We open source at: https://github.com/dropbox
● We are hiring! dropbox.com/jobs or email me (diwaker@)
Lessons from the Dropbox Go SDK
#1: Use a Code Generator
#1: Use a code generator
● Language-agnostic API definition (DSL, JSON,
YAML, etc), Language-specific generators
● Dropbox Stone (spec + generators)
○ https://github.com/dropbox/stone
● Google
○ JSON Spec https://developers.google.com/discovery/
○ Codegen
https://github.com/google/google-api-go-client/
● AWS Go SDK has a very similar setup
● OpenAPI: https://github.com/OAI/OpenAPI-Specification
#2: Avoid Surprises
#2: Avoid Surprises
● Principle of Least Surprise
● No external dependencies
○ Only standard library imports
● No vendored dependencies
● What you need is what you get
○ Scoped sub-packages for larger APIs (e.g. AWS)
○ Make it `go get` friendly
#3: Make Configuration Simple
#3: Make Configuration Simple
● Don’t use cmdline flags
○ Stdlib limitations
● Environment variables
○ OK, but beware pitfalls
● Use a config struct
○ Same pattern in AWS SDK
● Persistence outside SDK
○ Let applications choose
○ dbxcli load/stores json
configs
// Config contains parameters for
configuring the SDK.
type Config struct {
// OAuth2 access token
Token string
// Enable verbose logging in SDK
Verbose bool
...
// For testing only
Client *http.Client
}
#4: Provide Visibility
#4: Provide Visibility
● Allow verbose logging
● Allow configurable
logging targets
● Limited by stdlib :(
type Config struct {
// Enable verbose logging
Verbose bool
// Optional logging target
Logger *log.Logger
}
// TryLog will, if Verbose is set, log to
// the config's logger or the default logger
// if Config.Logger is nil.
func (c *Config) TryLog(format string, v
...interface{}) {
if !c.Verbose {
return
}
if c.Logger != nil {
c.Logger.Printf(format, v...)
} else {
log.Printf(format, v...)
}
}
#5: Use Go idioms for unsupported types
#5: Unions
Consider (in Stone):
union DeleteError
path_lookup LookupError
path_write WriteError
In JSON (note LookupError):
{
".tag": "path_lookup",
"path_lookup": {
".tag": "malformed_path",
"malformed_path": "/some/path"
}
}
Equivalent struct in Go
type DeleteError struct {
dropbox.Tagged
PathLookup *LookupError `json:"path_lookup"`
PathWrite *WriteError `json:"path_write"`
}
Problem: (de)serialization
func (u *DeleteError) UnmarshalJSON(body []byte)
error {
type wrap struct {
dropbox.Tagged
PathLookup json.RawMessage
PathWrite json.RawMessage
}
var w wrap
switch w.Tag {
case "path_lookup":
err = json.Unmarshal(w.PathLookup,
&u.PathLookup)
...
case "path_write":
err = json.Unmarshal(w.PathWrite,
&u.PathWrite)
...
}
#5: Unions
type DeleteError struct {
dropbox.Tagged
PathLookup *LookupError
`json:"path_lookup,omitempty"`
PathWrite *WriteError
`json:"path_write,omitempty"`
}
{
".tag": "path_lookup",
"path_lookup": {
".tag": "malformed_path",
"malformed_path": "/some/path"
}
}
#5: Inherited Types
In Stone
struct Metadata
// Common fields: Name, Path etc
union
file FileMetadata
folder FolderMetadata
Idiomatic Go: Embedding
type Metadata struct {
// Common fields
}
type FileMetadata struct {
Metadata
// FileMetadata specific fields
}
type FolderMetadata struct {
Metadata
// FolderMetadata specific fields
}
Solution: Use a dummy interface
type IsMetadata interface {
IsMetadata()
}
// Subtypes get this via embedding
func (u *Metadata) IsMetadata() {}
// Use IsMetadata where you need
// the union type
#5: Inherited Types
Problem: Polymorphism
func List(...) []Metadata
Can return FileMetadata or
FolderMetadata
Similar trick as Unions
type metadataUnion struct {
dropbox.Tagged
File *FileMetadata
Folder *FolderMetadata
}
func IsMetadataFromJSON(data []byte) (IsMetadata,
e) {
var t metadataUnion
if err := json.Unmarshal(data, &t); err !=
nil {
return nil, err
}
switch t.Tag {
...
}
}
#5: Inherited Types
Problem: (de)serialization
{
".tag": "file",
"name": "Prime_Numbers.txt",
"id": "id:a4ayc_80_OEAAAAAAAAAXw",
"content_hash": "e3b0c44298fc"
}
OR
{
".tag": "folder",
"name": "math",
"id": "id:a4ayc_80_OEAAAAAAAAAXz",
"path_lower": "/homework/math",
}
#6: Do NOT authenticate
#6: Do NOT authenticate
● Apps authenticate, SDK accepts OAuth Token
● Beware of known OAuth pitfalls
○ Changed OAuth Endpoint from api.dropbox.com to
api.dropboxapi.com
○ App started failing with oauth2: cannot fetch token:
400 Bad Request
○ Gem from oauth2/internal/token.go
○ func RegisterBrokenAuthHeaderProvider(tokenURL string)
○ Google, Stripe and yes, Dropbox are “broken”
● More information:
○ On debugging OAuth2 in #golang
#7: Auto Generate Tests
#7: Auto Generate Tests
● Tests should be
comprehensive and
up-to-date
● Dropbox SDK is NOT a
good example!
● Model after AWS SDK
○ Example input/output
defined in JSON
○ Tests are auto-generated
● Not a panacea, still
need to write tests!
○ Especially negative tests
#8: Handle errors the Go way
#8: Handle errors the Go way
Dropbox SDK
res, err := dbx.ListFolder(arg)
if err != nil {
switch e := err.(type) {
case files.ListFolderAPIError:
...
AWS SDK
output, err := s3manage.Upload(...)
if err != nil {
if reqerr, ok := err.(RequestFailure);
ok {
...
● Have SDK errors implement the `error` interface
● Use type assertions to extract errors
● Good packages exist for combining / unrolling errors --
wish stdlib had more support!
Lessons Recap
1. Use a Code Generator
2. Avoid Surprises
3. Make Configuration Simple
4. Provide Visibility
5. Use Go Idioms for Unsupported Types
6. Do Not Authenticate
7. Auto Generate Tests
8. Handle Errors the Go Way
Where to get it?
● SDK:https://github.com/dropbox/dropbox-sdk-go-unofficial
● dbxcli: https://github.com/dropbox/dbxcli/
○ Command line tool for Dropbox
○ Pre-compiled binaries for Windows, Mac, Linux, ARM
○ Useful for end users as well as team administrators
● Support for Dropbox Paper coming soon!
○ https://www.dropbox.com/paper
How to build SDKs in Go
How to build SDKs in Go

Más contenido relacionado

La actualidad más candente

La actualidad más candente (20)

Introduction to Kubernetes Workshop
Introduction to Kubernetes WorkshopIntroduction to Kubernetes Workshop
Introduction to Kubernetes Workshop
 
D2 domain driven-design
D2 domain driven-designD2 domain driven-design
D2 domain driven-design
 
Introduction to Kubernetes and Google Container Engine (GKE)
Introduction to Kubernetes and Google Container Engine (GKE)Introduction to Kubernetes and Google Container Engine (GKE)
Introduction to Kubernetes and Google Container Engine (GKE)
 
Docker swarm
Docker swarmDocker swarm
Docker swarm
 
Deploy Application on Kubernetes
Deploy Application on KubernetesDeploy Application on Kubernetes
Deploy Application on Kubernetes
 
Grafana Loki: like Prometheus, but for Logs
Grafana Loki: like Prometheus, but for LogsGrafana Loki: like Prometheus, but for Logs
Grafana Loki: like Prometheus, but for Logs
 
Delivering Quality at Speed with GitOps
Delivering Quality at Speed with GitOpsDelivering Quality at Speed with GitOps
Delivering Quality at Speed with GitOps
 
Docker: From Zero to Hero
Docker: From Zero to HeroDocker: From Zero to Hero
Docker: From Zero to Hero
 
Istio : Service Mesh
Istio : Service MeshIstio : Service Mesh
Istio : Service Mesh
 
Istio on Kubernetes
Istio on KubernetesIstio on Kubernetes
Istio on Kubernetes
 
Docker introduction
Docker introductionDocker introduction
Docker introduction
 
Docker networking Tutorial 101
Docker networking Tutorial 101Docker networking Tutorial 101
Docker networking Tutorial 101
 
Advanced Deployment Strategies with Kubernetes and Istio
Advanced Deployment Strategies with Kubernetes and IstioAdvanced Deployment Strategies with Kubernetes and Istio
Advanced Deployment Strategies with Kubernetes and Istio
 
Evolution of containers to kubernetes
Evolution of containers to kubernetesEvolution of containers to kubernetes
Evolution of containers to kubernetes
 
Kubernetes 101 - A Cluster Operating System
Kubernetes 101 - A Cluster Operating SystemKubernetes 101 - A Cluster Operating System
Kubernetes 101 - A Cluster Operating System
 
Write microservice in golang
Write microservice in golangWrite microservice in golang
Write microservice in golang
 
Bighead: Airbnb’s End-to-End Machine Learning Platform with Krishna Puttaswa...
 Bighead: Airbnb’s End-to-End Machine Learning Platform with Krishna Puttaswa... Bighead: Airbnb’s End-to-End Machine Learning Platform with Krishna Puttaswa...
Bighead: Airbnb’s End-to-End Machine Learning Platform with Krishna Puttaswa...
 
Creating a Context-Aware solution, Complex Event Processing with FIWARE Perseo
Creating a Context-Aware solution, Complex Event Processing with FIWARE PerseoCreating a Context-Aware solution, Complex Event Processing with FIWARE Perseo
Creating a Context-Aware solution, Complex Event Processing with FIWARE Perseo
 
Exploring the power of OpenTelemetry on Kubernetes
Exploring the power of OpenTelemetry on KubernetesExploring the power of OpenTelemetry on Kubernetes
Exploring the power of OpenTelemetry on Kubernetes
 
Google Kubernetes Engine Deep Dive Meetup
Google Kubernetes Engine Deep Dive MeetupGoogle Kubernetes Engine Deep Dive Meetup
Google Kubernetes Engine Deep Dive Meetup
 

Similar a How to build SDKs in Go

JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...
JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...
JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...
Guillaume Laforge
 

Similar a How to build SDKs in Go (20)

Go 1.10 Release Party - PDX Go
Go 1.10 Release Party - PDX GoGo 1.10 Release Party - PDX Go
Go 1.10 Release Party - PDX Go
 
Grails Introduction - IJTC 2007
Grails Introduction - IJTC 2007Grails Introduction - IJTC 2007
Grails Introduction - IJTC 2007
 
"Xapi-lang For declarative code generation" By James Nelson
"Xapi-lang For declarative code generation" By James Nelson"Xapi-lang For declarative code generation" By James Nelson
"Xapi-lang For declarative code generation" By James Nelson
 
Getting started with go - Florin Patan - Codemotion Milan 2016
Getting started with go - Florin Patan - Codemotion Milan 2016Getting started with go - Florin Patan - Codemotion Milan 2016
Getting started with go - Florin Patan - Codemotion Milan 2016
 
Grooscript greach
Grooscript greachGrooscript greach
Grooscript greach
 
dojo.Patterns
dojo.Patternsdojo.Patterns
dojo.Patterns
 
Mobile Apps by Pure Go with Reverse Binding
Mobile Apps by Pure Go with Reverse BindingMobile Apps by Pure Go with Reverse Binding
Mobile Apps by Pure Go with Reverse Binding
 
Building Dojo in the Cloud
Building Dojo in the CloudBuilding Dojo in the Cloud
Building Dojo in the Cloud
 
JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...
JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...
JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...
 
Build Great Networked APIs with Swift, OpenAPI, and gRPC
Build Great Networked APIs with Swift, OpenAPI, and gRPCBuild Great Networked APIs with Swift, OpenAPI, and gRPC
Build Great Networked APIs with Swift, OpenAPI, and gRPC
 
Grooscript gr8conf 2015
Grooscript gr8conf 2015Grooscript gr8conf 2015
Grooscript gr8conf 2015
 
Go, meet Lua
Go, meet LuaGo, meet Lua
Go, meet Lua
 
Missing objects: ?. and ?? in JavaScript (BrazilJS 2018)
Missing objects: ?. and ?? in JavaScript (BrazilJS 2018)Missing objects: ?. and ?? in JavaScript (BrazilJS 2018)
Missing objects: ?. and ?? in JavaScript (BrazilJS 2018)
 
Daniel Steigerwald: EsteJS - javascriptové aplikace robusně, modulárně a komf...
Daniel Steigerwald: EsteJS - javascriptové aplikace robusně, modulárně a komf...Daniel Steigerwald: EsteJS - javascriptové aplikace robusně, modulárně a komf...
Daniel Steigerwald: EsteJS - javascriptové aplikace robusně, modulárně a komf...
 
Little Did He Know ...
Little Did He Know ...Little Did He Know ...
Little Did He Know ...
 
JavaScript ES6
JavaScript ES6JavaScript ES6
JavaScript ES6
 
Cape Cod Web Technology Meetup - 3
Cape Cod Web Technology Meetup - 3Cape Cod Web Technology Meetup - 3
Cape Cod Web Technology Meetup - 3
 
PHP BASIC PRESENTATION
PHP BASIC PRESENTATIONPHP BASIC PRESENTATION
PHP BASIC PRESENTATION
 
Golang introduction
Golang introductionGolang introduction
Golang introduction
 
SF Grails - Ratpack - Compact Groovy Webapps - James Williams
SF Grails - Ratpack - Compact Groovy Webapps - James WilliamsSF Grails - Ratpack - Compact Groovy Webapps - James Williams
SF Grails - Ratpack - Compact Groovy Webapps - James Williams
 

Último

Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Medical / Health Care (+971588192166) Mifepristone and Misoprostol tablets 200mg
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
masabamasaba
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
masabamasaba
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
masabamasaba
 

Último (20)

%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go Platformless
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the Situation
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
tonesoftg
tonesoftgtonesoftg
tonesoftg
 
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
 
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
 
WSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaSWSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaS
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
 

How to build SDKs in Go

  • 1. How to build SDKs in Go Lessons from the Go SDK for Dropbox
  • 2. Diwaker Gupta ● Infrastructure @ Dropbox ● Metadata Services, Multihoming, Search, Messaging, Email, Notifications, Machine Learning etc ● Authored Dropbox Go SDK and dbxcli ● Twitter/Github: @diwakergupta
  • 4. ● Gophercon ‘17 Keynote by @tammybutow: https://bit.ly/gophercon17dbx ● Dozens of Go services, many with millions of RPS! ● We open source at: https://github.com/dropbox ● We are hiring! dropbox.com/jobs or email me (diwaker@)
  • 5. Lessons from the Dropbox Go SDK
  • 6. #1: Use a Code Generator
  • 7. #1: Use a code generator ● Language-agnostic API definition (DSL, JSON, YAML, etc), Language-specific generators ● Dropbox Stone (spec + generators) ○ https://github.com/dropbox/stone ● Google ○ JSON Spec https://developers.google.com/discovery/ ○ Codegen https://github.com/google/google-api-go-client/ ● AWS Go SDK has a very similar setup ● OpenAPI: https://github.com/OAI/OpenAPI-Specification
  • 9. #2: Avoid Surprises ● Principle of Least Surprise ● No external dependencies ○ Only standard library imports ● No vendored dependencies ● What you need is what you get ○ Scoped sub-packages for larger APIs (e.g. AWS) ○ Make it `go get` friendly
  • 11. #3: Make Configuration Simple ● Don’t use cmdline flags ○ Stdlib limitations ● Environment variables ○ OK, but beware pitfalls ● Use a config struct ○ Same pattern in AWS SDK ● Persistence outside SDK ○ Let applications choose ○ dbxcli load/stores json configs // Config contains parameters for configuring the SDK. type Config struct { // OAuth2 access token Token string // Enable verbose logging in SDK Verbose bool ... // For testing only Client *http.Client }
  • 13. #4: Provide Visibility ● Allow verbose logging ● Allow configurable logging targets ● Limited by stdlib :( type Config struct { // Enable verbose logging Verbose bool // Optional logging target Logger *log.Logger } // TryLog will, if Verbose is set, log to // the config's logger or the default logger // if Config.Logger is nil. func (c *Config) TryLog(format string, v ...interface{}) { if !c.Verbose { return } if c.Logger != nil { c.Logger.Printf(format, v...) } else { log.Printf(format, v...) } }
  • 14. #5: Use Go idioms for unsupported types
  • 15. #5: Unions Consider (in Stone): union DeleteError path_lookup LookupError path_write WriteError In JSON (note LookupError): { ".tag": "path_lookup", "path_lookup": { ".tag": "malformed_path", "malformed_path": "/some/path" } } Equivalent struct in Go type DeleteError struct { dropbox.Tagged PathLookup *LookupError `json:"path_lookup"` PathWrite *WriteError `json:"path_write"` } Problem: (de)serialization
  • 16. func (u *DeleteError) UnmarshalJSON(body []byte) error { type wrap struct { dropbox.Tagged PathLookup json.RawMessage PathWrite json.RawMessage } var w wrap switch w.Tag { case "path_lookup": err = json.Unmarshal(w.PathLookup, &u.PathLookup) ... case "path_write": err = json.Unmarshal(w.PathWrite, &u.PathWrite) ... } #5: Unions type DeleteError struct { dropbox.Tagged PathLookup *LookupError `json:"path_lookup,omitempty"` PathWrite *WriteError `json:"path_write,omitempty"` } { ".tag": "path_lookup", "path_lookup": { ".tag": "malformed_path", "malformed_path": "/some/path" } }
  • 17. #5: Inherited Types In Stone struct Metadata // Common fields: Name, Path etc union file FileMetadata folder FolderMetadata Idiomatic Go: Embedding type Metadata struct { // Common fields } type FileMetadata struct { Metadata // FileMetadata specific fields } type FolderMetadata struct { Metadata // FolderMetadata specific fields }
  • 18. Solution: Use a dummy interface type IsMetadata interface { IsMetadata() } // Subtypes get this via embedding func (u *Metadata) IsMetadata() {} // Use IsMetadata where you need // the union type #5: Inherited Types Problem: Polymorphism func List(...) []Metadata Can return FileMetadata or FolderMetadata
  • 19. Similar trick as Unions type metadataUnion struct { dropbox.Tagged File *FileMetadata Folder *FolderMetadata } func IsMetadataFromJSON(data []byte) (IsMetadata, e) { var t metadataUnion if err := json.Unmarshal(data, &t); err != nil { return nil, err } switch t.Tag { ... } } #5: Inherited Types Problem: (de)serialization { ".tag": "file", "name": "Prime_Numbers.txt", "id": "id:a4ayc_80_OEAAAAAAAAAXw", "content_hash": "e3b0c44298fc" } OR { ".tag": "folder", "name": "math", "id": "id:a4ayc_80_OEAAAAAAAAAXz", "path_lower": "/homework/math", }
  • 20. #6: Do NOT authenticate
  • 21. #6: Do NOT authenticate ● Apps authenticate, SDK accepts OAuth Token ● Beware of known OAuth pitfalls ○ Changed OAuth Endpoint from api.dropbox.com to api.dropboxapi.com ○ App started failing with oauth2: cannot fetch token: 400 Bad Request ○ Gem from oauth2/internal/token.go ○ func RegisterBrokenAuthHeaderProvider(tokenURL string) ○ Google, Stripe and yes, Dropbox are “broken” ● More information: ○ On debugging OAuth2 in #golang
  • 23. #7: Auto Generate Tests ● Tests should be comprehensive and up-to-date ● Dropbox SDK is NOT a good example! ● Model after AWS SDK ○ Example input/output defined in JSON ○ Tests are auto-generated ● Not a panacea, still need to write tests! ○ Especially negative tests
  • 24. #8: Handle errors the Go way
  • 25. #8: Handle errors the Go way Dropbox SDK res, err := dbx.ListFolder(arg) if err != nil { switch e := err.(type) { case files.ListFolderAPIError: ... AWS SDK output, err := s3manage.Upload(...) if err != nil { if reqerr, ok := err.(RequestFailure); ok { ... ● Have SDK errors implement the `error` interface ● Use type assertions to extract errors ● Good packages exist for combining / unrolling errors -- wish stdlib had more support!
  • 26. Lessons Recap 1. Use a Code Generator 2. Avoid Surprises 3. Make Configuration Simple 4. Provide Visibility 5. Use Go Idioms for Unsupported Types 6. Do Not Authenticate 7. Auto Generate Tests 8. Handle Errors the Go Way
  • 27. Where to get it? ● SDK:https://github.com/dropbox/dropbox-sdk-go-unofficial ● dbxcli: https://github.com/dropbox/dbxcli/ ○ Command line tool for Dropbox ○ Pre-compiled binaries for Windows, Mac, Linux, ARM ○ Useful for end users as well as team administrators ● Support for Dropbox Paper coming soon! ○ https://www.dropbox.com/paper