Tumblr Engineering — tumblr.js update


You’ve been asking for an official Golang wrapper for the Tumblr API. The wait is over! We are thrilled to unveil two new repositories on our GitHub page which can be the gateway to the Tumblr API in your Go project.

Why Two Repos

We’ve tried to structure the wrapper in a way that is as flexible as possible so we’ve put the meat of the library in one repo that contains the code for creating requests and parsing the responses, and interacts with an interface that implements methods for making basic REST requests.

The second repo is an implementation of that interface with external dependencies used to sign requests using OAuth. If you do not wish to include these dependencies, you may write your own implementation of the ClientInterface and have the wrapper library use that client instead.

Handling Dynamic Response Types

Go is a strictly typed language including the data structures you marshal JSON responses into. This means that the library could have surfaced response data as a map of string => interface{} generics which would require the engineer to further cast into an int, string, another map of string => interface{}, etc. The API Team decided to make it more convenient for you by providing typed response values from various endpoints.

If you have used the Tumblr API, you’ll know that our Post object is highly variant in what properties and types are returned based on the post type. This proved to be a challenge in codifying the response data. In Go, you’d hope to simply be able to define a dashboard response as an array of posts

type Dashboard struct {
  // ... other properties
  Posts []Post `json:"posts"`
}

However this would mean we’d need a general Post struct type with the union of all possible properties on a Post across all post types. Further complicating this approach, we found that some properties with the same name have different types across post types. The highest profile example: an Audio post’s player property is a string of HTML while a Video post’s player property is an array of embed strings. Of course we could type any property with such conflicts as interface{} but then we’re back to the same problem as before where the engineer then has to cast values to effectively use them.

Doing Work So You Don’t Have To

Instead, we decided any array of posts could in fact be represented as an array of PostInterfaces. When decoding a response, we scan through each post in the response and create a correspondingly typed instance in an array, and return the array of instances as an array of PostInterfaces. Then, when marshalling the JSON into the array, the data fills in to the proper places with the proper types. The end user can then interact with the array of PostInterface instances by accessing universal properties (those that exist on any post type) with ease. If they wish to use a type-specific property, they can cast an instance to a specific post type once, and use all the typed properties afterward.

This can be especially convenient when paired with Go’s HTML templating system:

snippet.go

// previously, we have some `var response http.ResponseWriter`
client := tumblrclient.NewClientWithToken(
    // ... auth data
)

if t,err := template.New("posts").ParseFiles("post.tmpl"); err == nil {
    if dash,err := client.GetDashboard(); err == nil {
        for _,p := range dash.Posts {
            t.ExecuteTemplate(response, p.GetSelf().Type, p.GetSelf())
        }
    }
}

post.tmpl

{{define "text"}}
<div>
    {{.Body | html}}
</div>
{{end}}
{{define "photo"}}
<div>
    Post: {{.Type}}
</div>
{{end}}
{{define "video"}}
<div>
    Post: {{.Type}}
</div>
{{end}}
{{define "audio"}}
<div>
    Post: {{.Type}}
</div>
{{end}}
{{define "quote"}}
<div>
    Post: {{.Type}}
</div>
{{end}}
{{define "chat"}}
<div>
    Post: {{.Type}}
</div>
{{end}}
{{define "answer"}}
<div>
    Post: {{.Type}}
</div>
{{end}}
{{define "link"}}
<div>
    Post: {{.Type}}
</div>
{{end}}

This is a rudimentary example, but the convenience and utility is fairly evident. You can define blocks to be rendered, named by the post’s type value. Those blocks can then assume the object in its named scope is a specific post struct and access the typed values directly.

Wrapping Up

This is a v1.0 release and our goal was to release a limited scope, but flexible utility for developers to use. We plan on implementing plenty of new features and improvements in the future, and to make sure that improvements to the API are brought into the wrapper. Hope you enjoy using it!



Source link