Current section
Files
Jump to
Current section
Files
lib/rs_twitter.ex
defmodule RsTwitter do
@http_client Application.get_env(:rs_twitter, :http_client, RsTwitter.Http.Client)
@moduledoc """
Twitter API SDK
This is low level twitter client. The idea behind this package is not to define special functions for each endpoint,
but use generic request structure that will allow to make requests to any of twitter API endpoints.
## Setup
```
# Add your twitter app credentials to your app config
config :rs_twitter,
consumer_key: "your_app_consumer_key",
consumer_secret: "your_app_consumer_secret"
```
## How to use
```
iex(1)> %RsTwitter.Request{endpoint: "followers/ids", parameters: %{"screen_name" => "radzserg"}}
|> RsTwitter.request()
{:ok,
%RsTwitter.Response{
body: %{
"ids" => [55555555, 55555556, ...],
"next_cursor" => 1593278910906579502,
"next_cursor_str" => "1593278910906579502",
"previous_cursor" => 0,
"previous_cursor_str" => "0"
},
headers: [
....
{"x-rate-limit-limit", "15"},
{"x-rate-limit-remaining", "12"},
{"x-rate-limit-reset", "1534264549"},
{"x-response-time", "172"},
],
status_code: 200
}}
```
## Handle response/errors
```
%RsTwitter.Request{method: :post, endpoint: "followers/ids", parameters: %{"screen_name" => "radzserg"}}
|> RsTwitter.request()
|> proceed_response()
defp proceed_response({:ok, response = %RsTwitter.Response{status_code: 200,
%{body: %{"ids" => ids, "next_cursor" => next_cursor}}}}) do
# everything is ok do what you need with IDs
end
defp proceed_response({:error, response = %RsTwitter.Response{body: %{"errors" => errors}}}) do
# successfull request but some twitter error happened,
# decide what to do with the error
# https://developer.twitter.com/en/docs/basics/response-codes.html
# For example:
if RsTwitter.Response.has_error_code?(response, 88) do
# rate limit reached
end
end
defp proceed_response({:error, error}) when is_atom(error) do
# network error happened during request to twitter
end
```
## User Authentication
We worked with application authentication. i.e. we send only application `consumer_key` and `consumer_secret`.
In order to use user authentication we need to add `%RsTwitter.Credentials` to `RsTwitter.Request`.
*RsTwitter* do not obtain user token/secret. Please use specific packages like
[Überauth Twitter](https://github.com/ueberauth/ueberauth_twitter) to obtain user credentials.
As soon as you have user token and secret just add them to request.
```
iex(1)> credentials = %RsTwitter.Credentials{token: "your_user_token",
token_secret: "your_user_secret"}
iex(2)> request = %RsTwitter.Request{endpoint: "followers/ids",
parameters: %{"user_id" => 123}, credentials: credentials}
```
"""
@twitter_url "https://api.twitter.com/1.1/"
@doc """
Makes request to twitter API
Provide valid %RsTwitter.Request{} to make request
### Common usage
```
%RsTwitter.Request{method: :post, endpoint: "friendships/create",
parameters: %{"screen_name" => "radzserg"}, credentials: credentials}
|> RsTwitter.request()
```
### Examples
```
%RsTwitter.Request{endpoint: "followers/ids", parameters: %{"user_id" => 123},
credentials: credentials}
%RsTwitter.Request{endpoint: "users/lookup", parameters: %{"screen_name" => "johndoe"},
credentials: credentials}
%RsTwitter.Request{method: :post, endpoint: "friendships/create",
parameters: %{"screen_name" => "radzserg"}, credentials: credentials}
```
Build request using
[Twitter Docs](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference)
"""
@spec request(RsTwitter.Request.t()) :: {:ok, RsTwitter.Response.t()} | {:error, atom()}
def request(request = %RsTwitter.Request{}) do
url = build_url(request)
headers =
[{"Content-Type", "application/json"}]
|> RsTwitter.Auth.append_authorization_header(
request.method,
url,
[],
request.credentials
)
@http_client.request(request.method, url, [], headers)
|> handle_response
end
defp handle_response({:ok, response = %HTTPoison.Response{}}) do
%{status_code: status_code, body: body, headers: headers} = response
body = Poison.decode!(body)
if status_code == 200 do
{:ok, %RsTwitter.Response{status_code: status_code, body: body, headers: headers}}
else
{:error, %RsTwitter.Response{status_code: status_code, body: body, headers: headers}}
end
end
defp handle_response({:error, %HTTPoison.Error{reason: reason}}) do
{:error, reason}
end
defp build_url(request = %RsTwitter.Request{}) do
url = @twitter_url <> request.endpoint <> ".json"
query_string = URI.encode_query(request.parameters)
if query_string == "", do: url, else: url <> "?#{query_string}"
end
end