Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elli with Elixir Basic usage issue

Tags:

elixir

I am using elli https://github.com/knutin/elli in my Elixir application.

The sample code is provided below. It is quite basic, every time it is run, I only get "Internal Server Error". I am not sure what I am doing wrong. Can any one please help ?

defmodule Client.TestHttp do
  @behaviour :elli_handler

  def handle(_Req,_Args) do
    handle(:elli_request.method(Req), :elli_request.path(Req),Args)
  end

  def handle_event(_,_,_)do
    :ok
  end

  def handle(:GET,[],_)do
    {:ok, [], "OkGet"}
  end
end

This is how I am executing

{:ok,pid}=:elli.start_link [callback: Client.TestHttp, port: 2020]
like image 557
Alpha Sierra Avatar asked Oct 21 '15 14:10

Alpha Sierra


3 Answers

It looks like you haven't fully translated the Erlang code from the example and are still using variables that begin with an uppercase letter.

Change handle to:

  def handle(req, args) do
    handle(:elli_request.method(req), :elli_request.path(req), args)
  end

Notice the difference in the variable names. In Elixir, variables are written in snake_case and modules in CamelCase. Using and underscore (_) such as _var in a match indicates that the variable is unused.

Your code would actually be expanding Req and Args to atoms due to module names in Elixir being atoms:

Req == :'Elixir.Req' # true
like image 160
Gazler Avatar answered Oct 04 '22 21:10

Gazler


In addition to the answers above, I would like to write up a complete guide on getting knutin/elli to work with Elixir. The above answers are correct, but I needed some more information to get up and running in my new elixir project.

  1. Implement a handler that has @behaviour :elli_handler

    This is your router/controller. A bare minimum example version of this looks like this:

    # lib/elli_handler.ex
    defmodule ElliHandler do
      @behaviour :elli_handler
      alias :elli_request, as: Request
    
      def handle(req, args) do
        handle(Request.method(req), Request.path(req), req, args)
      end
    
      def handle(:GET, _, req, args) do
        # do something with the request.
        # e.g. you can use Request.get_arg/2 to fetch a query param
        say = Request.get_arg("say", req)
        # Return a tuple with 3 elements
        # status code, list of header tuples, response body
        {200, [], "echo, #{say}"}
      end
    
      # Here you can react to all kinds of events of the full connection/request/response cycle
      # You must implement this, otherwise elli wont function properly, as it evaluates
      # the return value of handle_event/3.
      def handle_event(event, args, config) do
        # Here would be a good point to handle logging.
        # IO.inspect([event, args, config])
        :ok
      end
    
    end
    
  2. Lets use an app that starts an elli supervisor

    # lib/elli_supervisor.ex
    defmodule ElliSupervisor do
      use Supervisor
    
      def start_link(ref, options) do
        Supervisor.start_link(__MODULE__, options, name: ref)
      end
    
      def init(options) do
        children = [
          worker(:elli, [options], id: :elli_http_server)
        ]
        supervise(children, strategy: :one_for_one)
      end
    
      def shutdown(ref) do
        case Supervisor.terminate_child(ref, :elli_http_server) do
          :ok -> Supervisor.delete_child(ref, :elli_http_server)
          err -> err
        end
      end
    end
    
    # lib/app.ex
    defmodule App do
      use Application
    
      def start(_type, _args) do
        import Supervisor.Spec, warn: false
        # lets start our elli supervisor, setting its options
        # callback should be set to the elli handler that implements the elli_handler behaviour
        # port will be the port elli is listening on, defaults to 8080
        ElliSupervisor.start_link(__MODULE__, callback: ElliHandler, port: 3000)
      end
    
    end
    
    # in mix.exs
    def application do
      [
        mod: {App, []}
      ]
    end
    
  3. Add elli as a dependency to your mix.exs

    Run mix get.deps to install your dependencies. Start your server with mix run --no-halt or in a console using iex -S mix.

    # in mix.exs
    defp deps do
      [
        # elli is our web server layer
        {:elli, github: "knutin/elli"}
      ]
    end
    
like image 35
Overbryd Avatar answered Oct 04 '22 20:10

Overbryd


In addition to @Gazier's answer (which is correct, of course), your code also looks wrong in another way. In your original source you've got:

def handle(_Req,_Args) do
    handle(:elli_request.method(Req), :elli_request.path(Req),Args)
end

The parameter to the call to :elli_request.method would need to be _Req and the parameters to the :elli_request.path would also need to be _Req and _Args. If variables starting with an uppercase letter were correct (they're not) it would look like this:

 def handle(_Req,_Args) do
        handle(:elli_request.method(_Req), :elli_request.path(_Req),_Args)
    end

But as Gazier pointed out your variables are not correctly cased anyway.

like image 38
Onorio Catenacci Avatar answered Oct 04 '22 21:10

Onorio Catenacci