Initial commit.
This commit is contained in:
commit
005477d827
4
.formatter.exs
Normal file
4
.formatter.exs
Normal file
|
@ -0,0 +1,4 @@
|
|||
# Used by "mix format"
|
||||
[
|
||||
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
|
||||
]
|
26
.gitignore
vendored
Normal file
26
.gitignore
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
# The directory Mix will write compiled artifacts to.
|
||||
/_build/
|
||||
|
||||
# If you run "mix test --cover", coverage assets end up here.
|
||||
/cover/
|
||||
|
||||
# The directory Mix downloads your dependencies sources to.
|
||||
/deps/
|
||||
|
||||
# Where third-party dependencies like ExDoc output generated docs.
|
||||
/doc/
|
||||
|
||||
# Ignore .fetch files in case you like to edit your project deps locally.
|
||||
/.fetch
|
||||
|
||||
# If the VM crashes, it generates a dump, let's ignore it too.
|
||||
erl_crash.dump
|
||||
|
||||
# Also ignore archive artifacts (built via "mix archive.build").
|
||||
*.ez
|
||||
|
||||
# Ignore package tarball (built via "mix hex.build").
|
||||
swapi_example-*.tar
|
||||
|
||||
# Nix output
|
||||
/result
|
3
Dockerfile
Normal file
3
Dockerfile
Normal file
|
@ -0,0 +1,3 @@
|
|||
FROM alpine:latest
|
||||
ADD _build/prod/rel/swapi_example /
|
||||
CMD ["bin/swapi_example", "eval", "Application.ensure_all_started(:swapi_example); SwapiExample.run"]
|
44
README.md
Normal file
44
README.md
Normal file
|
@ -0,0 +1,44 @@
|
|||
# SwapiExample
|
||||
|
||||
A small example of using the [Star Wars API](https://swapi.dev/) to list all of
|
||||
the starships and their pilots that have appeared in the Star Wars film canon.
|
||||
|
||||
## Installation
|
||||
|
||||
### Nix (preferred)
|
||||
|
||||
```
|
||||
nix-shell # Downloads Docker and Elixir, and then starts a new shell with them in your path.
|
||||
export MIX_ENV=prod
|
||||
mix deps.get
|
||||
mix compile
|
||||
nix-build docker.nix # This step builds the release and puts it in an image.
|
||||
docker load <result
|
||||
docker run swapi_example:latest
|
||||
```
|
||||
|
||||
### Elixir
|
||||
|
||||
Run the following commands:
|
||||
|
||||
```
|
||||
export MIX_ENV=prod
|
||||
mix deps.get
|
||||
mix compile
|
||||
mix release
|
||||
_build/prod/rel/swapi_example/bin/swapi_example eval 'Application.ensure_all_started(:swapi_example); SwapiExample.run'
|
||||
```
|
||||
|
||||
### Docker
|
||||
|
||||
Run the following commands:
|
||||
|
||||
```
|
||||
export MIX_ENV=prod
|
||||
mix deps.get
|
||||
mix compile
|
||||
mix release
|
||||
docker build -t swapi_example:latest .
|
||||
docker run swapi_example:latest
|
||||
```
|
||||
|
3
config/config.exs
Normal file
3
config/config.exs
Normal file
|
@ -0,0 +1,3 @@
|
|||
import Config
|
||||
|
||||
config :tesla, adapter: Tesla.Adapter.Hackney
|
37
default.nix
Normal file
37
default.nix
Normal file
|
@ -0,0 +1,37 @@
|
|||
let
|
||||
pkgs = import <nixpkgs> {};
|
||||
elixir = pkgs.beam.packages.erlangR22.elixir_1_10;
|
||||
buildMix = pkgs.beam.packages.erlangR22.buildMix.override { inherit elixir; };
|
||||
in
|
||||
with pkgs;
|
||||
buildMix rec {
|
||||
name = "swapi_example";
|
||||
version = "0.1.0";
|
||||
src = nix-gitignore.gitignoreSourcePure [ "erl_crash.dump" "*.ez" "swapi_example-*.tar" ] ./.;
|
||||
|
||||
buildInputs = [
|
||||
elixir
|
||||
];
|
||||
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
|
||||
export HEX_OFFLINE=1
|
||||
export HEX_HOME=`pwd`
|
||||
export MIX_ENV=prod
|
||||
export MIX_NO_DEPS=1
|
||||
|
||||
mix compile --no-deps-check
|
||||
mix release --no-deps-check --overwrite
|
||||
|
||||
runHook postBuild
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
cp -Hr "_build/prod/rel/${name}" "$out"
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
}
|
22
docker.nix
Normal file
22
docker.nix
Normal file
|
@ -0,0 +1,22 @@
|
|||
let
|
||||
pkgs = import <nixpkgs> {};
|
||||
swapi_example = import ./default.nix;
|
||||
alpineLatest = pkgs.dockerTools.pullImage {
|
||||
imageName = "alpine";
|
||||
imageDigest = "sha256:3c7497bf0c7af93428242d6176e8f7905f2201d8fc5861f45be7a346b5f23436";
|
||||
sha256 = "0dqmvchn79n5lvb0gs28wacyfjixi0a5hgipgd0fpqbam6kq0bsi";
|
||||
finalImageName = "alpine";
|
||||
finalImageTag = "latest";
|
||||
};
|
||||
in
|
||||
pkgs.dockerTools.buildImage {
|
||||
name = "swapi_example";
|
||||
tag = "latest";
|
||||
fromImage = alpineLatest;
|
||||
|
||||
contents = swapi_example;
|
||||
|
||||
config = {
|
||||
Cmd = [ "/bin/swapi_example" "eval" "Application.ensure_all_started(:swapi_example); SwapiExample.run" ];
|
||||
};
|
||||
}
|
37
lib/swapi_example.ex
Normal file
37
lib/swapi_example.ex
Normal file
|
@ -0,0 +1,37 @@
|
|||
defmodule SwapiExample do
|
||||
@moduledoc """
|
||||
Lists all of the starships and their respective pilots from the Star Wars
|
||||
API.
|
||||
"""
|
||||
|
||||
alias SwapiExample.Client
|
||||
|
||||
@doc """
|
||||
The main entrypoint of the program.
|
||||
"""
|
||||
def run do
|
||||
IO.puts("Starship Model\t| Starship Name\t| Pilots")
|
||||
{:ok, resp} = Client.starships()
|
||||
|
||||
print_starships(resp)
|
||||
end
|
||||
|
||||
defp print_starships(resp) do
|
||||
starships = resp.body["results"]
|
||||
|
||||
for starship <- starships do
|
||||
pilots = for pilot_url <- starship["pilots"] do
|
||||
{:ok, resp} = Client.get(pilot_url)
|
||||
pilot = resp.body
|
||||
pilot["name"]
|
||||
end
|
||||
|
||||
IO.puts("#{starship["model"]}\t| #{starship["name"]}\t| " <> Enum.join(pilots, ", "))
|
||||
end
|
||||
|
||||
if resp.body["next"] do
|
||||
{:ok, next_resp} = Client.get(resp.body["next"])
|
||||
print_starships(next_resp)
|
||||
end
|
||||
end
|
||||
end
|
19
lib/swapi_example/client.ex
Normal file
19
lib/swapi_example/client.ex
Normal file
|
@ -0,0 +1,19 @@
|
|||
defmodule SwapiExample.Client do
|
||||
use Tesla
|
||||
|
||||
plug Tesla.Middleware.BaseUrl, "https://swapi.dev/api/"
|
||||
plug Tesla.Middleware.FollowRedirects
|
||||
plug Tesla.Middleware.JSON
|
||||
|
||||
def starships() do
|
||||
get("/starships/")
|
||||
end
|
||||
|
||||
def people() do
|
||||
get("/people/")
|
||||
end
|
||||
|
||||
def person(id) do
|
||||
get("/people/#{id}/")
|
||||
end
|
||||
end
|
29
mix.exs
Normal file
29
mix.exs
Normal file
|
@ -0,0 +1,29 @@
|
|||
defmodule SwapiExample.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
def project do
|
||||
[
|
||||
app: :swapi_example,
|
||||
version: "0.1.0",
|
||||
elixir: "~> 1.10",
|
||||
start_permanent: false, # This is effectively a script to run once.
|
||||
deps: deps()
|
||||
]
|
||||
end
|
||||
|
||||
# Run "mix help compile.app" to learn about applications.
|
||||
def application do
|
||||
[
|
||||
extra_applications: [:logger]
|
||||
]
|
||||
end
|
||||
|
||||
# Run "mix help deps" to learn about dependencies.
|
||||
defp deps do
|
||||
[
|
||||
{:tesla, "~> 1.4"},
|
||||
{:hackney, "~> 1.16.0"},
|
||||
{:jason, "~> 1.1"}
|
||||
]
|
||||
end
|
||||
end
|
16
mix.lock
Normal file
16
mix.lock
Normal file
|
@ -0,0 +1,16 @@
|
|||
%{
|
||||
"certifi": {:hex, :certifi, "2.5.2", "b7cfeae9d2ed395695dd8201c57a2d019c0c43ecaf8b8bcb9320b40d6662f340", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm", "3b3b5f36493004ac3455966991eaf6e768ce9884693d9968055aeeeb1e575040"},
|
||||
"hackney": {:hex, :hackney, "1.16.0", "5096ac8e823e3a441477b2d187e30dd3fff1a82991a806b2003845ce72ce2d84", [:rebar3], [{:certifi, "2.5.2", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.1", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.0", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.6", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "3bf0bebbd5d3092a3543b783bf065165fa5d3ad4b899b836810e513064134e18"},
|
||||
"httpoison": {:hex, :httpoison, "0.8.3", "b675a3fdc839a0b8d7a285c6b3747d6d596ae70b6ccb762233a990d7289ccae4", [:mix], [{:hackney, "~> 1.6.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "74f2103e6eff47dcc2b288e37f42629874df3e4a4dce5fbc9dea508de4785e06"},
|
||||
"idna": {:hex, :idna, "6.0.1", "1d038fb2e7668ce41fbf681d2c45902e52b3cb9e9c77b55334353b222c2ee50c", [:rebar3], [{:unicode_util_compat, "0.5.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a02c8a1c4fd601215bb0b0324c8a6986749f807ce35f25449ec9e69758708122"},
|
||||
"jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"},
|
||||
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
|
||||
"mime": {:hex, :mime, "1.5.0", "203ef35ef3389aae6d361918bf3f952fa17a09e8e43b5aa592b93eba05d0fb8d", [:mix], [], "hexpm", "55a94c0f552249fc1a3dd9cd2d3ab9de9d3c89b559c2bd01121f824834f24746"},
|
||||
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
|
||||
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"},
|
||||
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
|
||||
"swapi": {:hex, :swapi_elixir, "1.0.0", "d75c08823f67015e881294841f1dcaff3a319df47309eb72aef50d462c260d29", [:mix], [{:jason, ">= 1.1.2", [hex: :jason, repo: "hexpm", optional: false]}, {:tesla, "~> 1.0.0", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm", "41ea3d5eb341f6ca8cad943b074e378ba0cc128c92ef4aa6b9db4708941ad2f5"},
|
||||
"swapi_elixir": {:hex, :swapi_elixir, "1.0.0", "d75c08823f67015e881294841f1dcaff3a319df47309eb72aef50d462c260d29", [:mix], [{:jason, ">= 1.1.2", [hex: :jason, repo: "hexpm", optional: false]}, {:tesla, "~> 1.0.0", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm", "41ea3d5eb341f6ca8cad943b074e378ba0cc128c92ef4aa6b9db4708941ad2f5"},
|
||||
"tesla": {:hex, :tesla, "1.4.0", "1081bef0124b8bdec1c3d330bbe91956648fb008cf0d3950a369cda466a31a87", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.3", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "~> 4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "bf1374a5569f5fca8e641363b63f7347d680d91388880979a33bc12a6eb3e0aa"},
|
||||
"unicode_util_compat": {:hex, :unicode_util_compat, "0.5.0", "8516502659002cec19e244ebd90d312183064be95025a319a6c7e89f4bccd65b", [:rebar3], [], "hexpm", "d48d002e15f5cc105a696cf2f1bbb3fc72b4b770a184d8420c8db20da2674b38"},
|
||||
}
|
25
shell.nix
Normal file
25
shell.nix
Normal file
|
@ -0,0 +1,25 @@
|
|||
let
|
||||
pkgs = import <nixpkgs> {};
|
||||
elixir = pkgs.beam.packages.erlangR22.elixir_1_10;
|
||||
in
|
||||
with pkgs; mkShell {
|
||||
buildInputs = [
|
||||
docker
|
||||
elixir
|
||||
];
|
||||
|
||||
shellHook =
|
||||
''
|
||||
# ERL_LIBS causes a load of compile warnings (warning: this clause cannot
|
||||
# match because a previous clause at line 1 always matches) in the standard
|
||||
# library. It appears to be because things are evaluated twice.
|
||||
# An actual export -n isn't inherited properly so we just set it blank.
|
||||
export ERL_LIBS=""
|
||||
'';
|
||||
|
||||
ERL_AFLAGS = "-kernel shell_history enabled";
|
||||
|
||||
ERL_INCLUDE_PATH="${elixir}/lib/erlang/usr/include";
|
||||
|
||||
LOCALE_ARCHIVE = "${glibcLocales}/lib/locale/locale-archive";
|
||||
}
|
8
test/swapi_example_test.exs
Normal file
8
test/swapi_example_test.exs
Normal file
|
@ -0,0 +1,8 @@
|
|||
defmodule SwapiExampleTest do
|
||||
use ExUnit.Case
|
||||
doctest SwapiExample
|
||||
|
||||
test "greets the world" do
|
||||
assert SwapiExample.hello() == :world
|
||||
end
|
||||
end
|
1
test/test_helper.exs
Normal file
1
test/test_helper.exs
Normal file
|
@ -0,0 +1 @@
|
|||
ExUnit.start()
|
Loading…
Reference in a new issue