Personal note: Build Elixir CRUD without Phoenix using MySQL and MongoDB
Tags: elix, mysql, mongodb
Published: 2023-08-01 13:40:15

My personal note about learning Elixir.

Finding learning resources for Elixir is not as easy as JS learning resources. So I initiate this post to document my journey learning Elixir.

Basically I want to practice to create a create, read, list, update, and delete using MongoDB and MySQL.

Here, I will use Elixir without Phoenix framework, I want to know how Elixir work.

Make sure you have installed Elixir in your system.

To start a new project, use this command `mix new <app-name> --sup`

```
mix new todo_app --sup
```

A --sup option can be given to generate an OTP application skeleton including a supervision tree. Normally an app is generated without a supervisor and without the app callback.

After initialize new project, it will create directory structure like this.

![Dir structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5zzqsg4md7w4j5jhg4di.png)

You will see Elixir extension with `.ex` and `.exs`. The ".ex" extension is used for Elixir source code files that are compiled into bytecode, while the ".exs" extension is used for Elixir script files that are interpreted directly.

## Adding dependency

Go to `/mix.exs`, inside `deps` add the dependency.

```
 defp deps do
    [
      {:plug_cowboy, "~> 2.5"},
      {:jason, "~> 1.3"},
      {:mongodb_driver, "~> 0.8"},
      {:myxql, "~> 0.6.0"}
    ]
  end
```

After adding the dependency, run `mix deps.get`.

`plug_cowboy` is a kind of Erlang web server, since we didn't use any framework like Phoenix, we can use it.
`jason` is a JSON parser and generator for Elixir.
`mongo_driver` for establishing connection with MongoDB, and `myxql` for connecting with MySQL.

## Set up the dependency

After installing the dependencies, we need to set it up in our `application.ex`. 

According to Elixir site
> _Applications are the idiomatic way to package software in Erlang/OTP. To get the idea, they are similar to the "library" concept common in other programming languages, but with some additional characteristics._

> _An application is a component implementing some specific functionality, with a standardized directory structure, configuration, and life cycle. Applications are loaded, started, and stopped. Each application also has its own environment, which provides a unified API for configuring each application._

Here we will define the entry point of our app. Let's head to `lib/todo_app/application.ex`

```ex
# lib/todo_app/application.ex

defmodule TodoApp.Application do
alias Mix.Tasks.Compile.App

  use Application

  @impl true
  def start(_type, _args) do
    children = [
      {
        Plug.Cowboy,
        scheme: :http,
        plug: TodoApp.Router,
        options: [port: Application.get_env(:todo_app, :port)]
      },
      {
        Mongo,
        name: :mongo,
        url: Application.get_env(:todo_app, :database_url),
      },
      {
        MyXQL,
        name: :myxql,
        hostname: Application.get_env(:todo_app, :mysql_host),
        username: Application.get_env(:todo_app, :mysql_username),
        password: Application.get_env(:todo_app, :mysql_password),
        database: Application.get_env(:todo_app, :mysql_database),
      }
    ]

    opts = [strategy: :one_for_one, name: TodoApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
end
```

We can see that we have setup for Cowboy, Mongo, and MySQL inside the `application.ex`. We can also see there are `Application.get_env(:todo_app, :mysql_database)`, it means that we calling the value from an environment variable. Now let's define the env variable.

## Env Variable

Go to `config/`, create `config.exs` and `dev.env.exs`.

Put this value into `config.exs`

```
# config/config.exs

import Config

# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{config_env()}.env.exs"
```

The config file will import the code from `dev.env.exs`, if we use prod then we must have `prod.env.exs`.

In dev.env

```
# config/dev.env.exs

import Config

config :todo_app, port: 8081
config :todo_app, database_url: "mongodb://localhost:27017/sultanads"
config :todo_app, database: "db_demo"
config :todo_app, pool_size: 3
config :todo_app, :basic_auth, username: "abc", password: "abc"
config :todo_app, mysql_host: "localhost"
config :todo_app, mysql_username: "root"
config :todo_app, mysql_password: ""
config :todo_app, mysql_database: "dev_mdom"
```
Read more about config here https://hexdocs.pm/elixir/main/Config.html

Next, define the router.

## Router

Here in router, we will define the endpoint and add little CRUD logic.

https://github.com/burhanahmeed/elixir-mongodb-app/blob/master/lib/todo_app/router.ex

That's all, I can't explain much about it, but as a personal note it's enough for me to get started again one day.

Next, I will try with Phoenix, dockerize, and CI/CD.