Créer une application Phoenix pas à pas

Notre objectif est de créer notre premiere page Html avec Phoenix Elixir. Cette première page doit nous permettre de découvrir l’architecture de Phoenix et de voir comment s’organise un projet Phoenix.

Cette premiere page HTML avec Phoenix nous permettra de prendre en main Phoenix avant de réaliser des applications complètes. Nous allons utiliser le livre Programming Phoenix>1.4 pour réaliser cette première page.

Installer l’environnement de développement

Nous allons vérifier que notre environnement de développemetn est prêt.

Version d’Elixir compatible avec la version d’Erlang :

C:\Users\broussel>elixir -v
Erlang/OTP 26 [erts-14.0.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit:ns]

Elixir 1.15.5 (compiled with Erlang/OTP 26)

C:\Users\broussel>

vérification de la version du package manager Elixir appelé Hex :

C:\Users\broussel>mix local.hex
Found existing entry: c:/Users/broussel/.mix/archives/hex-2.0.6
Are you sure you want to replace it with "https://builds.hex.pm/installs/1.14.0/hex-2.0.6.ez"? [Yn] n

C:\Users\broussel>

Nous avons déjà la dernière version de Hex installée.

Vérification de la version de Postgres :

C:\Users\broussel>psql --version
psql (PostgreSQL) 15.4

C:\Users\broussel>
C:\Users\broussel>psql -U postgres
Mot de passe pour l'utilisateur postgres :
psql (15.4)
Attention : l'encodage console (850) diffère de l'encodage Windows (1252).
            Les caractères 8 bits peuvent ne pas fonctionner correctement.
            Voir la section « Notes aux utilisateurs de Windows » de la page
            référence de psql pour les détails.
Saisissez « help » pour l'aide.

postgres=# \du
                                              Liste des r¶les
 Nom du r¶le |                                    Attributs                                    | Membre de
-------------+---------------------------------------------------------------------------------+-----------
 postgres    | Superutilisateur, CrÚer un r¶le, CrÚer une base, RÚplication, Contournement RLS | {}


postgres=# \q

C:\Users\broussel>

Nous avons bien la base de données Postgres installée avec un utilisateur postgres/postgres.

Vérification de la version de node.js :

C:\Users\broussel>node --version
'node' n'est pas reconnu en tant que commande interne
ou externe, un programme exécutable ou un fichier de commandes.

C:\Users\broussel>

Pour installer node, nous rédigeons un article montrant comment installer NodeJS et NPM sur Windows.

Afin que l’installation de Node soit prise en compte, nous devons relancer le shell.

C:\Users\broussel>node -v
v18.17.1

C:\Users\broussel>npm -v
9.6.7

C:\Users\broussel>

Vérification de l’installation de Phoenix

C:\Users\broussel>mix phx.new -v
Phoenix installer v1.7.7

C:\Users\broussel>

L’environnement de développement est maintenant prêt sur Windows. Nous utiliserons VS Code pour le développement. Dans un article précédent, nous avons montré comment installer VS Code pour développer avec Elixir.

Créer un projet de base avec Phoenix

Nous créons un projet hello avec le script mix phx.new. Le projet sera créé dans notre répertoire :

  • C:\CarbonX1\Phoenix\Projets\
C:\Users\broussel>cd C:\CarbonX1\Phoenix\Projets

