DEV Community

vKxni
vKxni

Posted on

2

REST APi in Phoenix

Ever wondered how to write a small REST APi for your frontend or for public usage? - here is how.

Requirements:

  • Elixir v13.3.2 +
  • Phoenix v1.6.10+
  • Basic Knowledge of Elixir
$ elixir -v
Elixir 1.13.2 (compiled with Erlang/OTP 24)

$ mix phx.new --version
Phoenix installer v1.6.10
Enter fullscreen mode Exit fullscreen mode

Getting started

Lets start with creating our Project with the following command

$ mix phx.new myApp --no-html --no-assets --no-mailer --no-dashboard --no-ecto 
Enter fullscreen mode Exit fullscreen mode

This will remove all the useless boilerplate for us - since APis do not need any HTML or CSS.

Now lets path into your folder:

$ cd myApp
Enter fullscreen mode Exit fullscreen mode

Lets open our router first lib/myapp_web/router.ex, there, add the following code
get "/random", RandomController, :index

Your Router should now look like this:

defmodule MyAppWeb.Router do
  use MyAppWeb, :router

  pipeline :api do
    plug :accepts, ["json"]
  end

  # localhost:4000/api/{route}
  scope "/api", MyAppWeb do
    pipe_through :api

    get "/random", RandomController, :index
  end
end
Enter fullscreen mode Exit fullscreen mode

Custom Controller

As defined in the router, we now need a Controller called RandomController.
For that, open the folder controllers (lib/myapp_web/controllers) and create a new file called random_controller.ex.

defmodule MyAppWeb.RandomController do
  use MyAppWeb, :controller

  def index(conn, _params) do
    send_resp(conn, 200, "hello world")
  end
end
Enter fullscreen mode Exit fullscreen mode

Save this file and now try to start your server.

$ mix phx.server
Enter fullscreen mode Exit fullscreen mode

Your server should be listening on http://localhost:4000/api/random. Try to enter that URL in your favourite browser. Your should now see "hello world" 😁.

Custom Files

It's not a good practice to write functions directly into your controller - specially in a bigger project - so lets write a helper function that handles everything for us.

Create a folder called helper with the following path: lib/myapp/helper.

Since this isn't web related, we will now use our main folder (not the myapp_web one).

In that folder, create a file called random.ex.

It should look like this:

defmodule MyApp.Random do
  def random_number do
   Enum.random(100..10000)
  end
end
Enter fullscreen mode Exit fullscreen mode

Awesome, now lets go back to our random_controller.ex and modify it a little bit.

First of all, import our new helper file with its function.

import MyApp.Random

Then replace our "hello world" response with the function name random_number().

Like this:
send_resp(conn, 200, random_number()).

Your random_controller.ex should now look like this

defmodule MyAppWeb.RandomController do
  use MyAppWeb, :controller

  import MyApp.Random

  def index(conn, _params) do
    send_resp(conn, 200, random_number())
  end
end
Enter fullscreen mode Exit fullscreen mode

Save the file and restart your server

$ mix phx.server
Enter fullscreen mode Exit fullscreen mode

Go to the following URL: http://localhost:4000/api/random, you should now see a random number every time you refresh/enter the page. 🎉

Handling CORS

This is a more in-depth topic - but it's necessary if you want other people to use your API or even call your own APi from another port/ip.

We will use a library called corsica for this, lets install it by opening our mix.exs file in the root directory.

Add the following line into your deps function

{:corsica, "~> 1.2"}
Enter fullscreen mode Exit fullscreen mode

Your mix.exs should now look like this

defmodule MyApp.MixProject do
  use Mix.Project

  def project do
    [
      app: :myapp,
      version: "0.1.0",
      elixir: "~> 1.13",
      description: "An example Web APi",
      elixirc_paths: elixirc_paths(Mix.env()),
      compilers: Mix.compilers(),
      start_permanent: Mix.env() == :prod,
      aliases: aliases(),
      deps: deps(),
      author: "github.com/vKxni",
      docs: [
        main: "readme",
        extras: [
          "README.md"
        ]
      ]
    ]
  end

  def application do
    [
      mod: {MyApp.Application, []},
      extra_applications: [:logger, :runtime_tools]
    ]
  end

  defp elixirc_paths(:test), do: ["lib", "test/support"]
  defp elixirc_paths(_), do: ["lib"]

  # Here !! :)
  defp deps do
    [
      # phoenix server
      {:phoenix, "~> 1.6.10"},
      {:telemetry_metrics, "~> 0.6"},
      {:telemetry_poller, "~> 1.0"},
      {:gettext, "~> 0.18"},
      {:plug_cowboy, "~> 2.5"},
      {:poison, "~> 5.0"},
      {:jason, "~> 1.3"},

      # add this line here
      {:corsica, "~> 1.2"} # <--
    ]
  end

  defp aliases do
    [
      setup: ["deps.get"]
    ]
  end
end
Enter fullscreen mode Exit fullscreen mode

Once done, run the following command

$ mix deps.get
Enter fullscreen mode Exit fullscreen mode

This might take some time depending on your connection.

Adding CORS to our Endpoint

Open the file called endpoint.exs in your myapp_web folder.
(lib/myapp_web/endpoint.exs)

Now in your Endpoint, add the following lines

 plug(Corsica,
    max_age: 600,
    origins: "*",
    allow_headers: ["accept", "content-type", "authorization"],
    allow_methods: ["GET", "POST"],
    allow_credentials: true,
    log: [rejected: :error, invalid: :warn, accepted: :debug]
  )
Enter fullscreen mode Exit fullscreen mode

Your endpoint.exs should now look like this:

defmodule MyAppWeb.Endpoint do
  use Phoenix.Endpoint, otp_app: :xadara

  @session_options [
    store: :cookie,
    key: "_myapp_key",
    signing_salt: "g10HT1jr"
  ]

  # our CORS config starts here
  plug(Corsica,
    max_age: 600,
    origins: "*",
    allow_headers: ["accept", "content-type", "authorization"],
    allow_methods: ["GET", "POST"],
    allow_credentials: true,
    log: [rejected: :error, invalid: :warn, accepted: :debug]
  )
  # CORS ends here

  plug Plug.Static,
    at: "/",
    from: :myapp,
    gzip: false,
    only: ~w(assets fonts images favicon.ico robots.txt)

  if code_reloading? do
    plug Phoenix.CodeReloader
  end

  plug Plug.RequestId
  plug Plug.Telemetry, event_prefix: [:phoenix, :endpoint]

  plug Plug.Parsers,
    parsers: [:urlencoded, :multipart, :json],
    pass: ["*/*"],
    json_decoder: Phoenix.json_library()

  plug Plug.MethodOverride
  plug Plug.Head
  plug Plug.Session, @session_options
  plug MyAppWeb.Router # this here is important too
end
Enter fullscreen mode Exit fullscreen mode

If something looks a bit different, don't worry, just add the new PLUG right below the session_options.

And you are done! Congratulations.

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

Top comments (0)

Billboard image

Try REST API Generation for Snowflake

DevOps for Private APIs. Automate the building, securing, and documenting of internal/private REST APIs with built-in enterprise security on bare-metal, VMs, or containers.

  • Auto-generated live APIs mapped from Snowflake database schema
  • Interactive Swagger API documentation
  • Scripting engine to customize your API
  • Built-in role-based access control

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay