How to build an Elixir chat app with Phoenix

Phoenix Framework

I recently started worked on Phoenix, an Elixir Web Framework targeting full-featured, fault tolerant applications with realtime functionality.

Here we interactively build an Elixir chat application from scratch using Phoenix’s new Websocket layer that landed in 0.2.2.

The realtime layer supports channel/topic pubsubbing, multiplexing, and ships with a javascript layer for easy client integration. The PubSub layer is based on pg2, allowing Phoenix channels to be run distributively across your entire cluster. Fault tolerance is achieved through automatic node failover.

Demo Application: phoenixchat.herokuapp.com

Example Usage

Elixir - Phoenix Router / Channel

1
                  2
                  3
                  4
                  5
                  6
                  7
                  8
                  9
                  10
                  11
                  12
                  13
                  14
                  15
                  16
                  17
                  18
                  19
                  20
                  21
                  22
                  23
                  24
                  25
                  26
              
defmodule Chat.Router do
                      use Phoenix.Router
                      use Phoenix.Router.Socket, mount: "/ws"
                    
                      plug Plug.Static, at: "/static", from: :chat
                      get "/", Chat.Controllers.Pages, :index, as: :page
                    
                      channel "rooms", Chat.Channels.Rooms
                    end
                    
                    defmodule Chat.Channels.Rooms do
                      use Phoenix.Channel
                    
                      def join(socket, "lobby", message) do
                        IO.puts "JOIN #{socket.channel}:#{socket.topic}"
                        broadcast socket, "user:entered", username: message["username"]
                        {:ok, socket}
                      end
                    
                      def event("new:message", socket, message) do
                        broadcast socket, "new:message", content: message["content"],
                                                         username: messages["username"]
                    
                        socket
                      end
                    end
      

JavaScript

1
                  2
                  3
                  4
                  5
                  6
                  7
                  8
                  9
                  10
                  11
                  12
                  13
                  14
                  15
                  16
                  17
                  18
                  19
                  20
                  21
                  22
                  23
                  24
                  25
              
var socket = new Phoenix.Socket("ws://" + location.host + "/ws");
                    var $messages = $("#messages");
                    var $messageInput = $("#message-input");
                    var $usernameInput = $("#username");
                    
                    socket.join("rooms", "lobby", {}, function(chan){
                    
                      chan.on("user:entered", function(message){
                        $messages.append("<br/>[" + message.username + "] entered")
                      });
                    
                      chan.on("new:message", function(msg){
                        $messages.append("<br/>[" + msg.username + "] " + msg.content)
                      });
                    
                      $messageInput.off("keypress").on("keypress", function(e){
                        if(e.keyCode == 13){
                          chan.send("new:message", {
                            content: $messageInput.val(),
                            username: $usernameInput.val()
                          });
                          $messageInput.val("");
                        }
                      });
                    });
      

Markup

1
                  2
                  3
              
<div id="messages"></div>
                    @<input id="username" type="text">
                    :<input id="message-input" type="text">
      

Comments