C:\CarbonX1\Phoenix\Projets>mix phx.new hello
* creating hello/config/config.exs
* creating hello/config/dev.exs
* creating hello/config/prod.exs
* creating hello/config/runtime.exs
* creating hello/config/test.exs
* creating hello/lib/hello/application.ex
* creating hello/lib/hello.ex
* creating hello/lib/hello_web/controllers/error_json.ex
* creating hello/lib/hello_web/endpoint.ex
* creating hello/lib/hello_web/router.ex
* creating hello/lib/hello_web/telemetry.ex
* creating hello/lib/hello_web.ex
* creating hello/mix.exs
* creating hello/README.md
* creating hello/.formatter.exs
* creating hello/.gitignore
* creating hello/test/support/conn_case.ex
* creating hello/test/test_helper.exs
* creating hello/test/hello_web/controllers/error_json_test.exs
* creating hello/lib/hello/repo.ex
* creating hello/priv/repo/migrations/.formatter.exs
* creating hello/priv/repo/seeds.exs
* creating hello/test/support/data_case.ex
* creating hello/lib/hello_web/controllers/error_html.ex
* creating hello/test/hello_web/controllers/error_html_test.exs
* creating hello/lib/hello_web/components/core_components.ex
* creating hello/lib/hello_web/controllers/page_controller.ex
* creating hello/lib/hello_web/controllers/page_html.ex
* creating hello/lib/hello_web/controllers/page_html/home.html.heex
* creating hello/test/hello_web/controllers/page_controller_test.exs
* creating hello/lib/hello_web/components/layouts/root.html.heex
* creating hello/lib/hello_web/components/layouts/app.html.heex
* creating hello/lib/hello_web/components/layouts.ex
* creating hello/priv/static/images/logo.svg
* creating hello/lib/hello/mailer.ex
* creating hello/lib/hello_web/gettext.ex
* creating hello/priv/gettext/en/LC_MESSAGES/errors.po
* creating hello/priv/gettext/errors.pot
* creating hello/priv/static/robots.txt
* creating hello/priv/static/favicon.ico
* creating hello/assets/js/app.js
* creating hello/assets/vendor/topbar.js
* creating hello/assets/css/app.css
* creating hello/assets/tailwind.config.js
* creating hello/assets/vendor/heroicons/LICENSE.md
* creating hello/assets/vendor/heroicons/UPGRADE.md
* extracting hello/assets/vendor/heroicons/optimized

Fetch and install dependencies? [Yn] Y
* running mix deps.get
* running mix assets.setup
* running mix deps.compile

We are almost there! The following steps are missing:

    $ cd hello

Then configure your database in config/dev.exs and run:

    $ mix ecto.create

Start your Phoenix app with:

    $ mix phx.server

You can also run your app inside IEx (Interactive Elixir) as:

    $ iex -S mix phx.server


C:\CarbonX1\Phoenix\Projets>

Le script a créé un projet hello dans notre dossier projets :

Créer une application Phoenix pas à pas#1-création du projet de base par le script mix-phx_new
Créer une application Phoenix pas à pas#1-création du projet de base par le script mix-phx_new

Nous suivons les instructions consistant à créer la base de données et à lancer lle serveur permettant de voir notre application dans le navigateur :

C:\CarbonX1\Phoenix\Projets>cd hello

C:\CarbonX1\Phoenix\Projets\hello>mix ecto.create
Compiling 15 files (.ex)
Generated hello app
The database for Hello.Repo has been created

C:\CarbonX1\Phoenix\Projets\hello>mix phx.server
[warning] Phoenix is unable to create symlinks. Phoenix' code reloader will run considerably faster if symlinks are allowed. On Windows, the lack of symlinks may even cause empty assets to be served. Luckily, you can address this issue by starting your Windows terminal at least once with "Run as Administrator" and then running your Phoenix application.
[info] Running HelloWeb.Endpoint with cowboy 2.10.0 at 127.0.0.1:4000 (http)
[info] Access HelloWeb.Endpoint at http://localhost:4000
[watch] build finished, watching for changes...

Rebuilding...

Done in 374ms.
[info] GET /
[debug] Processing with HelloWeb.PageController.home/2
  Parameters: %{}
  Pipelines: [:browser]
[info] Sent 200 in 75ms

Puis nous ouvrons le navigateur en :

  • http://localhost:4000/

La page dans le navigateur :

