twittergo

package module
v0.0.0-...-340f65d Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 15, 2021 License: Apache-2.0 Imports: 16 Imported by: 56

README

twittergo

This project implements a Go client library for the Twitter APIs. This library supports version 1.1 of Twitter's API and application-only auth.

The goal of this project is to provide a thin veneer over my oauth1a library in order to simplify access to Twitter's APIs from Go. Where possible, I've tried to defer to native objects (use of http requests for example). Additionally, responses could be parsed directly as JSON, but some wrapper types have been defined in order to provide some convenience methods for accessing data.

Build Status

Installing

Run

go get github.com/kurrik/twittergo

Include in your source:

import "github.com/kurrik/twittergo"

Godoc

See http://godoc.org/github.com/kurrik/twittergo

Using

I have moved all of the examples to the https://github.com/kurrik/twittergo-examples project in order to make this library easier to import. Please reference that project for ways to address specific use cases.

The simplest example in the twittergo-examples project is probably verify_credentials. This calls an endpoint which will return the current user if the request is signed correctly.

The example starts by loading credentials, which can be done in many ways. The example implements a LoadCredentials which looks for the CREDENTIALS file mentioned above:

var (
    err    error
    client *twittergo.Client
    req    *http.Request
    resp   *twittergo.APIResponse
    user   *twittergo.User
)
client, err = LoadCredentials()
if err != nil {
    fmt.Printf("Could not parse CREDENTIALS file: %v\n", err)
    os.Exit(1)
}

Then, a standard http request is created to a /1.1/ endpoint:

req, err = http.NewRequest("GET", "/1.1/account/verify_credentials.json", nil)
if err != nil {
    fmt.Printf("Could not parse request: %v\n", err)
    os.Exit(1)
}

The client object handles sending the request:

resp, err = client.SendRequest(req)
if err != nil {
    fmt.Printf("Could not send request: %v\n", err)
    os.Exit(1)
}

The response object has some convenience methods for checking rate limits, etc:

if resp.HasRateLimit() {
    fmt.Printf("Rate limit:           %v\n", resp.RateLimit())
    fmt.Printf("Rate limit remaining: %v\n", resp.RateLimitRemaining())
    fmt.Printf("Rate limit reset:     %v\n", resp.RateLimitReset())
} else {
    fmt.Printf("Could not parse rate limit from response.\n")
}

Finally, if the response format is known, the library provides some standard objects which make parsing response data easier:

user = &twittergo.User{}
err = resp.Parse(user)
if err != nil {
    fmt.Printf("Problem parsing response: %v\n", err)
    os.Exit(1)
}
fmt.Printf("ID:                   %v\n", user.Id())
fmt.Printf("Name:                 %v\n", user.Name())

Error handling

Errors are returned by most methods as is Golang convention. However, these errors may sometimes be cast into twittergo.ResponseError, twittergo.Errors or twittergo.RateLimitError structs which will provide additional information.

To check for rate limiting or other types of server errors, attempt to cast any errors returned by the APIResponse.Parse method.

resp, err = client.SendRequest(req)
if err != nil {
    fmt.Printf("Could not send request: %v\n", err)
    os.Exit(1)
}
tweet = &twittergo.Tweet{}
err = resp.Parse(tweet)
if err != nil {
    if rle, ok := err.(twittergo.RateLimitError); ok {
        fmt.Printf("Rate limited, reset at %v\n", rle.Reset)
    } else if errs, ok := err.(twittergo.Errors); ok {
        for i, val := range errs.Errors() {
            fmt.Printf("Error #%v - ", i + 1)
            fmt.Printf("Code: %v ", val.Code())
            fmt.Printf("Msg: %v\n", val.Message())
        }
    } else {
        fmt.Printf("Problem parsing response: %v\n", err)
    }
    os.Exit(1)
}

The previous snippet would print the following if a user attempted to Tweet the same text twice in a row:

Error #1 - Code: 187 Msg: Status is a duplicate

Rate limit errors are pretty easy to use. They're a simple struct containing what the limit for the request was, how many were remaining (should be 0) and when the limiting resets:

type RateLimitError struct {
    Limit     uint32
    Remaining uint32
    Reset     time.Time
}

The Errors type is a little more complicated, as it may return one or more server side errors. It is possible to cast one to a string using the standard Error method, but if you need to handle individual errors, iterate over the slice returned by Errors (plural) instead:

