DEV Community

Cover image for Creating a Twitter Bot with Phoenix
Kevin Expósito
Kevin Expósito

Posted on • Edited on

Creating a Twitter Bot with Phoenix

I started this blog in order to learn how to use Twitter API and also because i love going to the cinema 🙌. Im from Uruguay 🇺🇾, and here we have a cinema called "Movie Center". After checking their request, I started to investigate what we can get from them


Investigation 🕵️

After checking their request I found out that I can use that information for the Twitter bot.

Image description

Image description

Image description

Image description


Creating the app 👨‍💻

Let’s start by creating our Phoenix app

mix phx.new movies_uy
cd movies_uy
mix ecto.create

iex -S mix phx.server
Enter fullscreen mode Exit fullscreen mode

Now Im going to add the following dependencies that are needed for the bot:

# mix.exs
defp deps do
  [
     {:finch, "~> 0.13"},
     {:oauther, "~> 1.1"},
     {:extwitter, "~> 0.12"},
     {:oban, "~> 2.13"}
  ]
end
Enter fullscreen mode Exit fullscreen mode
  • Finch for doing request to the "Movie Center" API.
  • ExTwitter it's a Twitter Client for using Twitter API
  • Oban for creating jobs that run whenever we want (in our case once a day)

After adding this don't forget to run mix deps.get.


Config Finch

Let’s configure Finch by adding this, note that you can follow this from the Finch repo too.

# lib/movies_uy/application.ex
def start(_type, _args) do
  children = [
    ...
    {Finch, name: MoviesUyFinch}
  ]
end
Enter fullscreen mode Exit fullscreen mode


Config ExTwitter 🧵

# config/config.exs
config :extwitter, :oauth, [
  consumer_key: System.get_env("TWITTER_CONSUMER_KEY"),
  consumer_secret: System.get_env("TWITTER_CONSUMER_SECRET"),
  access_token: System.get_env("TWITTER_ACCESS_TOKEN"),
  access_token_secret: System.get_env("TWITTER_ACCESS_TOKEN_SECRET")
]
Enter fullscreen mode Exit fullscreen mode

Getting Movies 🎬

Let's add the following code that will search for all the movies from the Movie Center API.

# lib/movies_uy/movie_center.ex
defmodule MoviesUy.MovieCenter do
  require Logger

  def fetch_movies do
    movie_url = "https://api.movie.com.uy/api/billboard/cinema/weekly?nextReleases=false"

    request = Finch.build(:get, movie_url) |> Finch.request(MoviesUyFinch)

    with {:ok, %Finch.Response{body: data}} <- request,
     %{"items" => movies} <- Jason.decode!(data) do

      movies
      |> Enum.map(fn %{"content" => %{"title" => title, "id" => id, "urlSlug" => slug}}} ->

        "#{title} - https://www.movie.com.uy/movie/#{id}/#{slug}"
      end)

    else
      _ ->
        Logger.error "Error!"
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

You can also check if this is working correctly by running the following line on your iex

$ iex> MoviesUy.MovieCenter.fetch_movies # this should show all the movies from Movie center API

Using ExTwitter 🧵

Now is time to build the messages and post them on Twitter using ExTwitter.

What Im going to do is create a tweet that contains the current date, and the comments of this twitter will be the movies with their current url on Movie Center.

# lib/movies_uy/movie_center.ex
defmodule MoviesUy.MovieCenter do
  require Logger

  def fetch_movies do
    movie_url = "https://api.movie.com.uy/api/billboard/cinema/weekly?nextReleases=false"

    request = Finch.build(:get, movie_url) |> Finch.request(MoviesUyFinch)

    with {:ok, %Finch.Response{body: data}} <- request,
         %{"items" => movies} <- Jason.decode!(data),
         %ExTwitter.Model.Tweet{id: tweet_id} <- post_message()
    do
      movies
      |> Enum.map(&post_thread_message(&1, tweet_id))
    else
      error ->
        Logger.error error
    end
  end

  defp post_thread_message(%{"content" => %{"title" => title, "id" => id, "urlSlug" => slug}}, tweet_id) do
    "#{title} - https://www.movie.com.uy/movie/#{id}/#{slug}"
    |> ExTwitter.update(in_reply_to_status_id: tweet_id)
  end

  defp post_message do
    %Date{day: day, month: month, year: year} = Date.utc_today

    "Cartelera de Movie Center del #{day}/#{month}/#{year}"
    |> ExTwitter.update
  end
end
Enter fullscreen mode Exit fullscreen mode

We can run this using the same function as before and we should be able to see that is posting correctly on Twitter.

Image description


Config Oban 📅

It’s time to use Oban, this will allow us to create a worker that runs our code whenever we want, in our case once a day! Lets config Oban (you can also read the docs).

$ mix ecto.gen.migration add_oban_jobs_table
Enter fullscreen mode Exit fullscreen mode

Then open the generated migration and update it:

defmodule MoviesUy.Repo.Migrations.AddObanJobsTable do
  use Ecto.Migration

  def up do
    Oban.Migrations.up(version: 11)
  end

  # We specify `version: 1` in `down`, ensuring that we'll roll all the way back down if
  # necessary, regardless of which version we've migrated `up` to.
  def down do
    Oban.Migrations.down(version: 1)
  end
end
Enter fullscreen mode Exit fullscreen mode

And finally lets run this

$ mix ecto.migrate
Enter fullscreen mode Exit fullscreen mode

Lets add this

#config/config.exs
config :movies_uy, Oban,
  repo: MoviesUy.Repo,
  plugins: [
    Oban.Plugins.Pruner,
    {Oban.Plugins.Cron,
      crontab: [
        {"@daily", MoviesUy.DailyWorker, max_attempts: 1},
      ]}
  ],
  queues: [default: 10]
Enter fullscreen mode Exit fullscreen mode
# lib/my_app/application.ex
def start(_type, _args) do
  children = [
    ...
    {Oban, Application.fetch_env!(:movies_uy, Oban)}
  ]
end
Enter fullscreen mode Exit fullscreen mode
# lib/movies_uy/workers/daily_worker.ex
defmodule MoviesUy.DailyWorker do
  use Oban.Worker, queue: :default

  @impl Oban.Worker
  def perform(_) do
    MoviesUy.MovieCenter.fetch_movies()
  end
end
Enter fullscreen mode Exit fullscreen mode

Thats it! you can see this Twitter bot working visiting: https://twitter.com/movies_uy

Note: you can also create just a mix app and this guide will work too. I used phx because Im planning to do another thing in the future with it


Things we used here:


Visit the bot:

Twitter bot: https://twitter.com/movies_uy

The code:

https://github.com/kexposito/movies-uy

Top comments (0)