Créer une application Phoenix pas à pas#2-la page du projet hello dans le navigateur
Créer une application Phoenix pas à pas#2-la page du projet hello dans le navigateur

Ajouter une page dans notre projet hello

Dans le projet hello que nous venons de générer, nous souhaitons ajouter une page afin de le personnaliser. Nous allons regarder comment ajouter une nouvelle page affichant pour l’instant un message « Hello World ! ».

Nous ouvrons VS Code avec le projet :

C:\Users\broussel>cd C:\CarbonX1\Phoenix\Projets\hello
C:\CarbonX1\Phoenix\Projets\hello>code .
C:\CarbonX1\Phoenix\Projets\hello>

VS Code s’ouvre avec le projet :

Créer une application Phoenix pas à pas#3-Le projet hello ouvert dans VS Code
Créer une application Phoenix pas à pas#3-Le projet hello ouvert dans VS Code

Pour créer une page nous devons :

  • créer une page template affichant « hello world ! », à placer dans le dossier : lib/hello_web/templates/
  • créer une view qui utilisera notre template, la view sera placée dans le dossier : lib/hello_web/views/
  • ajouter un contrôleur dans le dossier : lib/hello_web/controllers
  • déclarer notre contrôleur dans le routeur : lib/hello_web/router.ex

Nous allons créer dela en suivant le parcours de la requête provenant du navigateur.

Ajout du chemin dans Router.ex

Le routeur reçoit les requêtes en provenance du navigateur :

  • HELLO>lib>hello_web>router.ex

router.ex :

  scope "/", HelloWeb do
    pipe_through :browser

    get "/", PageController, :home
  end

Ici, scope attrape les requêtes dont l’url est ‘/’ et dirige la requête vers le controleur ‘PageController‘ en activant la fonction appelée ‘home‘ :

PageController.ex :

defmodule HelloWeb.PageController do
  use HelloWeb, :controller

  def home(conn, _params) do
    # The home page is often custom made,
    # so skip the default app layout.
    render(conn, :home, layout: false)
  end
end

Ajoutons notre route vers notre controleur ‘HelloController‘ et sa fonction ‘world

Nous plaçons notre nouvelle route ‘/hello’ juste au dessus de la route générale ‘/’.

router.ex :

  scope "/", HelloWeb do
    pipe_through :browser

	get "/hello", HelloController, :world
    get "/", PageController, :home
  end

L’ordre des routes a de l’importance car Elixir prend les routes dans l’ordre en s’arrêtant sur la première route qui match, donc ‘/hello’ doit être avant la route qui attrape tout : ‘/’.

Si nous activons le projet et demandons l’url ‘/hello’, nous avons un message qui s’affiche dans le navigateur et dans la console :

Créer une application Phoenix pas à pas#4-Le navigateur affiche l'erreur, il manque le Controller
Créer une application Phoenix pas à pas#4-Le navigateur affiche l’erreur, il manque le Controller

Dans la partie droite, nous avons la liste des étapes parcourues par la requête. Les lignes commençant avec un point orange sont des modules et fonctions de l’application que nous développons. En cliquant sur ces lignes nous accédons au code de l’application.

La console affiche le message d’erreur :

C:\CarbonX1\Phoenix\Projets\hello>mix phx.server
Compiling 1 file (.ex)
warning: HelloWeb.HelloController.init/1 is undefined (module HelloWeb.HelloController is not available or is yet to be defined)
  lib/hello_web/router.ex:20: HelloWeb.Router.__checks__/0

[warning] Phoenix is unable to create symlinks. Phoenix' code reloader will run considerably faster if symlinks are allowed. On Windows, the lack of symlinks may even cause empty assets to be served. Luckily, you can address this issue by starting your Windows terminal at least once with "Run as Administrator" and then running your Phoenix application.
[info] Running HelloWeb.Endpoint with cowboy 2.10.0 at 127.0.0.1:4000 (http)
[info] Access HelloWeb.Endpoint at http://localhost:4000
[watch] build finished, watching for changes...

