Skip to content

Commit 105a025

Browse files
committed
finish tutorial stoic
1 parent 9b184a2 commit 105a025

File tree

8 files changed

+645
-58
lines changed

8 files changed

+645
-58
lines changed

docs/elixir/apirest.html

Lines changed: 305 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ <h2 id="paso-2-crear-las-migraciones"><a class="anchor" href="#paso-2-crear-las-
358358
</div>
359359
<div class="paragraph">
360360
<p>El esquema es utilizado por el contexto de <em>Phoenix</em>, también conocido
361-
como dominio (en Domain Driven Desing) o reglas de negocio. Es un archivo utilizado como capa
361+
como dominio (en Domain Driven Desing), modelo (en MVC) o reglas de negocio (en capas). Es un archivo utilizado como capa
362362
superior al esquema y que permite realizar operaciones comunes como consultas, modificaciones o inserciones.
363363
Esta ubicado en <code>lib/stoic_quotes/quotes.ex</code>. Si bien tiene varias funciones, es recomendable subdividir
364364
este contexto en archivos con operaciones de lectura y escritura para evitar que se convierta en un archivo demasiado grande,
@@ -658,6 +658,21 @@ <h2 id="paso-4-añadir-registros-a-la-base-de-datos"><a class="anchor" href="#pa
658658
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ mix run priv/repo/seeds.exs</code></pre>
659659
</div>
660660
</div>
661+
<div class="admonitionblock note">
662+
<table>
663+
<tr>
664+
<td class="icon">
665+
<i class="fa icon-note" title="Note"></i>
666+
</td>
667+
<td class="content">
668+
<div class="paragraph">
669+
<p>Los comandos de <code>mix</code> deben ser ejecutados en el mismo lugar donde esta presente el archivo <code>mix.exs</code>.
670+
Podemos verificar usando los comandos <code>ls</code> y <code>pwd</code>.</p>
671+
</div>
672+
</td>
673+
</tr>
674+
</table>
675+
</div>
661676
<div class="paragraph">
662677
<p>Si todo sale bien podremos verificar en <em>DBeaver</em> que los datos están presentes.</p>
663678
</div>
@@ -677,6 +692,295 @@ <h2 id="paso-4-añadir-registros-a-la-base-de-datos"><a class="anchor" href="#pa
677692
</div>
678693
</div>
679694
</div>
695+
<div class="sect1">
696+
<h2 id="paso-5-construcción-de-rutas"><a class="anchor" href="#paso-5-construcción-de-rutas"></a>Paso 5: Construcción de Rutas</h2>
697+
<div class="sectionbody">
698+
<div class="paragraph">
699+
<p>Esta API tendrá dos rutas principales:</p>
700+
</div>
701+
<div class="ulist">
702+
<ul>
703+
<li>
704+
<p><code>/api/quotes/</code>: Lista todas las citas disponibles.</p>
705+
</li>
706+
<li>
707+
<p><code>/api/quotes/random</code>: Lista una cita aleatoria.</p>
708+
</li>
709+
</ul>
710+
</div>
711+
<div class="paragraph">
712+
<p>Para esto se debe editar el <code>router</code> ubicado en <code>lib/stoic_quotes_web/router.ex</code>.</p>
713+
</div>
714+
<div class="listingblock">
715+
<div class="content">
716+
<pre class="highlightjs highlight"><code class="language-elixir hljs" data-lang="elixir">scope "/api", StoicQuotesWeb do
717+
pipe_through :api
718+
get "/quotes", QuotesController, :index
719+
get "/quotes/random", QuotesController, :show
720+
end</code></pre>
721+
</div>
722+
</div>
723+
<div class="paragraph">
724+
<p>El siguiente código nos indica lo siguiente:</p>
725+
</div>
726+
<div class="ulist">
727+
<ul>
728+
<li>
729+
<p><code>scope</code>: Es una macro que acepta como parámetro la ruta base (endpoint) y el módulo base para buscar los controladores.</p>
730+
</li>
731+
</ul>
732+
</div>
733+
<div class="listingblock">
734+
<div class="content">
735+
<pre class="highlightjs highlight"><code class="language-elixir hljs" data-lang="elixir"># las rutas tendrán como base /api y como base el módulo StoicQuotesWeb
736+
scope "/api", StoicQuotesWeb do</code></pre>
737+
</div>
738+
</div>
739+
<div class="paragraph">
740+
<p>El siguiente código nos indica lo siguiente:</p>
741+
</div>
742+
<div class="ulist">
743+
<ul>
744+
<li>
745+
<p><code>pipe_through</code>: Es una macro que gatillará lo definido en el pipeline <code>:api</code> para todos los requests que cumplan el <code>scope "/api"</code>.</p>
746+
</li>
747+
</ul>
748+
</div>
749+
<div class="listingblock">
750+
<div class="content">
751+
<pre class="highlightjs highlight"><code class="language-elixir hljs" data-lang="elixir">pipe_through :api</code></pre>
752+
</div>
753+
</div>
754+
<div class="paragraph">
755+
<p>El pipeline de <code>:api</code> establece un pipeline para aceptar requests del formato <code>json</code>,
756+
se define como lo siguiente:</p>
757+
</div>
758+
<div class="listingblock">
759+
<div class="content">
760+
<pre class="highlightjs highlight"><code class="language-elixir hljs" data-lang="elixir">pipeline :api do
761+
plug(:accepts, ["json"])
762+
end</code></pre>
763+
</div>
764+
</div>
765+
<div class="paragraph">
766+
<p>El código nos indica lo siguiente:</p>
767+
</div>
768+
<div class="ulist">
769+
<ul>
770+
<li>
771+
<p><code>get</code>: Es la función identificada con el verbo HTTP a usar en la ruta. Por ejemplo si usamos <em>POST</em> no encontrará la ruta.</p>
772+
</li>
773+
<li>
774+
<p><code>/quotes</code>: Es la ruta donde deberemos hacer las llamadas HTTP. Como estamos dentro del scope <code>/api/</code> la ruta completa será <code>/api/quotes</code></p>
775+
</li>
776+
<li>
777+
<p><code>QuotesController</code>: Es el módulo donde se encontrarán las funciones para procesar el request. Como estamos dentro del scope <code>StoicQuotesWeb</code> el módulo usado será <code>StoicQuotesWeb.QuotesController</code>.</p>
778+
</li>
779+
<li>
780+
<p><code>:index</code>: Es un átomo que permite identificar el request, utilizado en el módulo para segregar las funcionalidad de manejar el request. En este caso se asociará a una función dentro del controlador llamada <code>index</code>.</p>
781+
</li>
782+
</ul>
783+
</div>
784+
<div class="listingblock">
785+
<div class="content">
786+
<pre class="highlightjs highlight"><code class="language-elixir hljs" data-lang="elixir"># verbo http, "/ruta", modulo, parámetro
787+
get "/quotes", QuotesController, :index</code></pre>
788+
</div>
789+
</div>
790+
<div class="paragraph">
791+
<p>Quedando el archivo como lo siguiente:</p>
792+
</div>
793+
<div class="listingblock">
794+
<div class="title">stoic_quotes_web/router.ex</div>
795+
<div class="content">
796+
<pre class="highlightjs highlight"><code class="language-elixir hljs" data-lang="elixir">defmodule StoicQuotesWeb.Router do
797+
use StoicQuotesWeb, :router
798+
799+
pipeline :browser do
800+
plug(:accepts, ["html"])
801+
plug(:fetch_session)
802+
plug(:fetch_live_flash)
803+
plug(:put_root_layout, html: {StoicQuotesWeb.Layouts, :root})
804+
plug(:protect_from_forgery)
805+
plug(:put_secure_browser_headers)
806+
end
807+
808+
pipeline :api do
809+
plug(:accepts, ["json"])
810+
end
811+
812+
scope "/", StoicQuotesWeb do
813+
pipe_through(:browser)
814+
815+
get("/", PageController, :home)
816+
end
817+
818+
scope "/api", StoicQuotesWeb do
819+
pipe_through(:api)
820+
get("/quotes", QuotesController, :index)
821+
get("/quotes/random", QuotesController, :show)
822+
end
823+
824+
# Enable LiveDashboard and Swoosh mailbox preview in development
825+
if Application.compile_env(:stoic_quotes, :dev_routes) do
826+
# If you want to use the LiveDashboard in production, you should put
827+
# it behind authentication and allow only admins to access it.
828+
# If your application does not have an admins-only section yet,
829+
# you can use Plug.BasicAuth to set up some basic authentication
830+
# as long as you are also using SSL (which you should anyway).
831+
import Phoenix.LiveDashboard.Router
832+
833+
scope "/dev" do
834+
pipe_through(:browser)
835+
836+
live_dashboard("/dashboard", metrics: StoicQuotesWeb.Telemetry)
837+
forward("/mailbox", Plug.Swoosh.MailboxPreview)
838+
end
839+
end
840+
end</code></pre>
841+
</div>
842+
</div>
843+
</div>
844+
</div>
845+
<div class="sect1">
846+
<h2 id="paso-6-crear-el-controlador"><a class="anchor" href="#paso-6-crear-el-controlador"></a>Paso 6: Crear el controlador</h2>
847+
<div class="sectionbody">
848+
<div class="paragraph">
849+
<p>El <a href="https://hexdocs.pm/phoenix/controllers.html#actions">controlador</a> es donde se alojan las funciones que responderán a las requests definidas en el router.
850+
Por lo que se debe crear un nuevo archivo llamado <code>quotes_controller.ex</code> dentro de <code>stoic_quotes_web/controllers/quotes_controller.ex</code>
851+
y tener el siguiente contenido:</p>
852+
</div>
853+
<div class="listingblock">
854+
<div class="title">stoic_quotes_web/controllers/quotes_controller.ex</div>
855+
<div class="content">
856+
<pre class="highlightjs highlight"><code class="language-elixir hljs" data-lang="elixir">defmodule StoicQuotesWeb.QuotesController do
857+
use Phoenix.Controller, formats: [:json]
858+
alias StoicQuotes.Quotes
859+
860+
def index(conn, _params) do
861+
quotes = %{quotes: Quotes.list_quotes()}
862+
render(conn, :index, quotes)
863+
end
864+
865+
def show(conn, _params) do
866+
quote = %{quote: Quotes.get_random_quote()}
867+
render(conn, :show, quote)
868+
end
869+
end</code></pre>
870+
</div>
871+
</div>
872+
<div class="ulist">
873+
<ul>
874+
<li>
875+
<p><code>def index(conn, _params)</code>: Notar como cada función recibe un parámetro conexión (conn), donde tiene los detalles del request, el cual se usará para ser enviado a otras funciones como <code>render</code> y el resto de parámetros (params) donde se reciben los distintos parámetros definidos en la ruta principal.</p>
876+
</li>
877+
<li>
878+
<p><code>use Phoenix.Controller, formats: [:json]</code>: Define a este módulo como un controlador que responde con <code>json</code>.</p>
879+
</li>
880+
<li>
881+
<p><code>render(conn, :index, quotes)</code>: Utiliza la <a href="https://hexdocs.pm/phoenix/Phoenix.Controller.html#module-rendering-and-layouts">función render</a> que llama a la vista y genera el json final pasándole los parámetros desde el controlador.</p>
882+
</li>
883+
</ul>
884+
</div>
885+
</div>
886+
</div>
887+
<div class="sect1">
888+
<h2 id="paso-7-crear-la-vista"><a class="anchor" href="#paso-7-crear-la-vista"></a>Paso 7: Crear la vista</h2>
889+
<div class="sectionbody">
890+
<div class="paragraph">
891+
<p>La vista será principalmente un <code>json</code>, por lo que tenemos que crear un nuevo archivo llamado <code>quotes_json.ex</code>
892+
dentro del mismo directorio que <code>quotes_controller.ex</code>.</p>
893+
</div>
894+
<div class="paragraph">
895+
<p>Notar que tiene las mismas funciones usadas en el controlador, con la excepción de que definen su parámetro
896+
como el dato a mostrar, que es pasado a la función <code>render</code> usada en el controlador.</p>
897+
</div>
898+
<div class="listingblock">
899+
<div class="content">
900+
<pre class="highlightjs highlight"><code class="language-elixir hljs" data-lang="elixir">defmodule StoicQuotesWeb.QuotesJSON do
901+
alias StoicQuotes.Quotes.Quote
902+
903+
def index(%{quotes: quotes}) do
904+
%{data: for(quote &lt;- quotes, do: data(quote))}
905+
end
906+
907+
def show(%{quote: quote}) do
908+
%{data: data(quote)}
909+
end
910+
911+
defp data(%Quote{} = datum) do
912+
%{
913+
quote: datum.quote,
914+
author: datum.author,
915+
source: datum.source
916+
}
917+
end
918+
end</code></pre>
919+
</div>
920+
</div>
921+
</div>
922+
</div>
923+
<div class="sect1">
924+
<h2 id="paso-8-modificar-el-contexto"><a class="anchor" href="#paso-8-modificar-el-contexto"></a>Paso 8: Modificar el contexto</h2>
925+
<div class="sectionbody">
926+
<div class="paragraph">
927+
<p>Debemos modificar el contexto (o modelo) para añadir la función <code>Quotes.get_random_quote()</code> usada en el controlador
928+
en su función <code>show</code>.</p>
929+
</div>
930+
<div class="listingblock">
931+
<div class="title">lib/stoic_quotes/quotes.ex</div>
932+
<div class="content">
933+
<pre class="highlightjs highlight"><code class="language-elixir hljs" data-lang="elixir">@doc """
934+
Gets a random quote
935+
936+
## Examples
937+
938+
iex&gt; get_random_quote()
939+
%Quote{}
940+
"""
941+
def get_random_quote() do
942+
query =
943+
from(q in Quote,
944+
order_by: fragment("RANDOM()"),
945+
limit: 1
946+
)
947+
948+
Repo.one(query)
949+
end</code></pre>
950+
</div>
951+
</div>
952+
</div>
953+
</div>
954+
<div class="sect1">
955+
<h2 id="paso-9-pruebas-manuales"><a class="anchor" href="#paso-9-pruebas-manuales"></a>Paso 9: Pruebas Manuales</h2>
956+
<div class="sectionbody">
957+
<div class="paragraph">
958+
<p>Para las pruebas se puede usar <code>curl</code> o crear una colección con <a href="https://www.usebruno.com/">Bruno</a>.
959+
Las pruebas automatizadas con <code>mix test</code> serán implementadas en un proyecto futuro.</p>
960+
</div>
961+
<div class="listingblock">
962+
<div class="content">
963+
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ iex -S mix phx.server
964+
$ curl -i localhost:4000/api/quotes/
965+
$ curl -i localhost:4000/api/quotes/random</code></pre>
966+
</div>
967+
</div>
968+
<div class="listingblock">
969+
<div class="content">
970+
<pre class="highlightjs highlight"><code class="language-text hljs" data-lang="text">➜ ~ curl -i localhost:4000/api/quotes/
971+
HTTP/1.1 200 OK
972+
date: Sat, 27 Sep 2025 03:16:50 GMT
973+
content-length: 723
974+
vary: accept-encoding
975+
content-type: application/json; charset=utf-8
976+
cache-control: max-age=0, private, must-revalidate
977+
x-request-id: GGkFWTujtWGncGAAAAGC
978+
979+
{"data":[{"author":"Marcus Aurelius","source":"Book II, Meditations","quote":"Seldom are any found unhappy from not observing what is in the minds of others. But such as observe not well the stirrings of their own souls must of necessity be unhappy."},{"author":"Marcus Aurelius","source":"Book XI, Meditations","quote":"Consider whence each thing came, of what it was compounded, into what it will be changed, how it will be with it when changed, and that it will suffer no evil."},{"author":"Marcus Aurelius","source":"Book X, Meditations","quote":"Accustom yourself as much as possible, when any one takes any action, to consider only: To what end is he working? But begin at home; and examine yourself first of all."}]}%</code></pre>
980+
</div>
981+
</div>
982+
</div>
983+
</div>
680984
<nav class="pagination">
681985
<span class="prev"><a href="chapter.html">El Lenguaje Elixir</a></span>
682986
<span class="next"><a href="../mobile/chapter.html">Aplicaciones Móviles</a></span>

docs/search-index.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)