Skip to content

Instantly share code, notes, and snippets.

@adamu
Last active June 10, 2023 18:02
Show Gist options
  • Select an option

  • Save adamu/a37bd88962cbd072b4505a98458edaff to your computer and use it in GitHub Desktop.

Select an option

Save adamu/a37bd88962cbd072b4505a98458edaff to your computer and use it in GitHub Desktop.

Revisions

  1. adamu revised this gist Dec 8, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion line_bot_elixir_howto_en.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    This is my entry for the [fukuoka.ex Elixir/Phoenix Advent Calendar 2019](https://qiita.com/advent-calendar/2019/fukuokaex), and it's a guide for how to write a Line bot using Elixir. 🧪🤖🧪
    This is my entry for the [fukuoka.ex Elixir/Phoenix Advent Calendar 2019](https://qiita.com/advent-calendar/2019/fukuokaex) day 13, and it's a guide for how to write a Line bot using Elixir. 🧪🤖🧪

    [日本語版はこちらです。](https://gist.github.com/adamu/6155478ca7a4791877e871907e618f0a)

  2. adamu revised this gist Dec 8, 2019. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions line_bot_elixir_howto_en.md
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,7 @@
    This is my entry for the [fukuoka.ex Elixir/Phoenix Advent Calendar 2019](https://qiita.com/advent-calendar/2019/fukuokaex), and it's a guide for how to write a Line bot using Elixir. 🧪🤖🧪

    [日本語版はこちらです。](https://gist.github.com/adamu/6155478ca7a4791877e871907e618f0a)

    1. First you need to create a **Messaging API Channel** on the [Line Developers Console](https://developers.line.biz). You will also need to add your bot as a friend, and know the generated *Channel ID* and *Channel Secret*.
    1. Create a new Elixir app with a supervision tree:

  3. adamu created this gist Dec 8, 2019.
    150 changes: 150 additions & 0 deletions line_bot_elixir_howto_en.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,150 @@
    This is my entry for the [fukuoka.ex Elixir/Phoenix Advent Calendar 2019](https://qiita.com/advent-calendar/2019/fukuokaex), and it's a guide for how to write a Line bot using Elixir. 🧪🤖🧪

    1. First you need to create a **Messaging API Channel** on the [Line Developers Console](https://developers.line.biz). You will also need to add your bot as a friend, and know the generated *Channel ID* and *Channel Secret*.
    1. Create a new Elixir app with a supervision tree:

    `mix new advent --sup`
    1. `cd advent`
    1. If you want to use git, now we can create a repository (optional):

    `git init && git add . && git commit -m 'Initial commit'`

    I will not talk anymore about git in this guide.
    1. Test the app works:
    ```
    $ iex -S mix
    Erlang/OTP 22 [erts-10.5] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [hipe]
    Interactive Elixir (1.9.2) - press Ctrl+C to exit (type h() ENTER for help)
    iex(1)> Advent.hello
    :world
    ```
    1. Add `line_bot` and related dependencies to `mix.exs`:
    ```elixir
    defp deps do
    [
    {:line_bot, "~> 0.1.0"},
    {:plug_cowboy, "~> 2.0"}
    ]
    end
    ```
    1. Fetch the `line_bot` package with `mix deps.get`.
    1. Define a config file in `config/config.exs`:
    ```elixir
    import Config
    config :line_bot,
    client_id: "YOUR_CLIENT_ID",
    client_secret: "YOUR_CLIENT_SECRET",
    # TODO remove this before deployment!
    skip_validation: true
    ```
    The `client_id` and `client_secret` are the Channel ID and Channel Secret are taken from the Line Developer Console.
    1. Check that our `:advent` and the `:line_bot` applications are started automatically.
    ```
    $ iex -S mix
    Erlang/OTP 22 [erts-10.5] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [hipe]
    Interactive Elixir (1.9.2) - press Ctrl+C to exit (type h() ENTER for help)
    iex(1)> Application.started_applications
    [
    {:advent, 'advent', '0.1.0'},
    {:line_bot, 'A package for creating chatbots with the Line messenger',
    '0.1.0'},
    ...
    ```
    1. So we can handle the incoming webhook request, define a Plug router in `lib/advent/router.ex`:
    ```elixir
    defmodule Advent.Router do
    use Plug.Router
    plug :match
    plug :dispatch
    forward "/bot", to: LineBot.Webhook, callback: Advent
    end
    ```
    1. And set our application to start it in `lib/advent/application.ex`:
    ```elixir
    children = [
    Plug.Cowboy.child_spec(scheme: :http, plug: Advent.Router, options: [port: 4000])
    ]
    ```
    1. Now start the application again with `iex -S mix`, and see if it responds to an example request:
    ```
    curl http://localhost:4000/bot
    ```
    The output should be something like:
    ```
    19:31:18.051 [warn] Skipping signature validation because :skip_validation is enabled.
    19:31:18.051 [debug] Webhook Request:
    ```
    Now we have a server that is running and receiving webhook events. Let's connect it to the internet.
    1. I like to use [ngrok](https://ngrok.com/) to give us a publicly accessible HTTPS proxy to our local environment. Install it and start it on port `4000`:
    ```
    $ ngrok http 4000
    ngrok by @inconshreveable (Ctrl+C to quit)
    Session Status online
    Account Adam Millerchip (Plan: Free)
    Version 2.3.35
    Region United States (us)
    Web Interface http://127.0.0.1:4040
    Forwarding http://xxxxxxxx.ngrok.io -> http://localhost:4000
    Forwarding https://xxxxxxxx.ngrok.io -> http://localhost:4000
    ```
    1. Take the URL generated by ngrok, and add `/bot`: `https://xxxxxxxx.ngrok.io/bot`, then set it as your bot's Webhook URL in the Line Developer Console.
    1. Now let's start to implement our bot code. Replace `lib/advent.ex` with this:
    ```elixir
    defmodule Advent do
    use LineBot
    end
    ```
    1. Now we should be able to check that our bot responds to events. In Line, open a chat window to your bot, and send it a message. You should see it arrive in the iex console. For example, if I send "Hello, bot!":

    `19:34:48.510 [debug] Webhook Request: {"events":[{"type":"message","replyToken":"xxxxxxxxx","source":{"userId":"U123456789abcdefghijllmnopqrstuvw","type":"user"},"timestamp":1575801287666,"message":{"type":"text","id":"0","text":"Hello, Bot!"}}],"destination":"Uyyyyyyyyyy"}`
    1. Let's modify our bot to reply to the message. We'll just echo the message:
    ```elixir
    defmodule Advent do
    use LineBot

    def handle_message(%{"type" => "text", "text" => message}, _info, reply_token) do
    reply = %LineBot.Message.Text{text: message}
    LineBot.send_reply(reply_token, reply)
    end
    end
    ```
    If all goes well, now our bot will repeat whatever is said to it.

    <img width="313" alt="image" src="https://user-images.githubusercontent.com/498229/70389044-91b1f280-19fd-11ea-9f7b-48b348ea01d0.png">

    1. You can also send messages directly from iex. You'll need to know your your personal Line `userId` for this bot. You can find it from an earlier Webhook Request log. Let's send ourselves the message "Hello from iex!":
    ```elixir
    iex> me = "U123456789abcdefghijllmnopqrstuvw"
    "U123456789abcdefghijllmnopqrstuvw"

    iex> message = %LineBot.Message.Text{text: "Hello from iex!"}
    %LineBot.Message.Text{quickReply: nil, text: "Hello from iex!", type: :text}

    iex> LineBot.send_push(me, message)
    19:55:02.919 [debug] API Response: %HTTPoison.Response{status_code: 200, request_url: "https://api.line.me/v2/bot/message/reply", ...}
    {:ok, %{}}
    ```
    Hopefully the message should arrive in your Line account.

    <img width="185" alt="image" src="https://user-images.githubusercontent.com/498229/70389056-aabaa380-19fd-11ea-888c-d52fc16f6cab.png">

    1. Sometimes it's convenient to send HTTP messages directly to our application for testing, but now that we have configured the Line server to send us messages, let's turn on signature validation to make sure our bot only responds to messages signed by Line, and refuses all others. In `config/config.exs`:
    ```
    import Config
    config :line_bot,
    client_id: "YOUR_CLIENT_ID",
    client_secret: "YOUR_CLIENT_SECRET",
    skip_validation: false
    ```

    And that's it! We made a simple line bot that can handle requests from the line server and send reply messages. We also demonstrated how to send messages directly from the command line while developing.

    You can see all the API commands you can use, and all the type of events that can be handled in the documentation for [`LineBot`](https://hexdocs.pm/line_bot/LineBot.html).

    There is also a fully functional sample app available. Why not copy the sample code from [`line_bot_sample.ex`](https://github.com/adamu/line_bot/blob/master/sample/lib/line_bot_sample.ex) to `lib/advent.ex` and see if you can get it running in your bot?

    <img width="310" alt="image" src="https://user-images.githubusercontent.com/498229/70389091-fd945b00-19fd-11ea-8eea-b9c63fdca2cf.png">