Rebuilding...

Done in 378ms.
warning: HelloWeb.HelloController.init/1 is undefined (module HelloWeb.HelloController is not available or is yet to be defined)
  lib/hello_web/router.ex:20

[info] GET /
[debug] Processing with HelloWeb.PageController.home/2
  Parameters: %{}
  Pipelines: [:browser]
[info] Sent 200 in 280ms
warning: HelloWeb.HelloController.init/1 is undefined (module HelloWeb.HelloController is not available or is yet to be defined)
  lib/hello_web/router.ex:20

[info] GET /hello
[debug] Processing with HelloWeb.HelloController.world/2
  Parameters: %{}
  Pipelines: [:browser]
[info] Sent 500 in 206ms
[error] #PID<0.532.0> running Phoenix.Endpoint.SyncCodeReloadPlug (connection #PID<0.506.0>, stream id 2) terminated
Server: localhost:4000 (http)
Request: GET /hello
** (exit) an exception was raised:
    ** (UndefinedFunctionError) function HelloWeb.HelloController.init/1 is undefined (module HelloWeb.HelloController is not available)
        HelloWeb.HelloController.init(:world)
        (phoenix 1.7.7) lib/phoenix/router.ex:430: Phoenix.Router.__call__/5
        (hello 0.1.0) lib/hello_web/endpoint.ex:1: HelloWeb.Endpoint.plug_builder_call/2
        (hello 0.1.0) deps/plug/lib/plug/debugger.ex:136: HelloWeb.Endpoint."call (overridable 3)"/2
        (hello 0.1.0) lib/hello_web/endpoint.ex:1: HelloWeb.Endpoint.call/2
        (phoenix 1.7.7) lib/phoenix/endpoint/sync_code_reload_plug.ex:22: Phoenix.Endpoint.SyncCodeReloadPlug.do_call/4
        (plug_cowboy 2.6.1) lib/plug/cowboy/handler.ex:11: Plug.Cowboy.Handler.init/2
        (cowboy 2.10.0) c:/CarbonX1/Phoenix/Projets/hello/deps/cowboy/src/cowboy_handler.erl:37: :cowboy_handler.execute/2
        (cowboy 2.10.0) c:/CarbonX1/Phoenix/Projets/hello/deps/cowboy/src/cowboy_stream_h.erl:306: :cowboy_stream_h.execute/3
        (cowboy 2.10.0) c:/CarbonX1/Phoenix/Projets/hello/deps/cowboy/src/cowboy_stream_h.erl:295: :cowboy_stream_h.request_process/3
        (stdlib 5.0.2) proc_lib.erl:241: :proc_lib.init_p_do_apply/3

Le message nous indique bien que HelloController n’est pas défini ligne (35).

Ajout d’un Controlleur pour le projet : _controller.ex

Nous ajoutons le controleur HelloController dans le dossier qui regroupe l’ensemble des controleurs :

lib/hello_web/controllers/hello_controller.ex :

defmodule HelloWeb.HelloController do
  use HelloWeb, :controller

  def world(conn, _params) do
    # render(conn, :home, layout: false)
    render(conn, :world) # nous gardons le layout
  end
end

Comme nous avons laissé le navigateur ouvert, chaque enregistrement de modification dans VS Code relance automatiquement le chargement de la page. Nous voyons une nouvelle erreur s’afficher :

Créer une application Phoenix pas à pas#5-Le navigateur affiche l'erreur, le template world n'existe pas
Créer une application Phoenix pas à pas#5-Le navigateur affiche l’erreur, le template world n’existe pas

Ajout du Template dans le dossier controllers

Nous ne pouvons pas suivre à la lettre l’ouvrage Programming Phoenix >1.4 car la version 1.7 a changé la façon de faire :

Les pages templates sont rangées dorénavant dans le dossiert controllers.

