henrik

henrik

PlugAndPlay: Set up Plug apps with less boilerplate

I just made a small library to reduce boilerplate when making a new Plug app:

https://github.com/henrik/plug_and_play

I started rewriting a Sinatra app in Plug a while back and got a little frustrated by having to figure out a lot of boilerplate just to get a basic app running. So this is my way of maybe reducing that friction.

I’ve tried to keep it low on magic, and layered – you can have PlugAndPlay own the whole supervision tree, or provide your own with PlugAndPlay.Supervisor as a child.

It might be convenient to have something like this built into Plug itself. But I suspect Plug wants to be mostly low-level and leave these concerns to other libraries.

Would love feedback and thoughts. Try it out the next time you set up a Plug app!

Most Liked

henrik

henrik

Figured out why I got that error: it was simply that I tried running the same router twice on different ports, which does not work. I think Cowboy by default assumes it can refer uniquely to each one based on its module name.

When I specified two different routers, it worked fine. So now I’ve pushed that change:

I also introduced a child_spec to make things easier:

children = [
  PlugAndPlay.Supervisor.child_spec(HelloWorld.RouterOne, 1111),
  PlugAndPlay.Supervisor.child_spec(HelloWorld.RouterTwo, 2222),
]
jwarlander

jwarlander

I love the concept, and it looks like it could be a good fit for many apps. However, not being able to customize the port via regular application configuration unfortunately leaves it dead in the water for my purposes :pensive:

While we do, in some cases, use OS environment for configuration, we also like Conform, and having a nice little config file managed by Puppet. Even if that weren’t an issue, PORT seems to be a little too generic, and doesn’t scale beyond a single endpoint in the same application :wink: We often have a main application endpoint, then another endpoint for monitoring, listening on a different port and responding with metrics in JSON format.

Using application config for PlugAndPlay would still enable the OS environment scenario with a simple one-liner, and also enable any other convention within the Elixir / Erlang ecosystem.

I appreciate that this might be intended as a very simple scaffolding helper for a specific convention; in that case, please just ignore what I’m saying :smile:

jwarlander

jwarlander

Depends… the port: config would only be needed if you actually must configure the port that way, and since that kind of falls into the “custom requirements” category I’d say that an extra line of code isn’t too bad.

The regular use, if you’re happy with OS environment or the 8080 default port, would just be:

use PlugAndPlay.Application, router: HelloWorld.Router

The explicitness on the router specification feels a lot better to me at least.

Nice thing is the router + port options could be consistent in both PlugAndPlay.Application and PlugAndPlay.Supervisor, so if I had multiple endpoints, it would look like:

defmodule HelloWorld.Application do
  use Application
  import Supervisor.Spec

  def start(_type, _args) do
    children = [
      supervisor(PlugAndPlay.Supervisor, [HelloWorld.Web.Router, 8080]),
      supervisor(PlugAndPlay.Supervisor, [HelloWorld.Monitoring.Router, 8090]),
    ]

    Supervisor.start_link(children, strategy: :one_for_one)
  end
end
jwarlander

jwarlander

Hmm… interesting; with Phoenix, it “just works” when you define an extra Endpoint, so it’s probably doing something under the covers to make that play nice with Cowboy.

henrik

henrik

So I explored the pipeline thing. It’s definitely possible to do something like

use PlugAndPlay.Router do
  plug Foo
after
  plug Bar
end

or whatever, but it’s cryptic enough, and reduces boilerplate by such a small amount, that I would rather just state in the README that you shouldn’t use PlugAndPlay.Router if you want to customise the pipeline.

Where Next?

Popular in Libraries Top

hpopp
After just over two years in development, this latest version of Pigeon is what I finally consider done in regards to my original vision ...
New
tompave
Hello there, I would like to share a feature toggles library (AKA feature flags) I’ve been working on. The main package is FunWithFlags...
New
josevalim
EDIT: since Ecto 3.0 final version is out, this post was amended to use the final versions in the instructions below. Hi everyone, We a...
New
benlime
I created a new library GitHub - benvp/ex_cva: Class Variance Authority for Elixir which aims to make it very easy to define different va...
New
Qqwy
Hello everyone, I wrote a small library today called MapDiff. It returns a map listing the (smallest amount of) changes to get from map...
New
mbuhot
EctoJob A transactional job queue built with Ecto, PostgreSQL and GenStage Available on Hex.pm: ecto_job | Hex Docs: API Reference — ec...
New
wmnnd
Hi there, for my project DBLSQD, I needed a file storage solution that is a bit more flexible than Arc. Because I thought others might f...
New
maltoe
Hello! Came here to announce ChromicPDF, a pet project PDF generator I’ve been working on for the past few months. Why another PDF gener...
New
versilov
Could not wait for the missing Elixir ML libraries to appear, so, I wrote one myself, taking https://github.com/sdwolfz/exlearn as a foun...
New
bluzky
You may know https://ui.shadcn.com/, a UI component library for React. I really love it’s design style and components. I’ve built some co...
381 12391 119
New

Other popular topics Top

JDanielMartinez
Hi! May someone helps me, please! I have two apps into an umbrella project: the first one is Database, which manages queries, and the se...
New
peerreynders
Manning 2016 Halloween weekend sale via Deal of the Day Friday, October 28 - Half off all MEAPs - code WM102816LT Saturday, October 29 ...
326 29600 154
New
srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call th...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 49522 488
New
malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
magnetic
Hey :wave:t3: Elixir community, I’ve been learning Elixir, and working on some side projects. My editor of choice is VSCode, and althoug...
New

Sub Categories:

We're in Beta

About us Mission Statement