for i, val := range errs.Errors() {
    fmt.Printf("Error #%v - ", i + 1)
    fmt.Printf("Code: %v ", val.Code())
    fmt.Printf("Msg: %v\n", val.Message())
}

Each of those errors has a Code and a Message method, which return values and strings corresponding to those listed in the "Error codes" section of this page: https://dev.twitter.com/docs/error-codes-responses

Application-only auth

If no user credentials are set, then the library falls back to attempting to authenticate with application-only auth, as described here: https://dev.twitter.com/docs/auth/application-only-auth

If you want to obtain an access token for later use, create a client with no user credentials.

config := &oauth1a.ClientConfig{
    ConsumerKey:    "consumer_key",
    ConsumerSecret: "consumer_secret",
}
client = twittergo.NewClient(config, nil)
if err := c.FetchAppToken(); err != nil {
    // Handle error ...
}
token := c.GetAppToken()
// ... Save token in data store

To restore a previously obtained token, just call SetAppToken():

// Get token from data store ...
c.SetAppToken(token)

Saving and restoring the token isn't necessary if you keep the client in memory, though. If you just create a client without any user credentials, calls to SendRequest will automatically fetch and persist the app token in memory. See search_app_auth/main.go for an example of this.

Google App Engine

This library works with Google App Engine's Go runtime but requires slight modification to fall back on the urlfetch package for http transport.

After creating a Client, replace its HttpClient with an instance of urlfetch.Client:

var (
    r      *http.Request
    config *oauth1a.ClientConfig
    user   *oauth1a.UserConfig
)
...
ctx = appengine.NewContext(r)
c = twittergo.NewClient(config, user)
c.HttpClient = urlfetch.Client(ctx)

For a comprehensive example, see user_timeline_appengine

Custom models

The twittergo library comes with some standard models for structures like Tweets and Timelines, but you are not required to use them. Pass any struct which will deserialize from a Twitter API response to APIResponse.Parse:

type CustomTweet struct {
    CustomID   string `json:"id_str"`
    CustomText string `json:"text"`
}
...

req, err = http.NewRequest("GET", url, nil)
...
resp, err = client.SendRequest(req)
customTweet = &CustomTweet{}
err = resp.Parse(customTweet)
...

For complete code, see the custom_struct example.

Debugging

To see what requests are being issued by the library, set up an HTTP proxy such as Charles Proxy and then set the following environment variable:

export HTTP_PROXY=http://localhost:8888

Because Go will reject HTTPS requests through a proxy, you'll need to set the following for any HTTPS endpoints:

export TLS_INSECURE=1

Make sure not to use this in production!

Documentation

Overview

Implements a Twitter client library in Go.

Index

Constants

View Source
const (
	H_LIMIT              = "X-Rate-Limit-Limit"
	H_LIMIT_REMAIN       = "X-Rate-Limit-Remaining"
	H_LIMIT_RESET        = "X-Rate-Limit-Reset"
	H_MEDIA_LIMIT        = "X-MediaRateLimit-Limit"
	H_MEDIA_LIMIT_REMAIN = "X-MediaRateLimit-Remaining"
	H_MEDIA_LIMIT_RESET  = "X-MediaRateLimit-Reset"
)
View Source
const (
	STATUS_OK           = 200
	STATUS_CREATED      = 201
	STATUS_ACCEPTED     = 202
	STATUS_NO_CONTENT   = 204
	STATUS_INVALID      = 400
	STATUS_UNAUTHORIZED = 401
	STATUS_FORBIDDEN    = 403
	STATUS_NOTFOUND     = 404
	STATUS_LIMIT        = 429
	STATUS_GATEWAY      = 502
)

Variables

This section is empty.

Functions

This section is empty.

Types

type APIResponse

type APIResponse http.Response

APIResponse provides methods for retrieving information from the HTTP headers in a Twitter API response.

func (APIResponse) HasMediaRateLimit

func (r APIResponse) HasMediaRateLimit() bool

func (APIResponse) HasRateLimit

func (r APIResponse) HasRateLimit() bool

func (APIResponse) MediaRateLimit

func (r APIResponse) MediaRateLimit() uint32

func (APIResponse) MediaRateLimitRemaining

func (r APIResponse) MediaRateLimitRemaining() uint32

func (APIResponse) MediaRateLimitReset

func (r APIResponse) MediaRateLimitReset() time.Time