lib/hello_web/controllers/hello_html.ex :

defmodule HelloWeb.HelloHTML do
  use HelloWeb, :html

  embed_templates "hello_html/*"
end

Puis nous créons le fichier

lib/hello_web/controllers/hello_html/world.html.heex :

<h1>Hello world!</h1>

Créer une application Phoenix pas à pas#6-La page Hello World créé en version 1_7 de Phoenix
Créer une application Phoenix pas à pas#6-La page Hello World créé en version 1_7 de Phoenix

Si nous supprimons le layout dans hello_controller.ex :

defmodule HelloWeb.HelloController do
  use HelloWeb, :controller

  def world(conn, _params) do
    # The home page is often custom made,
    # so skip the default app layout.
    # render(conn, :home, layout: false)
    # render(conn, :world)
    render(conn, :world, layout: false)
  end
end

La mise en page change et n’affiche plus le layout :

Créer une application Phoenix pas à pas#7-La page Hello World sans layout
Créer une application Phoenix pas à pas#7-La page Hello World sans layout

Le layout est défini dans le dossier components/layouts.

lib/hello_web/components/layouts/app.html.heex :

<header class="px-4 sm:px-6 lg:px-8">
  <div class="flex items-center justify-between border-b border-zinc-100 py-3 text-sm">
    <div class="flex items-center gap-4">
      <a href="/">
        <img src={~p"/images/logo.svg"} width="36" />
      </a>
      <p class="bg-brand/5 text-brand rounded-full px-2 font-medium leading-6">
        v<%= Application.spec(:phoenix, :vsn) %>
      </p>
    </div>
    <div class="flex items-center gap-4 font-semibold leading-6 text-zinc-900">
      <a href="https://twitter.com/elixirphoenix" class="hover:text-zinc-700">
        @elixirphoenix
      </a>
      <a href="https://github.com/phoenixframework/phoenix" class="hover:text-zinc-700">
        GitHub
      </a>
      <a
        href="https://hexdocs.pm/phoenix/overview.html"
        class="rounded-lg bg-zinc-100 px-2 py-1 hover:bg-zinc-200/80"
      >
        Get Started <span aria-hidden="true">&rarr;</span>
      </a>
    </div>
  </div>
</header>
<main class="px-4 py-20 sm:px-6 lg:px-8">
  <div class="mx-auto max-w-2xl">
    <.flash_group flash={@flash} />
    <%= @inner_content %>
  </div>
</main>

La structure du projet

Dans la version 1.7 de Phoenix l’emplacement des fichiers est modifiée par rapport à la version décrite dans l’ouvrage Programming Phoenix >1.4.

La structure du projet :

la page hello_controller.ex :

Créer une application Phoenix pas à pas#8-La structure du projet dans VS Code
Créer une application Phoenix pas à pas#8-La structure du projet dans VS Code

La page hello_html.ex :

Créer une application Phoenix pas à pas#9-La page hello_html dans VS Code
Créer une application Phoenix pas à pas#9-La page hello_html dans VS Code

Dans le dossier controllers, nous avons le dossier hello_html où nous plaçons le template world.html.heex

Créer une application Phoenix pas à pas#10-Structure de projet Programming Phoenix-v_1_4 p37
Créer une application Phoenix pas à pas#10-Structure de projet Programming Phoenix-v_1_4 p37

Les repertoires templates et views (1) sont deplacés dans controllers (2).

Conclusion,

nous avons créé une première page pour une application dans Phoenix Elixir. La réalisation passe par :

  • la déclaration de la page dans le router.ex dirigeant vers HelloController.ex,
  • la création du controller HelloController pour notre page,
  • le contenu de notre page dans world.html.heex.
  • Le controller HelloController trouve le dossier dans lequel est rangé la page world.html.heex dans HelloHtml.
Si vous avez aimé l'article vous êtes libre de le partager :-)

Laisser un commentaire