## FlEx
FlEx it's a micro-framework for backend inspired by the simplicity of Flask and the complication to use Phoenix in very
small applications
One of the cores of this micro-framework it's be flexible, you can define your whole app in a single file or split in a
lot of more files, basic rules, nothing to be followed
This project doesn't pretend to replace Phoenix, the opposite we LOVE Phoenix and we're taking a lot of inspiration on
the use and implementation of Phoenix, but sometimes a lot of stuff it's too overkill for some very small servers and
more when you want to create a very small service
The design it's based on [Plug](https://hexdocs.pm/plug/https.html) so it's FULLY COMPATIBLE WITH ALL THE PLUGS! and you
can create your own plugs in the same format and the same way to use, 100% compatibility
Also includes some useful plugs to create/configure your server quickly
## Installation
If [available in Hex](https://hex.pm/packages/fl_ex), the package can be installed
by adding `fl_ex` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:fl_ex, "~> 0.1.0"}
]
end
```
## The example
This project includes a complete implementation example (server, routers, testing), just check the folder
[fl_ex_example](./fl_ex_example)
## Basic Usage
> IMPORTANT! this implementation comes from the point from a empty project, if you have some of the files mentioned
> just follow the line that says: `add to your file`
First you need create a module that will be your server
```elixir
defmodule MyApp.Server do
use FlEx.Server, otp_app: :my_app
plug Plug.Head
plug Plug.RequestId
plug Plug.Logger, log: :debug
plug FlEx.Plug.Accepts, ["json"]
plug MyApp.Plugs.Auth
# define directly your route
get "/your_page/:param", &my_func/2
# also you can define a function from other module
get "/your_page/:param", MyApp.SomeOtherModule, :function_name
# or define a scope of routes
scope "/api/v1" do
# you can add your plugs that just will run on this scoped routes
plug MyApp.Plugs.Auth
get "/your_page", &my_func/2
get "/your_page", MyApp.SomeOtherModule, :function_name
# you can add exclusive plugs to just one route if you want
get "/your_page", MyApp.SomeOtherModule, :function_name, Plug.ExamplePlug, {Plug.OtherExamplePlug, [opts: 1]}
end
def my_func(conn, %{"param" => param} = _params) do
conn
|> FlEx.Renderer.status(200)
|> FlEx.Renderer.json(%{some_key: "value of param is #{param}"})
end
end
```
Then create your Application module, this must have the previous server added to the childer list
```elixir
defmodule MyApp.Application do
use Application, otp_app: :my_app
@impl true
def start(_type, _args) do
# List all child processes to be supervised
children = [
MyApp.Server # add to your file
]
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, opts)
end
end
```
Then add your Application module to your application list to start in your `mix.exs` file, in case that this isn't done
yet
```elixir
def application do
[
mod: {MyApp.Application, []},
extra_applications: [:logger]
]
end
```
With this you have the basic server working now and you can start using it
## Routes
The `FlEx.Server` allows to define routes and plugs directly, but what if you want to define your routes in other places
and just merge all the routes in the server, for this you need `FlEx.Router`
```elixir
defmodule MyApp.SomeRouter do
use FlEx.Router
plug :accepts, ["json"]
scope "/api/v1" do
get "/your_page", MyApp.SomeOtherModule, :function_name
end
end
```
and add to the server module the next line
```elixir
defmodule MyApp.Server do
use FlEx.Server, otp_app: :my_app
define_router MyApp.SomeRouter
end
```
## Configure
You can configure your server in the `config/config.exs` file
```elixir
import Config
config :fl_ex_example, FlEx.Server,
port: System.get_env("PORT"),
json_handler: Jason
```
| key | type | default | desc |
|---|---|---|---|
| port | :string | 4000 | server port |
| json_handler | Module | [Jason](https://github.com/michalmuskala/jason) | The module that partses string to map and viseversa |
## How to test
You can test your server using the module `FlEx.ConnTest` sharing with key `endpoint` your implemented server
```elixir
defmodule FlExExample.ServerTest do
use FlEx.ConnTest, endpoint: FlExExample.Server
setup %{conn: conn} do
{:ok, conn: put_req_header(conn, "accept", "application/json")}
end
test "should work /your_page/:param", %{conn: conn} do
conn = get(conn, "/your_page/some_value")
assert %{"some_key" => _} = json_response(conn, 200)
end
end
```
Or to test by "controllers" or routers, create your conn test module
```elixir
defmodule FlExExample.ConnTest do
defmacro __using__(_) do
quote do
use FlEx.ConnTest, endpoint: FlExExample.Server
setup %{conn: conn} do
{:ok, conn: put_req_header(conn, "accept", "application/json")}
end
end
end
end
```
and just implement the module directly in your test
```elixir
defmodule FlExExample.ServerTest do
use FlExExample.ConnTest
test "should work /your_page/:param", %{conn: conn} do
conn = get(conn, "/your_page/some_value")
assert %{"some_key" => _} = json_response(conn, 200)
end
end
```
## Roadmap
- [x] Working
- [ ] Live code changes
- [ ] Render
- [x] JSON
- [ ] HTML
- [x] Compatible with Plugs (100%)
- [x] Plugs for whole router
- [x] Plugs exclusive for `scope`
- [ ] `pipeline` to create plug flows and refeer to `scope` or route
- [x] Private plugs for specific routes
- [ ] Testing
- [x] Basic json testing
- [ ] More helpers
- [x] Server
- [x] Separated routers