func (APIResponse) Parse

func (r APIResponse) Parse(out interface{}) (err error)

Parse unmarshals a JSON encoded HTTP response into the supplied interface, with handling for the various kinds of errors the Twitter API can return.

The returned error may be of the type Errors, RateLimitError, ResponseError, or an error returned from io.Reader.Read().

func (APIResponse) RateLimit

func (r APIResponse) RateLimit() uint32

func (APIResponse) RateLimitRemaining

func (r APIResponse) RateLimitRemaining() uint32

func (APIResponse) RateLimitReset

func (r APIResponse) RateLimitReset() time.Time

func (APIResponse) ReadBody

func (r APIResponse) ReadBody() string

ReadBody returns the body of the response as a string. Only one of ReadBody and Parse may be called on a given APIResponse.

type BearerToken

type BearerToken struct {
	AccessToken string
}

type Client

type Client struct {
	Host       string
	OAuth      *oauth1a.Service
	User       *oauth1a.UserConfig
	AppToken   *BearerToken
	HttpClient *http.Client
}

Implements a Twitter client.

func NewClient

func NewClient(config *oauth1a.ClientConfig, user *oauth1a.UserConfig) *Client

Creates a new Twitter client with the supplied OAuth configuration. Supports the use of HTTP proxies through the $HTTP_PROXY env var. For example:

export HTTP_PROXY=http://localhost:8888

When using a proxy, disable TLS certificate verification with the following:

export TLS_INSECURE=1

func (*Client) FetchAppToken

func (c *Client) FetchAppToken() (err error)

Requests a new app auth bearer token and stores it.

func (*Client) GetAppToken

func (c *Client) GetAppToken() string

Returns the current app-only auth token or an empty string. Must call FetchAppToken to populate this value before getting it. You may call SetAppToken with the value returned by this call in order to restore a previously-fetched bearer token to use.

func (*Client) SendRequest

func (c *Client) SendRequest(req *http.Request) (resp *APIResponse, err error)

Sends a HTTP request through this instance's HTTP client.

func (*Client) SetAppToken

func (c *Client) SetAppToken(token string)

Sets the app-only auth token to the specified string.

func (*Client) SetUser

func (c *Client) SetUser(user *oauth1a.UserConfig)

Changes the user authorization credentials for this client.

func (*Client) Sign

func (c *Client) Sign(req *http.Request) (err error)

Signs the request with app-only auth, fetching a bearer token if needed.

type CursoredLists

type CursoredLists map[string]interface{}

func (CursoredLists) Lists

func (cl CursoredLists) Lists() Lists

func (CursoredLists) NextCursorStr

func (cl CursoredLists) NextCursorStr() string

func (CursoredLists) PreviousCursorStr

func (cl CursoredLists) PreviousCursorStr() string

type Entities

type Entities map[string]interface{}

Entities such as hashtags present in the Tweet. https://developer.twitter.com/en/docs/tweets/data-dictionary/overview/entities-object

func (Entities) Hashtags

func (e Entities) Hashtags() []Hashtag

func (Entities) Media

func (e Entities) Media() []Media

func (Entities) Polls

func (e Entities) Polls() []Poll

func (Entities) Symbols

func (e Entities) Symbols() []Symbol

func (Entities) URLs

func (e Entities) URLs() []URL

func (Entities) UserMentions

func (e Entities) UserMentions() []UserMention

type Error

type Error map[string]interface{}

func (Error) Code

func (e Error) Code() int64

func (Error) Error

func (e Error) Error() string

func (Error) Message

func (e Error) Message() string

type Errors

type Errors map[string]interface{}

func (Errors) Error

func (e Errors) Error() string

func (Errors) Errors

func (e Errors) Errors() []Error

func (Errors) String

func (e Errors) String() string

type Hashtag

type Hashtag map[string]interface{}

Hashtag reference in text.

type List

type List map[string]interface{}

A List!

func (List) Id

func (l List) Id() (id uint64)

func (List) IdStr

func (l List) IdStr() string

func (List) MemberCount

func (l List) MemberCount() int64

func (List) Mode

func (l List) Mode() string

func (List) Name

func (l List) Name() string

func (List) Slug

func (l List) Slug() string

func (List) SubscriberCount

func (l List) SubscriberCount() int64

func (List) User

func (l List) User() User

type Lists

type Lists []List

It's a less structured list of Lists!

