README.md

## 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