DEV Community

Marcio Lopes de Faria
Marcio Lopes de Faria

Posted on

A very simple scriptable Elixir server with tests

Sometimes I miss the old days of Sinatra. It was so simple to build a really simple server, that we can do it in less than ten lines into two files, the Gemfile and the server.rb file.

We need to work a little more than expected with Elixir, but it's doable, and with a plus, it's not hard to bake tests inside your script.

Thanks to Mix.install/2 that is available since Elixir v1.12.0, its possible even to make it in one single file. Just place the snippet bellow in a single file, for example, server.exs

# Place this content on server.exs file

Mix.install([
  {:plug_cowboy, "~> 2.0"}
])

defmodule Server do
  use Plug.Router
  plug(:match)
  plug(:dispatch)

  get "/hello-world" do
    send_resp(conn, 200, "Hello World!")
  end

  match _ do
    send_resp(conn, 404, "Nothing to see here")
  end
end

ExUnit.start(autorun: false)

defmodule ServerTest do
  use ExUnit.Case, async: true
  use Plug.Test

  @opts Server.init([])

  test "returns hello world" do
    # Create a test connection
    conn = conn(:get, "/hello-world")

    # Invoke the plug
    conn = Server.call(conn, @opts)

    # Assert the response and status
    assert conn.state == :sent
    assert conn.status == 200
    assert conn.resp_body == "Hello World!"
  end

  test "returns 404 to any another route" do
    for path <- ["/foo", "/bar"] do
      conn = conn(:get, path)
      conn = Server.call(conn, @opts)

      assert conn.state == :sent
      assert conn.status == 404
      assert conn.resp_body == "Nothing to see here"
    end
  end
end

case ExUnit.run() do
  %{failures: 0} ->
    Plug.Cowboy.http(Server, [], port: 4000)
    System.no_halt(true)

  _ ->
    :error
end
Enter fullscreen mode Exit fullscreen mode

And now just call in your shell:

elixir server.exs
Enter fullscreen mode Exit fullscreen mode

Visit your browser at http://localhost:4000/hello-world to see the result.

This is another small and interesting tip to the mix of useful things that we can do with Elixir.

Happy Hacking Folks!

Top comments (11)

Collapse
 
standelethan profile image
Ethan Standel

As far as simple single code file servers go, I really don't think it gets more basic than Express tbh 🤷‍♂️

Collapse
 
kelvinst profile image
Kelvin Stinghen

Well, in Elixir's defense, please note this script includes the server AND the tests for it, the server per se could be done just with:

Mix.install([{:plug_cowboy, "~> 2.0"}])

defmodule Server do
  use Plug.Router
  plug(:match)
  plug(:dispatch)

  get "/hello-world" do
    send_resp(conn, 200, "Hello World!")
  end

  match _ do
    send_resp(conn, 404, "Nothing to see here")
  end
end

Plug.Cowboy.http(Server, [], port: 4000)
System.no_halt(true)
Enter fullscreen mode Exit fullscreen mode

Also, this is a totally standalone script, it does not require ANYTHING else besides you having Elixir installed and calling elixir server.exs, as the dependencies are downloaded for you with the function Mix.install on the beginning of the file, so you could totally just download that script and run it. While with express, AFAIR you need to install express too, which either involves a npm -g express (that might lead to problems with different express versions) or having a folder structure and a package.json, which is not that simple TBH.

Collapse
 
standelethan profile image
Ethan Standel

Definitely good points! I suppose my suggestion would have to include something unsavory like exec("npm I express@latest -g") to truly get it into a true single file that you can run with just Node installed which just... yeah, yuck.

I guess I could make that point that Deno has this functionality built in if I wanted to be that kind of JS/TS fanboy but then we're out of the "simplistic" and well documented context.

For the record, I dig Elixir + Phoenix. I'm not a Node dev strictly (though it's what clients have most commonly been asking for, in my experience), I just think it's the defacto for most simple tooling.

Thread Thread
 
kelvinst profile image
Kelvin Stinghen

Yeah, deno is a nice project, hopefully it gets traction as it solves a lot of the problems node has. But I'm sticking with Elixir either way. 😄

Your comment got me thinking though: is this something we want? I mean, is there a valid use case for a very simple server like this? Cause if there is, maybe there is room for another library on top of plug that would make all this simpler. Maybe even improved tooling around single-file scripts servers IDK 🤔

Thread Thread
 
standelethan profile image
Ethan Standel

I think there's a use-case for incredibly simple tooling. I mean... the Docker build for deploying this server to production just has to have Elixir installed and that's pretty cool!

Collapse
 
neophen profile image
Mykolas Mankevicius

Nodejs is not very industry pervasive... Php is 70% of the internet. You might think nodejs is pervasive because the majority of loud people use. But they realy make up a very small minority of the internet. What you see is not all there is. And coming here on a Elixir post and telling a person to mention something is such a childish move.
nibblestew.blogspot.com/2017/04/wh...

Collapse
 
standelethan profile image
Ethan Standel

I ended up on this thread because of a Google News link to a previous title or a generated title that just said something along the lines of "A simple scriptable server." When I saw it was Elixir, I just felt like "oh that just doesn't seem like the simplest way to define a server in a single code file." It also references missing older technologies in Ruby so it appeared that the topic of other languages were on the table.

Also, I think the more relevant numbers are what percentage of jobs are using what at the moment. Or you can look at the Github developer survey where JavaScript has been the most popular language since 2014. Even if that's not all Node, it's still a nod to the accessibility of that language to developers. So on the topic of simplicity, I felt it was relevant.

Also I think that "70% of the internet is PHP" myth is partially out of date and partially driven up by CMS services which use it in the backend like WordPress.

Thread Thread
 
marciol profile image
Marcio Lopes de Faria

Yes, it's really interesting to discuss the missing points of our day to day tools and it's why I brough Ruby, a technology that I'm very familiar and linked it with Elixir because just happened to be my current history of transitioning from Ruby to Elixir, a path walked by a lot of people, so I think that the subject reasonates better to people with this background. Despite that, Elixir is niche in the industry and even Ruby is kind of niche, even after so many years with big companies using it, when compared to PHP, and also NodeJS.

Collapse
 
marciol profile image
Marcio Lopes de Faria

Yes sure, but anyways, Nodejs is not my tool of preference, never was.

Collapse
 
standelethan profile image
Ethan Standel

That's fair but it's incredibly industry pervasive these days. But I mean obviously Elixir has a performance advantage, but if you're going with "as simple as possible," I think the most common tool is worth talking about.

Thread Thread
 
marciol profile image
Marcio Lopes de Faria • Edited

Absolutely, and seems that there is a lot of examples of how to make a good usage of the most common tool on the internet, but interestingly I just find few showing how to setup a simple server in Elixir. This is the beauty of internet, there is space to every subject that can satisfy every audience.