SlideShare uma empresa Scribd logo
1 de 110
Baixar para ler offline
OTP, Phoenix & Ecto: Three
Pillars of Elixir
Elixir Club Ternopil, 2017
Erlang
Functional Programming in Erlang
www.futurelearn.com/courses/functional-programming-erlang/
Concurrent Programming in Erlang
https://www.futurelearn.com/courses/concurrent-programming-erlang
Learn You Some Erlang for great good!
http://learnyousomeerlang.com/
Overview
1. Processes & OTP
2. Phoenix Elixir web framework
3. Ecto database wrapper and language integrated query for Elixir
Erlang/Elixir processes
• All code runs inside processes
• Processes are isolated from each other, run concurrent to one
another and communicate via message passing (Actor model)
• Processes are extremely lightweight in terms of memory and CPU and
managed by Erlang VM
• It is common to have tens or even hundreds of thousands of
processes running simultaneously
Spawning basic process
iex> spawn fn -> 100 * 100 end
#PID<0.94.0>
iex> self()
#PID<0.80.0>
Sending and receiving messages
iex> parent = self()
#PID<0.80.0>
iex> spawn fn -> send(parent, {:hello, self()}) end
#PID<0.103.0>
iex> receive do
...> {:hello, pid} -> "Got hello from #{inspect pid}"
...> {:other, _} -> "Something other"
...> end
"Got hello from #PID<0.103.0>"
Receive timeout
iex> receive do
...> {:other, msg} -> msg
...> after
...> 1_000 -> "Nothing received after 1s"
...> end
"Nothing received after 1s"
Flush
iex> send self(), :hello
:hello
iex> send self(), :world
:world
iex> flush()
:hello
:world
:ok
Linked processes: spawn_link
iex> spawn_link fn -> raise "something bad happened" end
23:53:50.503 [error] Process #PID<0.93.0> raised an exception
** (RuntimeError) something bad happened
:erlang.apply/2
** (EXIT from #PID<0.91.0>) an exception was raised:
** (RuntimeError) something bad happened
:erlang.apply/2
Linked processes & “Failing fast” philosophy
Parent process, which is the shell process, has received an EXIT signal
from another process causing the parent process to terminate.
Often we will link our processes to supervisors which will detect when
a process dies and start a new process in its place.
In Elixir we are actually fine with letting processes fail because we
expect supervisors to properly restart our systems.
Elixir: Task
iex> task = Task.async(fn -> 100 * 100 end)
%Task{owner: #PID<0.94.0>, pid: #PID<0.96.0>, ref:
#Reference<0.0.1.139>}
iex> res = Task.await(task)
10000
State
def start_link do
Task.start_link(fn -> loop(%{}) end)
end
defp loop(map) do
receive do
{:get, key, caller} ->
send caller, Map.get(map, key)
loop(map)
{:put, key, value} ->
loop(Map.put(map, key, value))
end
end
State
Spawn LoopInit Exit
Send
Receive
Elixir: Agent
iex> {:ok, agent} = Agent.start_link(fn -> %{} end)
{:ok, #PID<0.88.0>}
iex> Agent.update(agent, &Map.put(&1, :hello, "world"))
:ok
iex> Agent.get(agent, &Map.get(&1, :hello))
"world"
Behaviours
• Many of the processes have similar structures, they follow similar
patterns
• Behaviours provide a way to define a set of functions that have to be
implemented by a module
• You can think of behaviours like interfaces in OO languages
Behaviours
defmodule GenServer do
@callback init(args :: term) :: {:ok, state} ...
@callback handle_call(request :: term, from, state :: term)
:: {:reply, reply, new_state} ...
@callback handle_cast(request :: term, state :: term)
:: {:noreply, new_state} ...
...
Implementing behaviours
...
# Callbacks
def handle_call(:pop, _from, [h | t]) do
{:reply, h, t}
end
def handle_cast({:push, item}, state) do
{:noreply, [item | state]}
end
...
GenServer
• “Generic servers” (processes) that encapsulate state, provide sync
and async calls, support code reloading, and more.
• The GenServer behaviour abstracts the common client-server
interaction. Developers are only required to implement the callbacks
and functionality they are interested in.
• A GenServer is a process like any other Elixir process and it can be
used to keep state, execute code asynchronously and so on.
GenServer example
defmodule Stack do
use GenServer
# Callbacks
def handle_call(:pop, _from, [h | t]) do
{:reply, h, t}
end
def handle_cast({:push, item}, state) do
{:noreply, [item | state]}
end
end
GenServer example
iex> {:ok, pid} = GenServer.start_link(Stack, [:hello])
iex> GenServer.call(pid, :pop)
:hello
iex> GenServer.cast(pid, {:push, :world})
:ok
iex>GenServer.call(pid, :pop)
:world
GenServer cheatsheet
Benjamin Tan Wei Hao
https://github.com/benjamintanweihao/elixir-cheatsheets
Supervision Trees
• Supervision trees are a nice way
to structure fault-tolerant
applications.
• Process structuring model based
on the idea of workers and
supervisors.
S
W
S
W
S
W
Supervision Trees
• Workers are processes that perform computations, that is, they do
the actual work.
• Supervisors are processes that monitor the behaviour of workers. A
supervisor can restart a worker if something goes wrong.
• The supervision strategy dictates what happens when one of the
children crashes.
Supervisor
• A behaviour module for implementing supervision functionality.
• A supervisor is a process which supervises other processes, which we
refer to as child processes.
Supervisor module
defmodule MyApp.Supervisor do
use Supervisor
def start_link do
Supervisor.start_link(__MODULE__, [])
end
def init([]) do
children = [ worker(Stack, [[:hello]]) ]
supervise(children, strategy: :one_for_one)
end
end
Supervisor Cheat Sheet
Benjamin Tan Wei Hao
https://github.com/benjamintanweihao/elixir-cheatsheets
Application behaviour
• In Erlang/OTP, an application is a component implementing some
specific functionality, that can be started and stopped as a unit
• Mix is responsible for compiling your source code and generating
your application .app file in Elixir.
• Mix is also responsible for configuring, starting and stopping your
application and its dependencies (mix.exs).
• .app holds our application definition
Application callback
defmodule MyApp do
use Application
def start(_type, _args) do
MyApp.Supervisor.start_link()
end
end
Application project
mix new hello_world --sup hello_world
|-- README.md
|-- config
| `-- config.exs
|-- lib
| |-- hello_world
| | `-- application.ex
| `-- hello_world.ex
|-- mix.exs
`-- test
|-- hello_world_test.exs
`-- test_helper.exs
Application project: configuration
hello_worldmix.exs
def application do
# Specify extra applications you'll use from Erlang/Elixir
[extra_applications: [:logger],
mod: {HelloWorld.Application, []}]
end
Application project: callback module
hello_worldlibhello_worldapplication.ex
defmodule HelloWorld.Application do
...
def start(_type, _args) do
import Supervisor.Spec, warn: false
children = []
opts = [strategy: :one_for_one, name: HelloWorld.Supervisor]
Supervisor.start_link(children, opts)
end
end
Umbrella projects
mix new hello_umbrella --umbrella
hello_umbrella
|-- README.md
|-- apps
|-- config
| `-- config.exs
`-- mix.exs
Umbrella projects: configuration
...
def project do
[apps_path: "apps",
build_embedded: Mix.env == :prod,
start_permanent: Mix.env == :prod,
deps: deps()]
end
...
In umbrella dependencies
Mix supports an easy mechanism to make one umbrella child depend
on another.
...
defp deps do
[{:hello_world, in_umbrella: true}]
end
...
GenStage & Flow
Announcing GenStage
http://elixir-lang.org/blog/2016/07/14/announcing-genstage/
GenStage and Flow - Jose Valim | Elixir Club 5
https://www.youtube.com/watch?v=IUrfcBwkm7w
https://hex.pm/packages/gen_stage
GenStage is a new Elixir behaviour for exchanging
events with back-pressure between Elixir processes
producer
producer
consumer
producer
consumer
consumer
Flow: concurrent data processing
def process_flow(path_to_file) do
path_to_file
|> File.stream!()
|> Flow.from_enumerable()
|> Flow.flat_map(&String.split/1)
|> Flow.map(&String.replace(&1, ~r/W/u, ""))
|> Flow.filter_map(fn w -> w != "" end, &String.downcase/1)
|> Flow.partition()
|> Flow.reduce(fn -> %{} end, fn word, map ->
Map.update(map, word, 1, &(&1 + 1))
end)
|> Enum.into(%{})
end
Flow: concurrent data processing
def process_flow(path_to_file) do
path_to_file
|> File.stream!()
|> Flow.from_enumerable()
|> Flow.flat_map(&String.split/1)
|> Flow.map(&String.replace(&1, ~r/W/u, ""))
|> Flow.filter_map(fn w -> w != "" end, &String.downcase/1)
|> Flow.partition()
|> Flow.reduce(fn -> %{} end, fn word, map ->
Map.update(map, word, 1, &(&1 + 1))
end)
|> Enum.into(%{})
end
P
PC PC
DemandDispatcher
PartitionDispatcher
PC PC
C CReducers
%{} %{}
Flow
P
PC PC
PC PC
C C
%{} %{}
"The Project Gutenberg EBook of
The Complete Works of William
Shakespeare, byn"
"William Shakespearen"
"The", "Project", "Gutenberg",
"EBook", "of", "The", "Complete",
"Works", "of", "William",
"Shakespeare,", "by"
"William", "Shakespeare"
"the", "project", "of", “the",
"william", "of", "by ", "william"
"gutenberg", "ebook",
"complete", "shakespeare",
"works", "shakespeare"
Flow
Experimental.Flow, Yurii Bodarev at KyivElixirMeetup 3.1
https://www.youtube.com/watch?v=XhUeSUFF06w
https://github.com/yuriibodarev/elixir_flow
Phoenix Framework
• Phoenix is a web development framework written in Elixir which
implements the server-side MVC pattern
• Phoenix provides the best of both worlds - high developer
productivity and high application performance
• Phoenix is actually the top layer of a multi-layer system designed to be
modular and flexible. The other layers include Plug, and Ecto
• The Erlang HTTP server, Cowboy, acts as the foundation for Plug and
Phoenix
Phoenix Framework
• The Plug
• The Endpoint
• The Router
• Controllers
• Actions
• Views
• Templates
• Channels
The Plug
• Plug is a specification for constructing composable modules to build web
applications.
• Plugs are reusable modules or functions built to that specification.
• They provide discrete behaviors - like request header parsing or logging.
• Because the Plug API is small and consistent, plugs can be defined and executed
in a set order, like a pipeline.
• Core Phoenix components like Endpoints, Routers, and Controllers are all just
Plugs internally
Module Plug example
defmodule Example.HelloWorldPlug do
import Plug.Conn
def init(options), do: options
def call(conn, _opts) do
conn
|> put_resp_content_type("text/plain")
|> send_resp(200, "Hello World!")
end
end
%Plug.Conn{…}
Plug pipelines
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
end
Module Plug example
...
@locales ["en", "fr", "de"]
def init(default), do: default
def call(%Plug.Conn{params: %{"locale" => loc}} = conn, _default)
when loc in @locales
do
assign(conn, :locale, loc)
end
def call(conn, default), do: assign(conn, :locale, default)
...
Adding Plug to the pipeline
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
plug PhoenixApp.Plugs.Locale, "en"
end
The Endpoint
• provides a wrapper for starting and stopping the endpoint as part of a
supervision tree;
• handles all aspects of requests up until the point where the router takes over
• to define an initial plug pipeline where requests are sent through;
• to host web specific configuration for your application.
• dispatches requests into a designated router
The Endpoint
phoenix_applibphoenix_appwebendpoint.ex
defmodule PhoenixApp.Web.Endpoint do
use Phoenix.Endpoint, otp_app: :phoenix_app
# plug ...
# plug ...
plug PhoenixApp.Web.Router
end
Starting Endpoint
phoenix_applibphoenix_appapplication.ex
...
children = [
# Start the Ecto repository
supervisor(PhoenixApp.Repo, []),
# Start the endpoint when the application starts
supervisor(PhoenixApp.Web.Endpoint, [])
]
opts = [strategy: :one_for_one, name: PhoenixApp.Supervisor]
Supervisor.start_link(children, opts)
...
The Router
• parses incoming requests and dispatches them to the correct
controller/action, passing parameters as needed
• provides helpers to generate route paths or urls to resources
• defines named pipelines through which we may pass our requests
The Router
phoenix_applibphoenix_appwebrouter.ex
...
pipeline :browser do
plug :accepts, ["html"]
...
plug :put_secure_browser_headers
end
scope "/", PhoenixApp.Web do
pipe_through :browser # Use the default browser stack
get "/", PageController, :index
end
...
Controllers & Actions
Controllers provide functions, called actions, to handle requests
Actions
• prepare data and pass it into views
• invoke rendering via views
• perform redirects
Controller
get "/pages/:id", PageController, :show
phoenix_applibphoenix_appwebcontrollerspage_controller.ex
defmodule PhoenixApp.Web.PageController do
use PhoenixApp.Web, :controller
def show(conn, %{"id" => id}) do
user = Accounts.get_user(id)
render(conn, "show.html", user: user)
end
end
webweb.ex
use PhoenixApp.Web, :controller
phoenix_applibphoenix_appwebweb.ex
...
def controller do
quote do
use Phoenix.Controller, namespace: PhoenixApp.Web
import Plug.Conn
import PhoenixApp.Web.Router.Helpers
import PhoenixApp.Web.Gettext
end
end
...
Views
• Defines the view layer of a Phoenix application
• Render templates
• Define helper functions, available in templates, to decorate data for
presentation
Rendering Templates
Phoenix assumes a strong naming convention from controllers to views
to the templates they render. The PageController requires a PageView
to render templates in the webtemplatespage directory.
phoenix_applibphoenix_appwebweb.ex
...
def view do quote do
use Phoenix.View, root: "lib/phoenix_app/web/templates",
namespace: PhoenixApp.Web
...
Rendering Templates
phoenix_applibphoenix_appwebviewspage_view.ex
defmodule PhoenixApp.Web.PageView do
use PhoenixApp.Web, :view
end
Phoenix.View will automatically load all templates at
“phoenix_applibphoenix_appwebtemplatespage” and include
them in the PhoenixApp.Web.PageView
Rendering JSON
def render("index.json", %{pages: pages}) do
%{data: render_many(pages, PhoenixApp.PageView, "page.json")}
end
def render("show.json", %{page: page}) do
%{data: render_one(page, PhoenixApp.PageView, "page.json")}
end
def render("page.json", %{page: page}) do
%{title: page.title}
end
Templates
foo.html.eex
• templates are precompiled and fast
• template name - is the name of the template as given by the user,
without the template engine extension, for example: “foo.html”
• template path - is the complete path of the template in the
filesystem, for example, “path/to/foo.html.eex”
• template root - the directory where templates are defined
• template engine (EEx)- a module that receives a template path and
transforms its source code into Elixir quoted expressions.
Template examples
Hello <%= @name %>
<h3>Keys for the conn Struct</h3>
<%= for key <- connection_keys @conn do %>
<p><%= key %></p>
<% end %>
function that returns List of keys
Channels
• manage sockets for easy real-time communication
• are analogous to controllers except that they allow bi-directional
communication with persistent connections
• Every time you join a channel, you need to choose which particular
topic you want to listen to. The topic is just an identifier, but by
convention it is often made of two parts: "topic:subtopic".
Channel endpoint
phoenix_applibphoenix_appwebendpoint.ex
socket "/socket", PhoenixApp.Web.UserSocket
phoenix_applibphoenix_appwebchannelsuser_socket.ex
channel "room:*", PhoenixApp.Web.RoomChannel
Any topic coming into the router with the "room:" prefix would
dispatch to MyApp.RoomChannel
Joining Channels
defmodule PhoenixApp.Web.RoomChannel do
use Phoenix.Channel
def join("room:lobby", _message, socket) do
{:ok, socket}
end
def join("room:" <> _private_room_id, _params, _socket) do
{:error, %{reason: "unauthorized"}}
end
end
JS
phoenix_appassetsjssocket.js
...
socket.connect()
// Now that you are connected, you can join channels with a topic:
let channel = socket.channel("topic:subtopic", {}) channel.join()
.receive("ok", resp => { console.log("Joined successfully", resp) })
.receive("error", resp => { console.log("Unable to join", resp) })
JS
…
channel.push("new_msg", {body: “Hello world!”})
…
…
channel.on("new_msg", payload => { … })
…
Incoming Events
We handle incoming events with handle_in/3. We can pattern match
on the event names, like “new_msg”
def handle_in("new_msg", %{"body" => body}, socket) do
broadcast! socket, "new_msg", %{body: body}
{:noreply, socket}
end
Outgoing Events: default implementation
def handle_out("new_msg", payload, socket) do
push socket, "new_msg", payload
{:noreply, socket}
end
Intercepting Outgoing Events
intercept ["smth_important"]
def handle_out("smth_important", msg, socket) do
if … do
{:noreply, socket}
else
push socket, " smth_important", msg
{:noreply, socket}
end
end
Phoenix Framework 1.3
v1.3.0-rc.1
https://hex.pm/packages/phoenix
phx.new project generator
mix archive.install https://github.com/phoenixframework/archives/raw/master/phx_new.ez
Phoenix Framework 1.3
Lonestar ElixirConf 2017- KEYNOTE: Phoenix 1.3 by Chris McCord
https://www.youtube.com/watch?v=tMO28ar0lW8
Phoenix v1.3.0-rc.0 released @ ElixirForum
https://elixirforum.com/t/phoenix-v1-3-0-rc-0-released/3947
Upcoming book “Programming Phoenix 1.3” @ ElixirForum
https://elixirforum.com/t/programming-phoenix-1-3/2469
1.2: mix phoenix.new phoenix_old
phoenix_old
|-- config
|-- lib
| `-- phoenix_old
|-- priv
|-- test
`-- web
|-- channels
|-- controllers
|-- models
|-- static
|-- templates
`-- views
1.3: mix phx.new phoenix_new
phoenix_new
|-- assets
|-- config
|-- lib
| `-- phoenix_new
| `-- web
| |-- channels
| |-- controllers
| |-- templates
| `-- views
|-- priv
`-- test
1.3: mix phx.new phoenix --umbrella
phoenix_umbrella
|-- apps
| |-- phoenix
…
| `-- phoenix_web
phoenix_umbrellaappsphoenix_webmix.exs
...
{:phoenix, in_umbrella: true},
...
Web Namespace
defmodule PhoenixApp.Web.PageController do
use PhoenixApp.Web, :controller
def index(conn, _params) do
render conn, "index.html"
end
end
Context
1.2: mix phoenix.gen.json User users email:string
Repo.get(User, id)
1.3: mix phx.gen.json Accounts User users email:string
Accounts.get_user(2)
iex> %User{email: oscar@swanros.com}
Accounts.create_user(params)
iex> {:ok, new_user}
1.2: Models
`-- web
|-- channels
|-- controllers
|-- models
| |-- comment.ex
| |-- invoice.ex
| |-- order.ex
| |-- payment.ex
| |-- post.ex
| `-- user.ex
|-- static
|-- templates
`-- views
1.3: Context
|-- lib
| `-- phoenix_new
| |-- blog
| | |-- blog.ex
| | |-- comment.ex
| | `-- post.ex
| |-- sales
| | |-- order.ex
| | |-- payment.ex
| | `-- sales.ex
| `-- web
| |-- channels
The boundary for the Sales system.
libphoenix_newsalessales.ex
defmodule PhoenixNew.Sales do
def list_orders do
Repo.all(Order)
end
def get_order!(id), do: Repo.get!(Order, id)
def create_order(attrs  %{}) do
%Order{} |> order_changeset(attrs) |> Repo.insert()
end
...
Action Fallback
On Phoenix 1.2, every controller needed to return a valid %Plug.Conn{} for
every request. Otherwise, an exception would rise.
On Phoenix 1.3 we can register the plug to call as a fallback to the
controller action. If the controller action fails to return a %Plug.Conn{},
the provided plug will be called and receive the controller’s
%Plug.Conn{} as it was before the action was invoked along with the
value returned from the controller action.
1.2: Controller Action
phoenix_oldwebcontrollerspost_controller.ex
case Repo.insert(changeset) do
{:ok, post} ->
conn
|> put_status(:created)
|> put_resp_header("location", post_path(conn, :show, post))
|> render("show.json", post: post)
{:error, changeset} ->
conn
|> put_status(:unprocessable_entity)
|> render(PhoenixOld.ChangesetView, "error.json", changeset:
changeset)
end
1.3: Controller Action
phoenix_newlibphoenix_newwebcontrollerspost_controller.ex
def create(conn, %{"post" => post_params}) do
with {:ok, %Post{} = post} <- Blog.create_post(post_params) do
conn
|> put_status(:created)
|> put_resp_header("location", post_path(conn, :show, post))
|> render("show.json", post: post)
end
end
1.3 Action Fallback
phoenix_newlibphoenix_newwebcontrollersfallback_controller.ex
def call(conn, {:error, %Ecto.Changeset{} = changeset}) do
conn
|> put_status(:unprocessable_entity)
|> render(PhoenixNew.Web.ChangesetView, "error.json", changeset:
changeset)
end
Ecto
Domain specific language for writing queries and interacting with
databases in Elixir.
pages.plataformatec.com.br/ebook-whats-new-in-ecto-2-0
Ecto
Ecto is split into 4 main components:
• Ecto.Repo - repositories are wrappers around the data store.
• Ecto.Schema - schemas are used to map any data source into an Elixir
struct.
• Ecto.Changeset - allow developers to filter, cast, and validate changes
before we apply them to the data.
• Ecto.Query - written in Elixir syntax, queries are used to retrieve
information from a given repository.
Repositories
Via the repository, we can create, update, destroy and query existing
database entries.
Repositories
Ecto.Repo is a wrapper around the database. We can define a
repository as follows:
defmodule Blog.Repo do
use Ecto.Repo, otp_app: :blog
end
Repositories
A repository needs an adapter and credentials to communicate to the database.
Configuration for the Repo usually defined in your config/config.exs:
config :blog, Blog.Repo,
adapter: Ecto.Adapters.Postgres,
database: "blog_repo",
username: "postgres",
password: "postgres",
hostname: "localhost"
Repositories
Each repository in Ecto defines a start_link/0. Usually this function is invoked as part
of your application supervision tree:
def start(_type, _args) do
import Supervisor.Spec, warn: false
children = [ worker(Blog.Repo, []), ]
opts = [strategy: :one_for_one, name: Blog.Supervisor]
Supervisor.start_link(children, opts)
end
Schema
Schemas allows developers to define the shape of their data.
defmodule Blog.User do
use Ecto.Schema
schema "users" do
field :name, :string
field :reputation, :integer, default: 0
has_many :posts, Blog.Post, on_delete: :delete_all
timestamps
end
end
Schema
By defining a schema, Ecto automatically defines a struct:
iex> user = %Blog.User{name: "Bill"}
%Blog.User{__meta__: #Ecto.Schema.Metadata<:built,
"users">, id: nil, inserted_at: nil, name: "Bill"},
posts: #Ecto.Association.NotLoaded<association
:posts is not loaded>, reputation: 0, updated_at:
nil}
Schema
Using Schema we can interact with a repository:
iex> user = %Blog.User{name: "Bill", reputation: 10}
%Blog.User{…}
iex> Blog.Repo.insert!(user)
%Blog.User{__meta__: #Ecto.Schema.Metadata<:loaded,
"users">, id: 6, inserted_at: ~N[2016-12-13
16:16:35.983000], name: "Bill", posts:
#Ecto.Association.NotLoaded<association :posts is not
loaded>, reputation: 10, updated_at: ~N[2016-12-13
16:16:36.001000]}
Schema
# Get the user back
iex> newuser = Blog.Repo.get(Blog.User, 6)
iex> newuser.id
6
# Delete it
iex> Blog.Repo.delete(newuser)
{:ok, %Blog.User{…, id: 6,…}}
Schema
We can use pattern matching on Structs created with Schemas:
iex> %{name: name, reputation: reputation} =
...> Blog.Repo.get(Blog.User, 1)
iex> name
"Alex"
iex> reputation
144
Changesets
We can add changesets to our schemas to validate changes before we
apply them to the data:
def changeset(user, params  %{}) do
user
|> cast(params, [:name, :reputation])
|> validate_required([:name, :reputation])
|> validate_inclusion(:reputation, -999..999)
end
Changesets
iex> alina = %Blog.User{name: "Alina"}
iex> correct_changeset = Blog.User.changeset(alina, %{reputation: 55})
#Ecto.Changeset<action: nil, changes: %{reputation: 55}, errors: [],
data: #Blog.User<>, valid?: true>
iex> invalid_changeset = Blog.User.changeset(alina, %{reputation: 1055})
#Ecto.Changeset<action: nil, changes: %{reputation: 1055}, errors:
[reputation: {"is invalid", [validation: :inclusion]}], data:
#Blog.User<>, valid?: false>
Changeset with Repository functions
iex> valid_changeset.valid?
true
iex> Blog.Repo.insert(valid_changeset)
{:ok, %Blog.User{…, id: 7, …}}
Changeset with Repository functions
iex> invalid_changeset.valid?
false
iex> Blog.Repo.insert(invalid_changeset)
{:error, #Ecto.Changeset<action: :insert, changes:
%{reputation: 1055}, errors: [reputation: {"is
invalid", [validation: :inclusion]}], data:
#Blog.User<>, valid?: false>}
Changeset with Repository functions
case Blog.Repo.update(changeset) do
{:ok, user} ->
# user updated
{:error, changeset} ->
# an error occurred
end
We can provide different changeset functions
for different use cases
def registration_changeset(user, params) do
# Changeset on create
end
def update_changeset(user, params) do
# Changeset on update
end
Query
Ecto allows you to write queries in Elixir and send them to the
repository, which translates them to the underlying database.
Query using predefined Schema
# Query using predefined Schema
query = from u in User,
where: u.reputation > 35,
select: u
# Returns %User{} structs matching the query
Repo.all(query)
[%Blog.User{…, id: 2, …, name: "Bender", …, reputation: 42, …},
%Blog.User{…, id: 1, …, name: "Alex", …, reputation: 144, …}]
Direct query with “users” table
# Directly querying the “users” table
query = from u in "users",
where: u.reputation > 30,
select: %{name: u.name, reputation: u.reputation}
# Returns maps as defined in select
Repo.all(query)
[%{name: "Bender", reputation: 42}, %{name: "Alex", reputation: 144}]
External values in Queries
# ^ operator
min = 33
query = from u in "users",
where: u.reputation > ^min,
select: u.name
# casting
mins = "33"
query = from u in "users",
where: u.reputation > type(^mins, :integer),
select: u.name
External values in Queries
If the query is made against Schema than Ecto will
automatically cast external value
min = "35"
Repo.all(from u in User, where: u.reputation > ^min)
You can also skip Select to retrieve all fields specified in the Schema
Ecto Multi
Ecto.Multi is a data structure for grouping multiple Repo operations in a single database
transaction.
def reset(account, params) do
Multi.new
|> Multi.update(:account, Account.password_reset_changeset(account, params))
|> Multi.insert(:log, Log.password_reset_changeset(account, params))
|> Multi.delete_all(:sessions, Ecto.assoc(account, :sessions))
end
Repo.transaction(PasswordManager.reset(account, params))
Ecto Multi
case result do
{:ok, %{account: account, log: log, sessions: sessions}} ->
# We can access results under keys we used
# for naming the operations.
{:error, failed_operation, failed_value, changes_so_far} ->
# One of the operations failed.
# We can access the operation's failure value (changeset)
# Successful operations would have been rolled back.
end
Books
Saša Jurić “Elixir in Action”
https://www.manning.com/books/elixir-in-action
Benjamin Tan Wei Hao “The Little Elixir & OTP Guidebook”
https://www.manning.com/books/the-little-elixir-and-otp-guidebook
New! Lance Halvorsen “Functional Web Development with Elixir, OTP, and Phoenix”
https://pragprog.com/book/lhelph/functional-web-development-with-elixir-otp-and-phoenix
Chris McCord “Programming Phoenix” (1.2 -> 1.3)
https://pragprog.com/book/phoenix/programming-phoenix
“What's new in Ecto 2.0”
http://pages.plataformatec.com.br/ebook-whats-new-in-ecto-2-0
THANK YOU!
Yurii Bodarev
@bodarev_yurii
https://github.com/yuriibodarev

Mais conteúdo relacionado

Mais procurados

Scratching the surface of hunky-dory Elixir features
Scratching the surface of hunky-dory Elixir featuresScratching the surface of hunky-dory Elixir features
Scratching the surface of hunky-dory Elixir featuresAdam Hodowany
 
第1回PHP拡張勉強会
第1回PHP拡張勉強会第1回PHP拡張勉強会
第1回PHP拡張勉強会Ippei Ogiwara
 
Introduction to Elixir
Introduction to ElixirIntroduction to Elixir
Introduction to ElixirDiacode
 
Elixir & Phoenix - fast, concurrent and explicit
Elixir & Phoenix - fast, concurrent and explicitElixir & Phoenix - fast, concurrent and explicit
Elixir & Phoenix - fast, concurrent and explicitTobias Pfeiffer
 
More than syntax
More than syntaxMore than syntax
More than syntaxWooga
 
Monitoring with Syslog and EventMachine (RailswayConf 2012)
Monitoring  with  Syslog and EventMachine (RailswayConf 2012)Monitoring  with  Syslog and EventMachine (RailswayConf 2012)
Monitoring with Syslog and EventMachine (RailswayConf 2012)Wooga
 
Ruby to Elixir - what's great and what you might miss
Ruby to Elixir - what's great and what you might missRuby to Elixir - what's great and what you might miss
Ruby to Elixir - what's great and what you might missTobias Pfeiffer
 
C++Programming Language Tips Tricks Understandings
C++Programming Language Tips Tricks UnderstandingsC++Programming Language Tips Tricks Understandings
C++Programming Language Tips Tricks Understandingsgufranresearcher
 
Django productivity tips and tricks
Django productivity tips and tricksDjango productivity tips and tricks
Django productivity tips and tricksSimone Federici
 
Introduction to Erlang/(Elixir) at a Webilea Hands-On Session
Introduction to Erlang/(Elixir) at a Webilea Hands-On SessionIntroduction to Erlang/(Elixir) at a Webilea Hands-On Session
Introduction to Erlang/(Elixir) at a Webilea Hands-On SessionAndré Graf
 
Ansible Callback Plugins
Ansible Callback PluginsAnsible Callback Plugins
Ansible Callback Pluginsjtyr
 
ElixirConf Lightning Talk: Elixir |> Production
ElixirConf Lightning Talk: Elixir |> ProductionElixirConf Lightning Talk: Elixir |> Production
ElixirConf Lightning Talk: Elixir |> ProductionJeff Weiss
 
Hacking ansible
Hacking ansibleHacking ansible
Hacking ansiblebcoca
 
Using HttpKernelInterface for Painless Integration
Using HttpKernelInterface for Painless IntegrationUsing HttpKernelInterface for Painless Integration
Using HttpKernelInterface for Painless IntegrationCiaranMcNulty
 
Any event intro
Any event introAny event intro
Any event introqiang
 
Flask restfulservices
Flask restfulservicesFlask restfulservices
Flask restfulservicesMarcos Lin
 

Mais procurados (20)

Scratching the surface of hunky-dory Elixir features
Scratching the surface of hunky-dory Elixir featuresScratching the surface of hunky-dory Elixir features
Scratching the surface of hunky-dory Elixir features
 
第1回PHP拡張勉強会
第1回PHP拡張勉強会第1回PHP拡張勉強会
第1回PHP拡張勉強会
 
Introduction to Elixir
Introduction to ElixirIntroduction to Elixir
Introduction to Elixir
 
Elixir & Phoenix - fast, concurrent and explicit
Elixir & Phoenix - fast, concurrent and explicitElixir & Phoenix - fast, concurrent and explicit
Elixir & Phoenix - fast, concurrent and explicit
 
More than syntax
More than syntaxMore than syntax
More than syntax
 
Monitoring with Syslog and EventMachine (RailswayConf 2012)
Monitoring  with  Syslog and EventMachine (RailswayConf 2012)Monitoring  with  Syslog and EventMachine (RailswayConf 2012)
Monitoring with Syslog and EventMachine (RailswayConf 2012)
 
Ruby to Elixir - what's great and what you might miss
Ruby to Elixir - what's great and what you might missRuby to Elixir - what's great and what you might miss
Ruby to Elixir - what's great and what you might miss
 
C++Programming Language Tips Tricks Understandings
C++Programming Language Tips Tricks UnderstandingsC++Programming Language Tips Tricks Understandings
C++Programming Language Tips Tricks Understandings
 
Django productivity tips and tricks
Django productivity tips and tricksDjango productivity tips and tricks
Django productivity tips and tricks
 
Introduction to Erlang/(Elixir) at a Webilea Hands-On Session
Introduction to Erlang/(Elixir) at a Webilea Hands-On SessionIntroduction to Erlang/(Elixir) at a Webilea Hands-On Session
Introduction to Erlang/(Elixir) at a Webilea Hands-On Session
 
Ansible Callback Plugins
Ansible Callback PluginsAnsible Callback Plugins
Ansible Callback Plugins
 
ElixirConf Lightning Talk: Elixir |> Production
ElixirConf Lightning Talk: Elixir |> ProductionElixirConf Lightning Talk: Elixir |> Production
ElixirConf Lightning Talk: Elixir |> Production
 
Symfony 2.0 on PHP 5.3
Symfony 2.0 on PHP 5.3Symfony 2.0 on PHP 5.3
Symfony 2.0 on PHP 5.3
 
Hacking ansible
Hacking ansibleHacking ansible
Hacking ansible
 
New in php 7
New in php 7New in php 7
New in php 7
 
Using HttpKernelInterface for Painless Integration
Using HttpKernelInterface for Painless IntegrationUsing HttpKernelInterface for Painless Integration
Using HttpKernelInterface for Painless Integration
 
Any event intro
Any event introAny event intro
Any event intro
 
ssh.isdn.test
ssh.isdn.testssh.isdn.test
ssh.isdn.test
 
Flask restfulservices
Flask restfulservicesFlask restfulservices
Flask restfulservices
 
ReactPHP
ReactPHPReactPHP
ReactPHP
 

Destaque

Anton Mishchuk - Multi-language FBP with Flowex
Anton Mishchuk - Multi-language FBP with FlowexAnton Mishchuk - Multi-language FBP with Flowex
Anton Mishchuk - Multi-language FBP with FlowexElixir Club
 
Ecto DSL Introduction - Yurii Bodarev
Ecto DSL Introduction - Yurii BodarevEcto DSL Introduction - Yurii Bodarev
Ecto DSL Introduction - Yurii BodarevElixir Club
 
Composable Queries with Ecto
Composable Queries with EctoComposable Queries with Ecto
Composable Queries with Ectodrewolson
 
Phoenix: Inflame the Web - Alex Troush
Phoenix: Inflame the Web - Alex TroushPhoenix: Inflame the Web - Alex Troush
Phoenix: Inflame the Web - Alex TroushElixir Club
 
Bottleneck in Elixir Application - Alexey Osipenko
 Bottleneck in Elixir Application - Alexey Osipenko  Bottleneck in Elixir Application - Alexey Osipenko
Bottleneck in Elixir Application - Alexey Osipenko Elixir Club
 

Destaque (6)

Anton Mishchuk - Multi-language FBP with Flowex
Anton Mishchuk - Multi-language FBP with FlowexAnton Mishchuk - Multi-language FBP with Flowex
Anton Mishchuk - Multi-language FBP with Flowex
 
Ecto DSL Introduction - Yurii Bodarev
Ecto DSL Introduction - Yurii BodarevEcto DSL Introduction - Yurii Bodarev
Ecto DSL Introduction - Yurii Bodarev
 
Composable Queries with Ecto
Composable Queries with EctoComposable Queries with Ecto
Composable Queries with Ecto
 
Phoenix: Inflame the Web - Alex Troush
Phoenix: Inflame the Web - Alex TroushPhoenix: Inflame the Web - Alex Troush
Phoenix: Inflame the Web - Alex Troush
 
Bottleneck in Elixir Application - Alexey Osipenko
 Bottleneck in Elixir Application - Alexey Osipenko  Bottleneck in Elixir Application - Alexey Osipenko
Bottleneck in Elixir Application - Alexey Osipenko
 
PowerPoint Tutorial
PowerPoint TutorialPowerPoint Tutorial
PowerPoint Tutorial
 

Semelhante a Yurii Bodarev - OTP, Phoenix & Ecto: Three Pillars of Elixir

Introducing Elixir and OTP at the Erlang BASH
Introducing Elixir and OTP at the Erlang BASHIntroducing Elixir and OTP at the Erlang BASH
Introducing Elixir and OTP at the Erlang BASHdevbash
 
Phoenix demysitify, with fun
Phoenix demysitify, with funPhoenix demysitify, with fun
Phoenix demysitify, with funTai An Su
 
Elixir flow: Building and tuning concurrent workflows
Elixir flow: Building and tuning concurrent workflowsElixir flow: Building and tuning concurrent workflows
Elixir flow: Building and tuning concurrent workflowsLuke Galea
 
Re-Design with Elixir/OTP
Re-Design with Elixir/OTPRe-Design with Elixir/OTP
Re-Design with Elixir/OTPMustafa TURAN
 
Concurrency, Robustness & Elixir SoCraTes 2015
Concurrency, Robustness & Elixir SoCraTes 2015Concurrency, Robustness & Elixir SoCraTes 2015
Concurrency, Robustness & Elixir SoCraTes 2015steffenbauer
 
Ecto and Phoenix: Doing web with Elixir - Yurii Bodarev
Ecto and Phoenix: Doing web with Elixir - Yurii BodarevEcto and Phoenix: Doing web with Elixir - Yurii Bodarev
Ecto and Phoenix: Doing web with Elixir - Yurii BodarevElixir Club
 
Ecto and Phoenix: Doing Web With Elixir
Ecto and Phoenix: Doing Web With ElixirEcto and Phoenix: Doing Web With Elixir
Ecto and Phoenix: Doing Web With ElixirYurii Bodarev
 
Introduction To Erlang Final
Introduction To Erlang   FinalIntroduction To Erlang   Final
Introduction To Erlang FinalSinarShebl
 
Awesome Concurrency with Elixir Tasks
Awesome Concurrency with Elixir TasksAwesome Concurrency with Elixir Tasks
Awesome Concurrency with Elixir TasksJonathan Magen
 
Origins of Elixir programming language
Origins of Elixir programming languageOrigins of Elixir programming language
Origins of Elixir programming languagePivorak MeetUp
 
Building Cloud Castles
Building Cloud CastlesBuilding Cloud Castles
Building Cloud CastlesBen Scofield
 
Cloud Orchestration with RightScale Cloud Workflow
Cloud Orchestration with RightScale Cloud WorkflowCloud Orchestration with RightScale Cloud Workflow
Cloud Orchestration with RightScale Cloud WorkflowRightScale
 
Exploring Clojurescript
Exploring ClojurescriptExploring Clojurescript
Exploring ClojurescriptLuke Donnet
 
Concurrency and Thread-Safe Data Processing in Background Tasks
Concurrency and Thread-Safe Data Processing in Background TasksConcurrency and Thread-Safe Data Processing in Background Tasks
Concurrency and Thread-Safe Data Processing in Background TasksWO Community
 

Semelhante a Yurii Bodarev - OTP, Phoenix & Ecto: Three Pillars of Elixir (20)

Introducing Elixir and OTP at the Erlang BASH
Introducing Elixir and OTP at the Erlang BASHIntroducing Elixir and OTP at the Erlang BASH
Introducing Elixir and OTP at the Erlang BASH
 
Experimental.flow
Experimental.flowExperimental.flow
Experimental.flow
 
Phoenix demysitify, with fun
Phoenix demysitify, with funPhoenix demysitify, with fun
Phoenix demysitify, with fun
 
Elixir flow: Building and tuning concurrent workflows
Elixir flow: Building and tuning concurrent workflowsElixir flow: Building and tuning concurrent workflows
Elixir flow: Building and tuning concurrent workflows
 
Re-Design with Elixir/OTP
Re-Design with Elixir/OTPRe-Design with Elixir/OTP
Re-Design with Elixir/OTP
 
Concurrency, Robustness & Elixir SoCraTes 2015
Concurrency, Robustness & Elixir SoCraTes 2015Concurrency, Robustness & Elixir SoCraTes 2015
Concurrency, Robustness & Elixir SoCraTes 2015
 
Tml for Laravel
Tml for LaravelTml for Laravel
Tml for Laravel
 
Ecto and Phoenix: Doing web with Elixir - Yurii Bodarev
Ecto and Phoenix: Doing web with Elixir - Yurii BodarevEcto and Phoenix: Doing web with Elixir - Yurii Bodarev
Ecto and Phoenix: Doing web with Elixir - Yurii Bodarev
 
Ecto and Phoenix: Doing Web With Elixir
Ecto and Phoenix: Doing Web With ElixirEcto and Phoenix: Doing Web With Elixir
Ecto and Phoenix: Doing Web With Elixir
 
Introduction To Erlang Final
Introduction To Erlang   FinalIntroduction To Erlang   Final
Introduction To Erlang Final
 
Awesome Concurrency with Elixir Tasks
Awesome Concurrency with Elixir TasksAwesome Concurrency with Elixir Tasks
Awesome Concurrency with Elixir Tasks
 
Origins of Elixir programming language
Origins of Elixir programming languageOrigins of Elixir programming language
Origins of Elixir programming language
 
Elixir and OTP
Elixir and OTPElixir and OTP
Elixir and OTP
 
Building Cloud Castles
Building Cloud CastlesBuilding Cloud Castles
Building Cloud Castles
 
Erlang, an overview
Erlang, an overviewErlang, an overview
Erlang, an overview
 
Elixir
ElixirElixir
Elixir
 
Cloud Orchestration with RightScale Cloud Workflow
Cloud Orchestration with RightScale Cloud WorkflowCloud Orchestration with RightScale Cloud Workflow
Cloud Orchestration with RightScale Cloud Workflow
 
Exploring Clojurescript
Exploring ClojurescriptExploring Clojurescript
Exploring Clojurescript
 
Concurrency and Thread-Safe Data Processing in Background Tasks
Concurrency and Thread-Safe Data Processing in Background TasksConcurrency and Thread-Safe Data Processing in Background Tasks
Concurrency and Thread-Safe Data Processing in Background Tasks
 
Elixir flow
Elixir flowElixir flow
Elixir flow
 

Mais de Elixir Club

Kubernetes + Docker + Elixir - Alexei Sholik, Andrew Dryga | Elixir Club Ukraine
Kubernetes + Docker + Elixir - Alexei Sholik, Andrew Dryga | Elixir Club UkraineKubernetes + Docker + Elixir - Alexei Sholik, Andrew Dryga | Elixir Club Ukraine
Kubernetes + Docker + Elixir - Alexei Sholik, Andrew Dryga | Elixir Club UkraineElixir Club
 
Integrating 3rd parties with Ecto - Eduardo Aguilera | Elixir Club Ukraine
Integrating 3rd parties with Ecto -  Eduardo Aguilera | Elixir Club UkraineIntegrating 3rd parties with Ecto -  Eduardo Aguilera | Elixir Club Ukraine
Integrating 3rd parties with Ecto - Eduardo Aguilera | Elixir Club UkraineElixir Club
 
— An async template - Oleksandr Khokhlov | Elixir Club Ukraine
— An async template  -  Oleksandr Khokhlov | Elixir Club Ukraine— An async template  -  Oleksandr Khokhlov | Elixir Club Ukraine
— An async template - Oleksandr Khokhlov | Elixir Club UkraineElixir Club
 
BEAM architecture handbook - Andrea Leopardi | Elixir Club Ukraine
BEAM architecture handbook - Andrea Leopardi  | Elixir Club UkraineBEAM architecture handbook - Andrea Leopardi  | Elixir Club Ukraine
BEAM architecture handbook - Andrea Leopardi | Elixir Club UkraineElixir Club
 
You ain't gonna need write a GenServer - Ulisses Almeida | Elixir Club Ukraine
You ain't gonna need write a GenServer - Ulisses Almeida  | Elixir Club UkraineYou ain't gonna need write a GenServer - Ulisses Almeida  | Elixir Club Ukraine
You ain't gonna need write a GenServer - Ulisses Almeida | Elixir Club UkraineElixir Club
 
— Knock, knock — An async templates — Who’s there? - Alexander Khokhlov | ...
 — Knock, knock — An async templates — Who’s there? - Alexander Khokhlov  |  ... — Knock, knock — An async templates — Who’s there? - Alexander Khokhlov  |  ...
— Knock, knock — An async templates — Who’s there? - Alexander Khokhlov | ...Elixir Club
 
Performance measurement methodology — Maksym Pugach | Elixir Evening Club 3
Performance measurement methodology — Maksym Pugach | Elixir Evening Club 3Performance measurement methodology — Maksym Pugach | Elixir Evening Club 3
Performance measurement methodology — Maksym Pugach | Elixir Evening Club 3Elixir Club
 
Erlang cluster. How is it? Production experience. — Valerii Vasylkov | Elixi...
Erlang cluster. How is it? Production experience. —  Valerii Vasylkov | Elixi...Erlang cluster. How is it? Production experience. —  Valerii Vasylkov | Elixi...
Erlang cluster. How is it? Production experience. — Valerii Vasylkov | Elixi...Elixir Club
 
Promo Phx4RailsDevs - Volodya Sveredyuk
Promo Phx4RailsDevs - Volodya SveredyukPromo Phx4RailsDevs - Volodya Sveredyuk
Promo Phx4RailsDevs - Volodya SveredyukElixir Club
 
Web of today — Alexander Khokhlov
Web of today —  Alexander KhokhlovWeb of today —  Alexander Khokhlov
Web of today — Alexander KhokhlovElixir Club
 
ElixirConf Eu 2018, what was it like? – Eugene Pirogov
ElixirConf Eu 2018, what was it like? – Eugene PirogovElixirConf Eu 2018, what was it like? – Eugene Pirogov
ElixirConf Eu 2018, what was it like? – Eugene PirogovElixir Club
 
Implementing GraphQL API in Elixir – Victor Deryagin
Implementing GraphQL API in Elixir – Victor DeryaginImplementing GraphQL API in Elixir – Victor Deryagin
Implementing GraphQL API in Elixir – Victor DeryaginElixir Club
 
WebPerformance: Why and How? – Stefan Wintermeyer
WebPerformance: Why and How? – Stefan WintermeyerWebPerformance: Why and How? – Stefan Wintermeyer
WebPerformance: Why and How? – Stefan WintermeyerElixir Club
 
GenServer in Action – Yurii Bodarev
GenServer in Action – Yurii Bodarev   GenServer in Action – Yurii Bodarev
GenServer in Action – Yurii Bodarev Elixir Club
 
Russian Doll Paradox: Elixir Web without Phoenix - Alex Rozumii
Russian Doll Paradox: Elixir Web without Phoenix - Alex RozumiiRussian Doll Paradox: Elixir Web without Phoenix - Alex Rozumii
Russian Doll Paradox: Elixir Web without Phoenix - Alex RozumiiElixir Club
 
Practical Fault Tolerance in Elixir - Alexei Sholik
Practical Fault Tolerance in Elixir - Alexei SholikPractical Fault Tolerance in Elixir - Alexei Sholik
Practical Fault Tolerance in Elixir - Alexei SholikElixir Club
 
Phoenix and beyond: Things we do with Elixir - Alexander Khokhlov
Phoenix and beyond: Things we do with Elixir - Alexander KhokhlovPhoenix and beyond: Things we do with Elixir - Alexander Khokhlov
Phoenix and beyond: Things we do with Elixir - Alexander KhokhlovElixir Club
 
Monads are just monoids in the category of endofunctors - Ike Kurghinyan
Monads are just monoids in the category of endofunctors - Ike KurghinyanMonads are just monoids in the category of endofunctors - Ike Kurghinyan
Monads are just monoids in the category of endofunctors - Ike KurghinyanElixir Club
 
Craft effective API with GraphQL and Absinthe - Ihor Katkov
Craft effective API with GraphQL and Absinthe - Ihor KatkovCraft effective API with GraphQL and Absinthe - Ihor Katkov
Craft effective API with GraphQL and Absinthe - Ihor KatkovElixir Club
 
Elixir in a service of government - Alex Troush
Elixir in a service of government - Alex TroushElixir in a service of government - Alex Troush
Elixir in a service of government - Alex TroushElixir Club
 

Mais de Elixir Club (20)

Kubernetes + Docker + Elixir - Alexei Sholik, Andrew Dryga | Elixir Club Ukraine
Kubernetes + Docker + Elixir - Alexei Sholik, Andrew Dryga | Elixir Club UkraineKubernetes + Docker + Elixir - Alexei Sholik, Andrew Dryga | Elixir Club Ukraine
Kubernetes + Docker + Elixir - Alexei Sholik, Andrew Dryga | Elixir Club Ukraine
 
Integrating 3rd parties with Ecto - Eduardo Aguilera | Elixir Club Ukraine
Integrating 3rd parties with Ecto -  Eduardo Aguilera | Elixir Club UkraineIntegrating 3rd parties with Ecto -  Eduardo Aguilera | Elixir Club Ukraine
Integrating 3rd parties with Ecto - Eduardo Aguilera | Elixir Club Ukraine
 
— An async template - Oleksandr Khokhlov | Elixir Club Ukraine
— An async template  -  Oleksandr Khokhlov | Elixir Club Ukraine— An async template  -  Oleksandr Khokhlov | Elixir Club Ukraine
— An async template - Oleksandr Khokhlov | Elixir Club Ukraine
 
BEAM architecture handbook - Andrea Leopardi | Elixir Club Ukraine
BEAM architecture handbook - Andrea Leopardi  | Elixir Club UkraineBEAM architecture handbook - Andrea Leopardi  | Elixir Club Ukraine
BEAM architecture handbook - Andrea Leopardi | Elixir Club Ukraine
 
You ain't gonna need write a GenServer - Ulisses Almeida | Elixir Club Ukraine
You ain't gonna need write a GenServer - Ulisses Almeida  | Elixir Club UkraineYou ain't gonna need write a GenServer - Ulisses Almeida  | Elixir Club Ukraine
You ain't gonna need write a GenServer - Ulisses Almeida | Elixir Club Ukraine
 
— Knock, knock — An async templates — Who’s there? - Alexander Khokhlov | ...
 — Knock, knock — An async templates — Who’s there? - Alexander Khokhlov  |  ... — Knock, knock — An async templates — Who’s there? - Alexander Khokhlov  |  ...
— Knock, knock — An async templates — Who’s there? - Alexander Khokhlov | ...
 
Performance measurement methodology — Maksym Pugach | Elixir Evening Club 3
Performance measurement methodology — Maksym Pugach | Elixir Evening Club 3Performance measurement methodology — Maksym Pugach | Elixir Evening Club 3
Performance measurement methodology — Maksym Pugach | Elixir Evening Club 3
 
Erlang cluster. How is it? Production experience. — Valerii Vasylkov | Elixi...
Erlang cluster. How is it? Production experience. —  Valerii Vasylkov | Elixi...Erlang cluster. How is it? Production experience. —  Valerii Vasylkov | Elixi...
Erlang cluster. How is it? Production experience. — Valerii Vasylkov | Elixi...
 
Promo Phx4RailsDevs - Volodya Sveredyuk
Promo Phx4RailsDevs - Volodya SveredyukPromo Phx4RailsDevs - Volodya Sveredyuk
Promo Phx4RailsDevs - Volodya Sveredyuk
 
Web of today — Alexander Khokhlov
Web of today —  Alexander KhokhlovWeb of today —  Alexander Khokhlov
Web of today — Alexander Khokhlov
 
ElixirConf Eu 2018, what was it like? – Eugene Pirogov
ElixirConf Eu 2018, what was it like? – Eugene PirogovElixirConf Eu 2018, what was it like? – Eugene Pirogov
ElixirConf Eu 2018, what was it like? – Eugene Pirogov
 
Implementing GraphQL API in Elixir – Victor Deryagin
Implementing GraphQL API in Elixir – Victor DeryaginImplementing GraphQL API in Elixir – Victor Deryagin
Implementing GraphQL API in Elixir – Victor Deryagin
 
WebPerformance: Why and How? – Stefan Wintermeyer
WebPerformance: Why and How? – Stefan WintermeyerWebPerformance: Why and How? – Stefan Wintermeyer
WebPerformance: Why and How? – Stefan Wintermeyer
 
GenServer in Action – Yurii Bodarev
GenServer in Action – Yurii Bodarev   GenServer in Action – Yurii Bodarev
GenServer in Action – Yurii Bodarev
 
Russian Doll Paradox: Elixir Web without Phoenix - Alex Rozumii
Russian Doll Paradox: Elixir Web without Phoenix - Alex RozumiiRussian Doll Paradox: Elixir Web without Phoenix - Alex Rozumii
Russian Doll Paradox: Elixir Web without Phoenix - Alex Rozumii
 
Practical Fault Tolerance in Elixir - Alexei Sholik
Practical Fault Tolerance in Elixir - Alexei SholikPractical Fault Tolerance in Elixir - Alexei Sholik
Practical Fault Tolerance in Elixir - Alexei Sholik
 
Phoenix and beyond: Things we do with Elixir - Alexander Khokhlov
Phoenix and beyond: Things we do with Elixir - Alexander KhokhlovPhoenix and beyond: Things we do with Elixir - Alexander Khokhlov
Phoenix and beyond: Things we do with Elixir - Alexander Khokhlov
 
Monads are just monoids in the category of endofunctors - Ike Kurghinyan
Monads are just monoids in the category of endofunctors - Ike KurghinyanMonads are just monoids in the category of endofunctors - Ike Kurghinyan
Monads are just monoids in the category of endofunctors - Ike Kurghinyan
 
Craft effective API with GraphQL and Absinthe - Ihor Katkov
Craft effective API with GraphQL and Absinthe - Ihor KatkovCraft effective API with GraphQL and Absinthe - Ihor Katkov
Craft effective API with GraphQL and Absinthe - Ihor Katkov
 
Elixir in a service of government - Alex Troush
Elixir in a service of government - Alex TroushElixir in a service of government - Alex Troush
Elixir in a service of government - Alex Troush
 

Último

Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
Evaluating the top large language models.pdf
Evaluating the top large language models.pdfEvaluating the top large language models.pdf
Evaluating the top large language models.pdfChristopherTHyatt
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 

Último (20)

Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Evaluating the top large language models.pdf
Evaluating the top large language models.pdfEvaluating the top large language models.pdf
Evaluating the top large language models.pdf
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 

Yurii Bodarev - OTP, Phoenix & Ecto: Three Pillars of Elixir

  • 1. OTP, Phoenix & Ecto: Three Pillars of Elixir Elixir Club Ternopil, 2017
  • 2. Erlang Functional Programming in Erlang www.futurelearn.com/courses/functional-programming-erlang/ Concurrent Programming in Erlang https://www.futurelearn.com/courses/concurrent-programming-erlang Learn You Some Erlang for great good! http://learnyousomeerlang.com/
  • 3. Overview 1. Processes & OTP 2. Phoenix Elixir web framework 3. Ecto database wrapper and language integrated query for Elixir
  • 4. Erlang/Elixir processes • All code runs inside processes • Processes are isolated from each other, run concurrent to one another and communicate via message passing (Actor model) • Processes are extremely lightweight in terms of memory and CPU and managed by Erlang VM • It is common to have tens or even hundreds of thousands of processes running simultaneously
  • 5. Spawning basic process iex> spawn fn -> 100 * 100 end #PID<0.94.0> iex> self() #PID<0.80.0>
  • 6. Sending and receiving messages iex> parent = self() #PID<0.80.0> iex> spawn fn -> send(parent, {:hello, self()}) end #PID<0.103.0> iex> receive do ...> {:hello, pid} -> "Got hello from #{inspect pid}" ...> {:other, _} -> "Something other" ...> end "Got hello from #PID<0.103.0>"
  • 7. Receive timeout iex> receive do ...> {:other, msg} -> msg ...> after ...> 1_000 -> "Nothing received after 1s" ...> end "Nothing received after 1s"
  • 8. Flush iex> send self(), :hello :hello iex> send self(), :world :world iex> flush() :hello :world :ok
  • 9. Linked processes: spawn_link iex> spawn_link fn -> raise "something bad happened" end 23:53:50.503 [error] Process #PID<0.93.0> raised an exception ** (RuntimeError) something bad happened :erlang.apply/2 ** (EXIT from #PID<0.91.0>) an exception was raised: ** (RuntimeError) something bad happened :erlang.apply/2
  • 10. Linked processes & “Failing fast” philosophy Parent process, which is the shell process, has received an EXIT signal from another process causing the parent process to terminate. Often we will link our processes to supervisors which will detect when a process dies and start a new process in its place. In Elixir we are actually fine with letting processes fail because we expect supervisors to properly restart our systems.
  • 11. Elixir: Task iex> task = Task.async(fn -> 100 * 100 end) %Task{owner: #PID<0.94.0>, pid: #PID<0.96.0>, ref: #Reference<0.0.1.139>} iex> res = Task.await(task) 10000
  • 12. State def start_link do Task.start_link(fn -> loop(%{}) end) end defp loop(map) do receive do {:get, key, caller} -> send caller, Map.get(map, key) loop(map) {:put, key, value} -> loop(Map.put(map, key, value)) end end
  • 14. Elixir: Agent iex> {:ok, agent} = Agent.start_link(fn -> %{} end) {:ok, #PID<0.88.0>} iex> Agent.update(agent, &Map.put(&1, :hello, "world")) :ok iex> Agent.get(agent, &Map.get(&1, :hello)) "world"
  • 15. Behaviours • Many of the processes have similar structures, they follow similar patterns • Behaviours provide a way to define a set of functions that have to be implemented by a module • You can think of behaviours like interfaces in OO languages
  • 16. Behaviours defmodule GenServer do @callback init(args :: term) :: {:ok, state} ... @callback handle_call(request :: term, from, state :: term) :: {:reply, reply, new_state} ... @callback handle_cast(request :: term, state :: term) :: {:noreply, new_state} ... ...
  • 17. Implementing behaviours ... # Callbacks def handle_call(:pop, _from, [h | t]) do {:reply, h, t} end def handle_cast({:push, item}, state) do {:noreply, [item | state]} end ...
  • 18. GenServer • “Generic servers” (processes) that encapsulate state, provide sync and async calls, support code reloading, and more. • The GenServer behaviour abstracts the common client-server interaction. Developers are only required to implement the callbacks and functionality they are interested in. • A GenServer is a process like any other Elixir process and it can be used to keep state, execute code asynchronously and so on.
  • 19. GenServer example defmodule Stack do use GenServer # Callbacks def handle_call(:pop, _from, [h | t]) do {:reply, h, t} end def handle_cast({:push, item}, state) do {:noreply, [item | state]} end end
  • 20. GenServer example iex> {:ok, pid} = GenServer.start_link(Stack, [:hello]) iex> GenServer.call(pid, :pop) :hello iex> GenServer.cast(pid, {:push, :world}) :ok iex>GenServer.call(pid, :pop) :world
  • 21. GenServer cheatsheet Benjamin Tan Wei Hao https://github.com/benjamintanweihao/elixir-cheatsheets
  • 22. Supervision Trees • Supervision trees are a nice way to structure fault-tolerant applications. • Process structuring model based on the idea of workers and supervisors. S W S W S W
  • 23. Supervision Trees • Workers are processes that perform computations, that is, they do the actual work. • Supervisors are processes that monitor the behaviour of workers. A supervisor can restart a worker if something goes wrong. • The supervision strategy dictates what happens when one of the children crashes.
  • 24. Supervisor • A behaviour module for implementing supervision functionality. • A supervisor is a process which supervises other processes, which we refer to as child processes.
  • 25. Supervisor module defmodule MyApp.Supervisor do use Supervisor def start_link do Supervisor.start_link(__MODULE__, []) end def init([]) do children = [ worker(Stack, [[:hello]]) ] supervise(children, strategy: :one_for_one) end end
  • 26. Supervisor Cheat Sheet Benjamin Tan Wei Hao https://github.com/benjamintanweihao/elixir-cheatsheets
  • 27. Application behaviour • In Erlang/OTP, an application is a component implementing some specific functionality, that can be started and stopped as a unit • Mix is responsible for compiling your source code and generating your application .app file in Elixir. • Mix is also responsible for configuring, starting and stopping your application and its dependencies (mix.exs). • .app holds our application definition
  • 28. Application callback defmodule MyApp do use Application def start(_type, _args) do MyApp.Supervisor.start_link() end end
  • 29. Application project mix new hello_world --sup hello_world |-- README.md |-- config | `-- config.exs |-- lib | |-- hello_world | | `-- application.ex | `-- hello_world.ex |-- mix.exs `-- test |-- hello_world_test.exs `-- test_helper.exs
  • 30. Application project: configuration hello_worldmix.exs def application do # Specify extra applications you'll use from Erlang/Elixir [extra_applications: [:logger], mod: {HelloWorld.Application, []}] end
  • 31. Application project: callback module hello_worldlibhello_worldapplication.ex defmodule HelloWorld.Application do ... def start(_type, _args) do import Supervisor.Spec, warn: false children = [] opts = [strategy: :one_for_one, name: HelloWorld.Supervisor] Supervisor.start_link(children, opts) end end
  • 32. Umbrella projects mix new hello_umbrella --umbrella hello_umbrella |-- README.md |-- apps |-- config | `-- config.exs `-- mix.exs
  • 33. Umbrella projects: configuration ... def project do [apps_path: "apps", build_embedded: Mix.env == :prod, start_permanent: Mix.env == :prod, deps: deps()] end ...
  • 34. In umbrella dependencies Mix supports an easy mechanism to make one umbrella child depend on another. ... defp deps do [{:hello_world, in_umbrella: true}] end ...
  • 35. GenStage & Flow Announcing GenStage http://elixir-lang.org/blog/2016/07/14/announcing-genstage/ GenStage and Flow - Jose Valim | Elixir Club 5 https://www.youtube.com/watch?v=IUrfcBwkm7w https://hex.pm/packages/gen_stage
  • 36. GenStage is a new Elixir behaviour for exchanging events with back-pressure between Elixir processes producer producer consumer producer consumer consumer
  • 37. Flow: concurrent data processing def process_flow(path_to_file) do path_to_file |> File.stream!() |> Flow.from_enumerable() |> Flow.flat_map(&String.split/1) |> Flow.map(&String.replace(&1, ~r/W/u, "")) |> Flow.filter_map(fn w -> w != "" end, &String.downcase/1) |> Flow.partition() |> Flow.reduce(fn -> %{} end, fn word, map -> Map.update(map, word, 1, &(&1 + 1)) end) |> Enum.into(%{}) end
  • 38. Flow: concurrent data processing def process_flow(path_to_file) do path_to_file |> File.stream!() |> Flow.from_enumerable() |> Flow.flat_map(&String.split/1) |> Flow.map(&String.replace(&1, ~r/W/u, "")) |> Flow.filter_map(fn w -> w != "" end, &String.downcase/1) |> Flow.partition() |> Flow.reduce(fn -> %{} end, fn word, map -> Map.update(map, word, 1, &(&1 + 1)) end) |> Enum.into(%{}) end P PC PC DemandDispatcher PartitionDispatcher PC PC C CReducers %{} %{}
  • 39. Flow P PC PC PC PC C C %{} %{} "The Project Gutenberg EBook of The Complete Works of William Shakespeare, byn" "William Shakespearen" "The", "Project", "Gutenberg", "EBook", "of", "The", "Complete", "Works", "of", "William", "Shakespeare,", "by" "William", "Shakespeare" "the", "project", "of", “the", "william", "of", "by ", "william" "gutenberg", "ebook", "complete", "shakespeare", "works", "shakespeare"
  • 40. Flow Experimental.Flow, Yurii Bodarev at KyivElixirMeetup 3.1 https://www.youtube.com/watch?v=XhUeSUFF06w https://github.com/yuriibodarev/elixir_flow
  • 41. Phoenix Framework • Phoenix is a web development framework written in Elixir which implements the server-side MVC pattern • Phoenix provides the best of both worlds - high developer productivity and high application performance • Phoenix is actually the top layer of a multi-layer system designed to be modular and flexible. The other layers include Plug, and Ecto • The Erlang HTTP server, Cowboy, acts as the foundation for Plug and Phoenix
  • 42. Phoenix Framework • The Plug • The Endpoint • The Router • Controllers • Actions • Views • Templates • Channels
  • 43. The Plug • Plug is a specification for constructing composable modules to build web applications. • Plugs are reusable modules or functions built to that specification. • They provide discrete behaviors - like request header parsing or logging. • Because the Plug API is small and consistent, plugs can be defined and executed in a set order, like a pipeline. • Core Phoenix components like Endpoints, Routers, and Controllers are all just Plugs internally
  • 44. Module Plug example defmodule Example.HelloWorldPlug do import Plug.Conn def init(options), do: options def call(conn, _opts) do conn |> put_resp_content_type("text/plain") |> send_resp(200, "Hello World!") end end %Plug.Conn{…}
  • 45. Plug pipelines pipeline :browser do plug :accepts, ["html"] plug :fetch_session plug :fetch_flash plug :protect_from_forgery plug :put_secure_browser_headers end
  • 46. Module Plug example ... @locales ["en", "fr", "de"] def init(default), do: default def call(%Plug.Conn{params: %{"locale" => loc}} = conn, _default) when loc in @locales do assign(conn, :locale, loc) end def call(conn, default), do: assign(conn, :locale, default) ...
  • 47. Adding Plug to the pipeline pipeline :browser do plug :accepts, ["html"] plug :fetch_session plug :fetch_flash plug :protect_from_forgery plug :put_secure_browser_headers plug PhoenixApp.Plugs.Locale, "en" end
  • 48. The Endpoint • provides a wrapper for starting and stopping the endpoint as part of a supervision tree; • handles all aspects of requests up until the point where the router takes over • to define an initial plug pipeline where requests are sent through; • to host web specific configuration for your application. • dispatches requests into a designated router
  • 49. The Endpoint phoenix_applibphoenix_appwebendpoint.ex defmodule PhoenixApp.Web.Endpoint do use Phoenix.Endpoint, otp_app: :phoenix_app # plug ... # plug ... plug PhoenixApp.Web.Router end
  • 50. Starting Endpoint phoenix_applibphoenix_appapplication.ex ... children = [ # Start the Ecto repository supervisor(PhoenixApp.Repo, []), # Start the endpoint when the application starts supervisor(PhoenixApp.Web.Endpoint, []) ] opts = [strategy: :one_for_one, name: PhoenixApp.Supervisor] Supervisor.start_link(children, opts) ...
  • 51. The Router • parses incoming requests and dispatches them to the correct controller/action, passing parameters as needed • provides helpers to generate route paths or urls to resources • defines named pipelines through which we may pass our requests
  • 52. The Router phoenix_applibphoenix_appwebrouter.ex ... pipeline :browser do plug :accepts, ["html"] ... plug :put_secure_browser_headers end scope "/", PhoenixApp.Web do pipe_through :browser # Use the default browser stack get "/", PageController, :index end ...
  • 53. Controllers & Actions Controllers provide functions, called actions, to handle requests Actions • prepare data and pass it into views • invoke rendering via views • perform redirects
  • 54. Controller get "/pages/:id", PageController, :show phoenix_applibphoenix_appwebcontrollerspage_controller.ex defmodule PhoenixApp.Web.PageController do use PhoenixApp.Web, :controller def show(conn, %{"id" => id}) do user = Accounts.get_user(id) render(conn, "show.html", user: user) end end
  • 55. webweb.ex use PhoenixApp.Web, :controller phoenix_applibphoenix_appwebweb.ex ... def controller do quote do use Phoenix.Controller, namespace: PhoenixApp.Web import Plug.Conn import PhoenixApp.Web.Router.Helpers import PhoenixApp.Web.Gettext end end ...
  • 56. Views • Defines the view layer of a Phoenix application • Render templates • Define helper functions, available in templates, to decorate data for presentation
  • 57. Rendering Templates Phoenix assumes a strong naming convention from controllers to views to the templates they render. The PageController requires a PageView to render templates in the webtemplatespage directory. phoenix_applibphoenix_appwebweb.ex ... def view do quote do use Phoenix.View, root: "lib/phoenix_app/web/templates", namespace: PhoenixApp.Web ...
  • 58. Rendering Templates phoenix_applibphoenix_appwebviewspage_view.ex defmodule PhoenixApp.Web.PageView do use PhoenixApp.Web, :view end Phoenix.View will automatically load all templates at “phoenix_applibphoenix_appwebtemplatespage” and include them in the PhoenixApp.Web.PageView
  • 59. Rendering JSON def render("index.json", %{pages: pages}) do %{data: render_many(pages, PhoenixApp.PageView, "page.json")} end def render("show.json", %{page: page}) do %{data: render_one(page, PhoenixApp.PageView, "page.json")} end def render("page.json", %{page: page}) do %{title: page.title} end
  • 60. Templates foo.html.eex • templates are precompiled and fast • template name - is the name of the template as given by the user, without the template engine extension, for example: “foo.html” • template path - is the complete path of the template in the filesystem, for example, “path/to/foo.html.eex” • template root - the directory where templates are defined • template engine (EEx)- a module that receives a template path and transforms its source code into Elixir quoted expressions.
  • 61. Template examples Hello <%= @name %> <h3>Keys for the conn Struct</h3> <%= for key <- connection_keys @conn do %> <p><%= key %></p> <% end %> function that returns List of keys
  • 62. Channels • manage sockets for easy real-time communication • are analogous to controllers except that they allow bi-directional communication with persistent connections • Every time you join a channel, you need to choose which particular topic you want to listen to. The topic is just an identifier, but by convention it is often made of two parts: "topic:subtopic".
  • 63. Channel endpoint phoenix_applibphoenix_appwebendpoint.ex socket "/socket", PhoenixApp.Web.UserSocket phoenix_applibphoenix_appwebchannelsuser_socket.ex channel "room:*", PhoenixApp.Web.RoomChannel Any topic coming into the router with the "room:" prefix would dispatch to MyApp.RoomChannel
  • 64. Joining Channels defmodule PhoenixApp.Web.RoomChannel do use Phoenix.Channel def join("room:lobby", _message, socket) do {:ok, socket} end def join("room:" <> _private_room_id, _params, _socket) do {:error, %{reason: "unauthorized"}} end end
  • 65. JS phoenix_appassetsjssocket.js ... socket.connect() // Now that you are connected, you can join channels with a topic: let channel = socket.channel("topic:subtopic", {}) channel.join() .receive("ok", resp => { console.log("Joined successfully", resp) }) .receive("error", resp => { console.log("Unable to join", resp) })
  • 66. JS … channel.push("new_msg", {body: “Hello world!”}) … … channel.on("new_msg", payload => { … }) …
  • 67. Incoming Events We handle incoming events with handle_in/3. We can pattern match on the event names, like “new_msg” def handle_in("new_msg", %{"body" => body}, socket) do broadcast! socket, "new_msg", %{body: body} {:noreply, socket} end
  • 68. Outgoing Events: default implementation def handle_out("new_msg", payload, socket) do push socket, "new_msg", payload {:noreply, socket} end
  • 69. Intercepting Outgoing Events intercept ["smth_important"] def handle_out("smth_important", msg, socket) do if … do {:noreply, socket} else push socket, " smth_important", msg {:noreply, socket} end end
  • 70. Phoenix Framework 1.3 v1.3.0-rc.1 https://hex.pm/packages/phoenix phx.new project generator mix archive.install https://github.com/phoenixframework/archives/raw/master/phx_new.ez
  • 71. Phoenix Framework 1.3 Lonestar ElixirConf 2017- KEYNOTE: Phoenix 1.3 by Chris McCord https://www.youtube.com/watch?v=tMO28ar0lW8 Phoenix v1.3.0-rc.0 released @ ElixirForum https://elixirforum.com/t/phoenix-v1-3-0-rc-0-released/3947 Upcoming book “Programming Phoenix 1.3” @ ElixirForum https://elixirforum.com/t/programming-phoenix-1-3/2469
  • 72.
  • 73. 1.2: mix phoenix.new phoenix_old phoenix_old |-- config |-- lib | `-- phoenix_old |-- priv |-- test `-- web |-- channels |-- controllers |-- models |-- static |-- templates `-- views
  • 74. 1.3: mix phx.new phoenix_new phoenix_new |-- assets |-- config |-- lib | `-- phoenix_new | `-- web | |-- channels | |-- controllers | |-- templates | `-- views |-- priv `-- test
  • 75. 1.3: mix phx.new phoenix --umbrella phoenix_umbrella |-- apps | |-- phoenix … | `-- phoenix_web phoenix_umbrellaappsphoenix_webmix.exs ... {:phoenix, in_umbrella: true}, ...
  • 76. Web Namespace defmodule PhoenixApp.Web.PageController do use PhoenixApp.Web, :controller def index(conn, _params) do render conn, "index.html" end end
  • 77. Context 1.2: mix phoenix.gen.json User users email:string Repo.get(User, id) 1.3: mix phx.gen.json Accounts User users email:string Accounts.get_user(2) iex> %User{email: oscar@swanros.com} Accounts.create_user(params) iex> {:ok, new_user}
  • 78. 1.2: Models `-- web |-- channels |-- controllers |-- models | |-- comment.ex | |-- invoice.ex | |-- order.ex | |-- payment.ex | |-- post.ex | `-- user.ex |-- static |-- templates `-- views
  • 79. 1.3: Context |-- lib | `-- phoenix_new | |-- blog | | |-- blog.ex | | |-- comment.ex | | `-- post.ex | |-- sales | | |-- order.ex | | |-- payment.ex | | `-- sales.ex | `-- web | |-- channels
  • 80. The boundary for the Sales system. libphoenix_newsalessales.ex defmodule PhoenixNew.Sales do def list_orders do Repo.all(Order) end def get_order!(id), do: Repo.get!(Order, id) def create_order(attrs %{}) do %Order{} |> order_changeset(attrs) |> Repo.insert() end ...
  • 81. Action Fallback On Phoenix 1.2, every controller needed to return a valid %Plug.Conn{} for every request. Otherwise, an exception would rise. On Phoenix 1.3 we can register the plug to call as a fallback to the controller action. If the controller action fails to return a %Plug.Conn{}, the provided plug will be called and receive the controller’s %Plug.Conn{} as it was before the action was invoked along with the value returned from the controller action.
  • 82. 1.2: Controller Action phoenix_oldwebcontrollerspost_controller.ex case Repo.insert(changeset) do {:ok, post} -> conn |> put_status(:created) |> put_resp_header("location", post_path(conn, :show, post)) |> render("show.json", post: post) {:error, changeset} -> conn |> put_status(:unprocessable_entity) |> render(PhoenixOld.ChangesetView, "error.json", changeset: changeset) end
  • 83. 1.3: Controller Action phoenix_newlibphoenix_newwebcontrollerspost_controller.ex def create(conn, %{"post" => post_params}) do with {:ok, %Post{} = post} <- Blog.create_post(post_params) do conn |> put_status(:created) |> put_resp_header("location", post_path(conn, :show, post)) |> render("show.json", post: post) end end
  • 84. 1.3 Action Fallback phoenix_newlibphoenix_newwebcontrollersfallback_controller.ex def call(conn, {:error, %Ecto.Changeset{} = changeset}) do conn |> put_status(:unprocessable_entity) |> render(PhoenixNew.Web.ChangesetView, "error.json", changeset: changeset) end
  • 85. Ecto Domain specific language for writing queries and interacting with databases in Elixir. pages.plataformatec.com.br/ebook-whats-new-in-ecto-2-0
  • 86. Ecto Ecto is split into 4 main components: • Ecto.Repo - repositories are wrappers around the data store. • Ecto.Schema - schemas are used to map any data source into an Elixir struct. • Ecto.Changeset - allow developers to filter, cast, and validate changes before we apply them to the data. • Ecto.Query - written in Elixir syntax, queries are used to retrieve information from a given repository.
  • 87. Repositories Via the repository, we can create, update, destroy and query existing database entries.
  • 88. Repositories Ecto.Repo is a wrapper around the database. We can define a repository as follows: defmodule Blog.Repo do use Ecto.Repo, otp_app: :blog end
  • 89. Repositories A repository needs an adapter and credentials to communicate to the database. Configuration for the Repo usually defined in your config/config.exs: config :blog, Blog.Repo, adapter: Ecto.Adapters.Postgres, database: "blog_repo", username: "postgres", password: "postgres", hostname: "localhost"
  • 90. Repositories Each repository in Ecto defines a start_link/0. Usually this function is invoked as part of your application supervision tree: def start(_type, _args) do import Supervisor.Spec, warn: false children = [ worker(Blog.Repo, []), ] opts = [strategy: :one_for_one, name: Blog.Supervisor] Supervisor.start_link(children, opts) end
  • 91. Schema Schemas allows developers to define the shape of their data. defmodule Blog.User do use Ecto.Schema schema "users" do field :name, :string field :reputation, :integer, default: 0 has_many :posts, Blog.Post, on_delete: :delete_all timestamps end end
  • 92. Schema By defining a schema, Ecto automatically defines a struct: iex> user = %Blog.User{name: "Bill"} %Blog.User{__meta__: #Ecto.Schema.Metadata<:built, "users">, id: nil, inserted_at: nil, name: "Bill"}, posts: #Ecto.Association.NotLoaded<association :posts is not loaded>, reputation: 0, updated_at: nil}
  • 93. Schema Using Schema we can interact with a repository: iex> user = %Blog.User{name: "Bill", reputation: 10} %Blog.User{…} iex> Blog.Repo.insert!(user) %Blog.User{__meta__: #Ecto.Schema.Metadata<:loaded, "users">, id: 6, inserted_at: ~N[2016-12-13 16:16:35.983000], name: "Bill", posts: #Ecto.Association.NotLoaded<association :posts is not loaded>, reputation: 10, updated_at: ~N[2016-12-13 16:16:36.001000]}
  • 94. Schema # Get the user back iex> newuser = Blog.Repo.get(Blog.User, 6) iex> newuser.id 6 # Delete it iex> Blog.Repo.delete(newuser) {:ok, %Blog.User{…, id: 6,…}}
  • 95. Schema We can use pattern matching on Structs created with Schemas: iex> %{name: name, reputation: reputation} = ...> Blog.Repo.get(Blog.User, 1) iex> name "Alex" iex> reputation 144
  • 96. Changesets We can add changesets to our schemas to validate changes before we apply them to the data: def changeset(user, params %{}) do user |> cast(params, [:name, :reputation]) |> validate_required([:name, :reputation]) |> validate_inclusion(:reputation, -999..999) end
  • 97. Changesets iex> alina = %Blog.User{name: "Alina"} iex> correct_changeset = Blog.User.changeset(alina, %{reputation: 55}) #Ecto.Changeset<action: nil, changes: %{reputation: 55}, errors: [], data: #Blog.User<>, valid?: true> iex> invalid_changeset = Blog.User.changeset(alina, %{reputation: 1055}) #Ecto.Changeset<action: nil, changes: %{reputation: 1055}, errors: [reputation: {"is invalid", [validation: :inclusion]}], data: #Blog.User<>, valid?: false>
  • 98. Changeset with Repository functions iex> valid_changeset.valid? true iex> Blog.Repo.insert(valid_changeset) {:ok, %Blog.User{…, id: 7, …}}
  • 99. Changeset with Repository functions iex> invalid_changeset.valid? false iex> Blog.Repo.insert(invalid_changeset) {:error, #Ecto.Changeset<action: :insert, changes: %{reputation: 1055}, errors: [reputation: {"is invalid", [validation: :inclusion]}], data: #Blog.User<>, valid?: false>}
  • 100. Changeset with Repository functions case Blog.Repo.update(changeset) do {:ok, user} -> # user updated {:error, changeset} -> # an error occurred end
  • 101. We can provide different changeset functions for different use cases def registration_changeset(user, params) do # Changeset on create end def update_changeset(user, params) do # Changeset on update end
  • 102. Query Ecto allows you to write queries in Elixir and send them to the repository, which translates them to the underlying database.
  • 103. Query using predefined Schema # Query using predefined Schema query = from u in User, where: u.reputation > 35, select: u # Returns %User{} structs matching the query Repo.all(query) [%Blog.User{…, id: 2, …, name: "Bender", …, reputation: 42, …}, %Blog.User{…, id: 1, …, name: "Alex", …, reputation: 144, …}]
  • 104. Direct query with “users” table # Directly querying the “users” table query = from u in "users", where: u.reputation > 30, select: %{name: u.name, reputation: u.reputation} # Returns maps as defined in select Repo.all(query) [%{name: "Bender", reputation: 42}, %{name: "Alex", reputation: 144}]
  • 105. External values in Queries # ^ operator min = 33 query = from u in "users", where: u.reputation > ^min, select: u.name # casting mins = "33" query = from u in "users", where: u.reputation > type(^mins, :integer), select: u.name
  • 106. External values in Queries If the query is made against Schema than Ecto will automatically cast external value min = "35" Repo.all(from u in User, where: u.reputation > ^min) You can also skip Select to retrieve all fields specified in the Schema
  • 107. Ecto Multi Ecto.Multi is a data structure for grouping multiple Repo operations in a single database transaction. def reset(account, params) do Multi.new |> Multi.update(:account, Account.password_reset_changeset(account, params)) |> Multi.insert(:log, Log.password_reset_changeset(account, params)) |> Multi.delete_all(:sessions, Ecto.assoc(account, :sessions)) end Repo.transaction(PasswordManager.reset(account, params))
  • 108. Ecto Multi case result do {:ok, %{account: account, log: log, sessions: sessions}} -> # We can access results under keys we used # for naming the operations. {:error, failed_operation, failed_value, changes_so_far} -> # One of the operations failed. # We can access the operation's failure value (changeset) # Successful operations would have been rolled back. end
  • 109. Books Saša Jurić “Elixir in Action” https://www.manning.com/books/elixir-in-action Benjamin Tan Wei Hao “The Little Elixir & OTP Guidebook” https://www.manning.com/books/the-little-elixir-and-otp-guidebook New! Lance Halvorsen “Functional Web Development with Elixir, OTP, and Phoenix” https://pragprog.com/book/lhelph/functional-web-development-with-elixir-otp-and-phoenix Chris McCord “Programming Phoenix” (1.2 -> 1.3) https://pragprog.com/book/phoenix/programming-phoenix “What's new in Ecto 2.0” http://pages.plataformatec.com.br/ebook-whats-new-in-ecto-2-0