├── .formatter.exs ├── .gitignore ├── .travis.yml ├── Procfile ├── README.md ├── config ├── .credo.exs ├── config.exs ├── dev.exs ├── prod.exs └── test.exs ├── elixir_buildpack.config ├── lib ├── minimal_server.ex └── minimal_server │ ├── application.ex │ ├── endpoint.ex │ └── router.ex ├── mix.exs ├── mix.lock ├── scripts └── lint.sh └── test ├── minimal_server_test.exs └── test_helper.exs /.formatter.exs: -------------------------------------------------------------------------------- 1 | [ 2 | inputs: [ 3 | "{mix,.formatter}.exs", 4 | "{config,lib,test}/**/*.{ex,exs}" 5 | ] 6 | ] 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where 3rd-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | minimal_server-*.tar 24 | 25 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: elixir 2 | elixir: 1.7 3 | otp_release: 21.0 4 | sudo: false 5 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: mix run --no-halt 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # elixir-http-json-api 2 | 3 | [](https://travis-ci.org/KamilLelonek/elixir-http-json-api) 4 | 5 | The purpose of this repository is to provide the complete implementation for the following article: 6 | 7 | https://k.lelonek.me/elixir-http-server 8 | -------------------------------------------------------------------------------- /config/.credo.exs: -------------------------------------------------------------------------------- 1 | %{ 2 | configs: [ 3 | %{ 4 | name: "default", 5 | files: %{ 6 | included: ["lib/**", "test/**"], 7 | excluded: [] 8 | }, 9 | checks: [ 10 | {Credo.Check.Readability.MaxLineLength, false}, 11 | {Credo.Check.Readability.ModuleDoc, false}, 12 | {Credo.Check.Readability.AliasOrder, false} 13 | ] 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /config/config.exs: -------------------------------------------------------------------------------- 1 | use Mix.Config 2 | 3 | config :minimal_server, MinimalServer.Endpoint, port: 4000 4 | config :minimal_server, redirect_url: "http://localhost:4000/bot" 5 | 6 | import_config "#{Mix.env()}.exs" 7 | -------------------------------------------------------------------------------- /config/dev.exs: -------------------------------------------------------------------------------- 1 | use Mix.Config 2 | -------------------------------------------------------------------------------- /config/prod.exs: -------------------------------------------------------------------------------- 1 | use Mix.Config 2 | 3 | config :minimal_server, MinimalServer.Endpoint, 4 | port: String.to_integer(System.get_env("PORT") || "4444") 5 | 6 | config :minimal_server, redirect_url: System.get_env("REDIRECT_URL") 7 | -------------------------------------------------------------------------------- /config/test.exs: -------------------------------------------------------------------------------- 1 | use Mix.Config 2 | -------------------------------------------------------------------------------- /elixir_buildpack.config: -------------------------------------------------------------------------------- 1 | erlang_version=21.0 2 | elixir_version=1.7.2 3 | -------------------------------------------------------------------------------- /lib/minimal_server.ex: -------------------------------------------------------------------------------- 1 | defmodule MinimalServer do 2 | end 3 | -------------------------------------------------------------------------------- /lib/minimal_server/application.ex: -------------------------------------------------------------------------------- 1 | defmodule MinimalServer.Application do 2 | use Application 3 | 4 | alias MinimalServer.Endpoint 5 | 6 | def start(_type, _args), 7 | do: Supervisor.start_link(children(), opts()) 8 | 9 | defp children do 10 | [ 11 | Endpoint 12 | ] 13 | end 14 | 15 | defp opts do 16 | [ 17 | strategy: :one_for_one, 18 | name: MinimalServer.Supervisor 19 | ] 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/minimal_server/endpoint.ex: -------------------------------------------------------------------------------- 1 | defmodule MinimalServer.Endpoint do 2 | use Plug.Router 3 | use Plug.Debugger 4 | use Plug.ErrorHandler 5 | 6 | alias MinimalServer.Router 7 | alias Plug.{Adapters.Cowboy2, HTML} 8 | 9 | require Logger 10 | 11 | plug(Plug.Logger, log: :debug) 12 | plug(:match) 13 | 14 | plug(Plug.Parsers, 15 | parsers: [:json], 16 | pass: ["application/json"], 17 | json_decoder: Poison 18 | ) 19 | 20 | plug(:dispatch) 21 | 22 | def child_spec(opts) do 23 | %{ 24 | id: __MODULE__, 25 | start: {__MODULE__, :start_link, [opts]} 26 | } 27 | end 28 | 29 | def start_link(_opts) do 30 | with {:ok, [port: port] = config} <- config() do 31 | Logger.info("Starting server at http://localhost:#{port}/") 32 | Cowboy2.http(__MODULE__, [], config) 33 | end 34 | end 35 | 36 | forward("/bot", to: Router) 37 | 38 | match _ do 39 | conn 40 | |> put_resp_header("location", redirect_url()) 41 | |> put_resp_content_type("text/html") 42 | |> send_resp(302, redirect_body()) 43 | end 44 | 45 | defp redirect_body do 46 | ~S(
You are being redirected.)) 49 | end 50 | 51 | defp config, do: Application.fetch_env(:minimal_server, __MODULE__) 52 | defp redirect_url, do: Application.get_env(:minimal_server, :redirect_url) 53 | 54 | def handle_errors(%{status: status} = conn, %{kind: _kind, reason: _reason, stack: _stack}), 55 | do: send_resp(conn, status, "Something went wrong") 56 | end 57 | -------------------------------------------------------------------------------- /lib/minimal_server/router.ex: -------------------------------------------------------------------------------- 1 | defmodule MinimalServer.Router do 2 | use Plug.Router 3 | 4 | plug(:match) 5 | plug(:dispatch) 6 | 7 | @content_type "application/json" 8 | 9 | get "/" do 10 | conn 11 | |> put_resp_content_type(@content_type) 12 | |> send_resp(200, message()) 13 | end 14 | 15 | match _ do 16 | send_resp(conn, 404, "Requested page not found!") 17 | end 18 | 19 | defp message do 20 | Poison.encode!(%{ 21 | response_type: "in_channel", 22 | text: "Hello from BOT :)" 23 | }) 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /mix.exs: -------------------------------------------------------------------------------- 1 | defmodule MinimalServer.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :minimal_server, 7 | version: "0.1.0", 8 | elixir: "~> 1.7", 9 | start_permanent: Mix.env() == :prod, 10 | deps: deps() 11 | ] 12 | end 13 | 14 | def application do 15 | [ 16 | extra_applications: [:logger], 17 | mod: {MinimalServer.Application, []} 18 | ] 19 | end 20 | 21 | defp deps do 22 | [ 23 | {:poison, "~> 3.0"}, 24 | {:plug, "~> 1.6"}, 25 | {:cowboy, "~> 2.4"}, 26 | {:credo, "~> 0.10", except: :prod, runtime: false} 27 | ] 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /mix.lock: -------------------------------------------------------------------------------- 1 | %{ 2 | "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm"}, 3 | "cowboy": {:hex, :cowboy, "2.4.0", "f1b72fabe9c8a5fc64ac5ac85fb65474d64733d1df52a26fad5d4ba3d9f70a9f", [:rebar3], [{:cowlib, "~> 2.3.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.5.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"}, 4 | "cowlib": {:hex, :cowlib, "2.3.0", "bbd58ef537904e4f7c1dd62e6aa8bc831c8183ce4efa9bd1150164fe15be4caa", [:rebar3], [], "hexpm"}, 5 | "credo": {:hex, :credo, "0.10.0", "66234a95effaf9067edb19fc5d0cd5c6b461ad841baac42467afed96c78e5e9e", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"}, 6 | "jason": {:hex, :jason, "1.1.1", "d3ccb840dfb06f2f90a6d335b536dd074db748b3e7f5b11ab61d239506585eb2", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, 7 | "mime": {:hex, :mime, "1.3.0", "5e8d45a39e95c650900d03f897fbf99ae04f60ab1daa4a34c7a20a5151b7a5fe", [:mix], [], "hexpm"}, 8 | "plug": {:hex, :plug, "1.6.3", "43088304337b9e8b8bd22a0383ca2f633519697e4c11889285538148f42cbc5e", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}], "hexpm"}, 9 | "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"}, 10 | "ranch": {:hex, :ranch, "1.5.0", "f04166f456790fee2ac1aa05a02745cc75783c2bfb26d39faf6aefc9a3d3a58a", [:rebar3], [], "hexpm"}, 11 | } 12 | -------------------------------------------------------------------------------- /scripts/lint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | mix credo --strict 5 | mix format --check-formatted 6 | -------------------------------------------------------------------------------- /test/minimal_server_test.exs: -------------------------------------------------------------------------------- 1 | defmodule MinimalServerTest do 2 | use ExUnit.Case 3 | end 4 | -------------------------------------------------------------------------------- /test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | --------------------------------------------------------------------------------