type Media

type Media map[string]interface{}

Media object reference in text.

type MediaResponse

type MediaResponse map[string]interface{}

Response for media upload requests.

func (MediaResponse) ExpiresAfterSecs

func (r MediaResponse) ExpiresAfterSecs() int32

func (MediaResponse) MediaId

func (r MediaResponse) MediaId() int64

func (MediaResponse) Size

func (r MediaResponse) Size() int64

func (MediaResponse) Video

func (r MediaResponse) Video() VideoUpload

type Poll

type Poll map[string]interface{}

Poll object associated with a Tweet.

type Range

type Range []int

A range, typically representing text ranges.

type RateLimitError

type RateLimitError struct {
	Limit     uint32
	Remaining uint32
	Reset     time.Time
}

RateLimitError is returned from SendRequest when a rate limit is encountered.

func (RateLimitError) Error

func (e RateLimitError) Error() string

func (RateLimitError) HasRateLimit

func (e RateLimitError) HasRateLimit() bool

func (RateLimitError) RateLimit

func (e RateLimitError) RateLimit() uint32

func (RateLimitError) RateLimitRemaining

func (e RateLimitError) RateLimitRemaining() uint32

func (RateLimitError) RateLimitReset

func (e RateLimitError) RateLimitReset() time.Time

type RateLimitResponse

type RateLimitResponse interface {
	// HasRateLimit returns false if the ratelimiting information is
	// optional and missing.
	HasRateLimit() bool
	// RateLimit returns the requests per time period capacity of the
	// limit.
	RateLimit() uint32
	// RateLimitRemaining returns how many requests are still available
	// in the current time period.
	RateLimitRemaining() uint32
	// RateLimitReset returns when the rate limit will reset.
	RateLimitReset() time.Time
}

RateLimitResponse is implemented by both RateLimitError and APIResponse.

type ResponseError

type ResponseError struct {
	Body string
	Code int
}

Error returned if there was an issue parsing the response body.

func NewResponseError

func NewResponseError(code int, body string) ResponseError

func (ResponseError) Error

func (e ResponseError) Error() string

type SearchResults

type SearchResults map[string]interface{}

It's a structured list of Tweets!

func (SearchResults) NextQuery

func (sr SearchResults) NextQuery() (val url.Values, err error)

func (SearchResults) SearchMetadata

func (sr SearchResults) SearchMetadata() map[string]interface{}

func (SearchResults) Statuses

func (sr SearchResults) Statuses() []Tweet

type Symbol

type Symbol map[string]interface{}

Symbol (e.g. cashtag) reference in text.

type Timeline

type Timeline []Tweet

It's a less structured list of Tweets!

type Tweet

type Tweet map[string]interface{}

It's a Tweet! (Adorably referred to by the API as a "status"). https://developer.twitter.com/en/docs/tweets/data-dictionary/overview/intro-to-tweet-json https://developer.twitter.com/en/docs/tweets/data-dictionary/overview/tweet-object https://developer.twitter.com/en/docs/tweets/data-dictionary/overview/extended-entities-object

func (Tweet) CreatedAt

func (t Tweet) CreatedAt() (out time.Time)

func (Tweet) Entities

func (t Tweet) Entities() Entities

func (Tweet) ExtendedEntities

func (t Tweet) ExtendedEntities() Entities

func (Tweet) ExtendedTweet

func (t Tweet) ExtendedTweet() Tweet

func (Tweet) FullText

func (t Tweet) FullText() string

func (Tweet) Id

func (t Tweet) Id() (id uint64)

func (Tweet) IdStr

func (t Tweet) IdStr() string

func (Tweet) Language

func (t Tweet) Language() string

func (Tweet) Text

func (t Tweet) Text() string

func (Tweet) Truncated

func (t Tweet) Truncated() bool

func (Tweet) User

func (t Tweet) User() User

type URL

type URL map[string]interface{}

Url reference in text.

type User

type User map[string]interface{}

It's a user!

func (User) Id

func (u User) Id() uint64

func (User) IdStr

func (u User) IdStr() string

func (User) Name

func (u User) Name() string

func (User) ScreenName

func (u User) ScreenName() string

type UserMention

type UserMention map[string]interface{}

User mention in text.

type VideoUpload

type VideoUpload map[string]interface{}

Nested response structure for video uploads.

func (VideoUpload) Type

func (v VideoUpload) Type() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL