<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gustavo Ramirez</title>
    <description>The latest articles on DEV Community by Gustavo Ramirez (@geramireze).</description>
    <link>https://dev.to/geramireze</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F955443%2Fa5a2542e-059b-47ee-88b5-2759e411f690.jpg</url>
      <title>DEV Community: Gustavo Ramirez</title>
      <link>https://dev.to/geramireze</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/geramireze"/>
    <language>en</language>
    <item>
      <title>Autenticación Social en Aplicaciones Web Usando AWS Cognito y OAuth</title>
      <dc:creator>Gustavo Ramirez</dc:creator>
      <pubDate>Thu, 27 Mar 2025 19:55:42 +0000</pubDate>
      <link>https://dev.to/geramireze/autenticacion-social-en-aplicaciones-web-usando-aws-cognito-y-oauth-1jj9</link>
      <guid>https://dev.to/geramireze/autenticacion-social-en-aplicaciones-web-usando-aws-cognito-y-oauth-1jj9</guid>
      <description>&lt;p&gt;La autenticación social permite a los usuarios iniciar sesión en aplicaciones web utilizando sus cuentas de redes sociales como Google y Facebook. AWS Cognito facilita la integración con múltiples proveedores de identidad a través de OAuth, simplificando el manejo de sesiones y permisos. En este artículo, veremos cómo implementar esta funcionalidad en una aplicación web usando React y AWS Cognito.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Por qué Usar AWS Cognito para Autenticación Social?
&lt;/h2&gt;

&lt;p&gt;AWS Cognito proporciona autenticación segura y escalable, integrándose fácilmente con múltiples proveedores de identidad. Utiliza JWT para manejar sesiones de forma segura, ofreciendo una experiencia de inicio de sesión fluida para los usuarios.&lt;/p&gt;

&lt;h3&gt;
  
  
  Beneficios de esta integración:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Inicio de sesión con cuentas populares (Google, Facebook).&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gestión segura de sesiones con tokens JWT.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integración directa con aplicaciones frontend modernas.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Control de acceso detallado con permisos basados en roles.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Arquitectura General
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;AWS Cognito:&lt;/strong&gt; Manejo de autenticación y almacenamiento de usuarios.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OAuth con Google y Facebook:&lt;/strong&gt; Proveedores de identidad.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React:&lt;/strong&gt; Interfaz frontend.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Paso 1: Crear el Pool de Usuarios en AWS Cognito
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Crear un Pool de Usuarios
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Ve a la consola de &lt;strong&gt;AWS Cognito&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Haz clic en &lt;strong&gt;Administrar usuarios&lt;/strong&gt; y luego en &lt;strong&gt;Crear un pool de usuarios&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Asigna un nombre (por ejemplo, &lt;code&gt;social-login-pool&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Habilitar la Autenticación Social
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Ve a &lt;strong&gt;Proveedores de identidad (Identity Providers)&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Agrega &lt;strong&gt;Google&lt;/strong&gt; y &lt;strong&gt;Facebook&lt;/strong&gt; como proveedores.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Configuración de Google
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Crea un &lt;strong&gt;Proyecto de API&lt;/strong&gt; en la consola de &lt;strong&gt;Google Developers&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Habilita la &lt;strong&gt;API de OAuth 2.0&lt;/strong&gt; y obtén el &lt;strong&gt;Client ID&lt;/strong&gt; y &lt;strong&gt;Client Secret&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Ingresa las credenciales en Cognito.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Configuración de Facebook
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Crea una &lt;strong&gt;Aplicación de Facebook&lt;/strong&gt; en &lt;strong&gt;Meta for Developers&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Habilita &lt;strong&gt;Inicio de Sesión con Facebook&lt;/strong&gt; y obtén el &lt;strong&gt;App ID&lt;/strong&gt; y &lt;strong&gt;App Secret&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Ingresa las credenciales en Cognito.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Paso 2: Configurar el App Client en Cognito
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Crea un &lt;strong&gt;App Client&lt;/strong&gt; en el Pool de Usuarios.&lt;/li&gt;
&lt;li&gt;Habilita &lt;strong&gt;Iniciar Sesión en la Web&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Activa los siguientes flujos de autenticación:

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Authorization Code Grant&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Implicit Grant&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Configura la URL de redirección (por ejemplo, &lt;code&gt;http://localhost:3000&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Anota el &lt;strong&gt;App Client ID&lt;/strong&gt; para usarlo en el frontend.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Paso 3: Crear un Dominio en Cognito
&lt;/h2&gt;

&lt;p&gt;Para que el flujo de OAuth funcione, necesitas un dominio propio.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws cognito-idp create-user-pool-domain &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--domain&lt;/span&gt; my-social-app &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--user-pool-id&lt;/span&gt; us-east-1_example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Paso 4: Configuración del Frontend con React
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Instalar Dependencias
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;aws-amplify @aws-amplify/ui-react
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuración de AWS Amplify
&lt;/h3&gt;

&lt;h4&gt;
  
  
  aws-exports.js
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;awsConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;Auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;us-east-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;userPoolId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;us-east-1_example&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;userPoolWebClientId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;example1234&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;oauth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-social-app.auth.us-east-1.amazoncognito.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;redirectSignIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3000/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;redirectSignOut&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3000/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;responseType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;code&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;awsConfig&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Inicialización en React
&lt;/h3&gt;

&lt;h4&gt;
  
  
  index.js
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ReactDOM&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Amplify&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-amplify&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;awsConfig&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./aws-exports&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;Amplify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;awsConfig&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Paso 5: Implementación de la Autenticación
&lt;/h2&gt;

&lt;h3&gt;
  
  
  App.js
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Amplify&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Auth&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-amplify&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;awsConfig&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./aws-exports&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;Amplify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;awsConfig&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;currentAuthenticatedUser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signIn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;federatedSignIn&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Google&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error al iniciar sesión&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signOut&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signOut&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Autenticación&lt;/span&gt; &lt;span class="nx"&gt;Social&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Bienvenido&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;signOut&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Cerrar&lt;/span&gt; &lt;span class="nx"&gt;Sesión&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Iniciar&lt;/span&gt; &lt;span class="nx"&gt;Sesión&lt;/span&gt; &lt;span class="nx"&gt;con&lt;/span&gt; &lt;span class="nx"&gt;Google&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Uso de Tokens JWT para Sesiones Seguras
&lt;/h2&gt;

&lt;p&gt;Una vez autenticado, puedes acceder al token JWT:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;currentSession&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getIdToken&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;getJwtToken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;JWT Token:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Buenas Prácticas de Seguridad
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Renovación de Tokens:&lt;/strong&gt; Utiliza el flujo de actualización para mantener la sesión activa.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Almacenamiento Seguro:&lt;/strong&gt; No almacenes el token directamente en el localStorage o sessionStorage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Políticas de IAM:&lt;/strong&gt; Restringe el acceso a los recursos de AWS utilizando políticas detalladas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Control de Acceso:&lt;/strong&gt; Define roles específicos en Cognito para limitar el acceso a recursos.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;La autenticación social usando AWS Cognito y OAuth ofrece una experiencia de usuario fluida y segura, integrando múltiples proveedores en un solo flujo de inicio de sesión. Siguiendo estos pasos, tendrás una aplicación web moderna con soporte para autenticación social lista para producción.&lt;/p&gt;

&lt;p&gt;¿Tienes dudas o sugerencias? ¡Déjalas en los comentarios!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Creación de Dashboards Interactivos Usando Recharts y AWS Data Lakes</title>
      <dc:creator>Gustavo Ramirez</dc:creator>
      <pubDate>Thu, 27 Mar 2025 19:47:05 +0000</pubDate>
      <link>https://dev.to/geramireze/creacion-de-dashboards-interactivos-usando-recharts-y-aws-data-lakes-3og4</link>
      <guid>https://dev.to/geramireze/creacion-de-dashboards-interactivos-usando-recharts-y-aws-data-lakes-3og4</guid>
      <description>&lt;p&gt;Los dashboards interactivos son esenciales para la toma de decisiones basadas en datos en tiempo real. En este artículo, vamos a combinar la potencia de &lt;strong&gt;AWS Lake Formation&lt;/strong&gt; para el almacenamiento de datos con la flexibilidad de &lt;strong&gt;Recharts&lt;/strong&gt; y &lt;strong&gt;D3.js&lt;/strong&gt; para la visualización. Además, utilizaremos &lt;strong&gt;AWS API Gateway&lt;/strong&gt; para acceder a los datos de manera segura y eficiente.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Por qué Recharts y AWS Data Lakes?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWS Lake Formation&lt;/strong&gt; permite almacenar y catalogar datos estructurados y no estructurados de manera eficiente.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS API Gateway&lt;/strong&gt; proporciona una capa de acceso segura a los datos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recharts&lt;/strong&gt; y &lt;strong&gt;D3.js&lt;/strong&gt; son bibliotecas de visualización ligeras y poderosas que se integran bien con React.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Beneficios de esta arquitectura:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Visualización en tiempo real&lt;/strong&gt; de métricas clave.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conexión segura&lt;/strong&gt; a los datos almacenados en AWS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibilidad&lt;/strong&gt; para crear gráficos personalizados y altamente interactivos.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Arquitectura General
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;AWS Lake Formation:&lt;/strong&gt; Para almacenamiento y catalogación de datos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS API Gateway:&lt;/strong&gt; Para exponer los datos a través de endpoints seguros.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React con Recharts:&lt;/strong&gt; Para la visualización dinámica.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;D3.js:&lt;/strong&gt; Para gráficos personalizados y avanzados.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Paso 1: Configuración del Data Lake en AWS Lake Formation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Crear el Data Lake
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Accede a &lt;strong&gt;AWS Lake Formation&lt;/strong&gt; desde la consola.&lt;/li&gt;
&lt;li&gt;Configura un &lt;strong&gt;repositorio de datos&lt;/strong&gt; utilizando Amazon S3.&lt;/li&gt;
&lt;li&gt;Otorga permisos de acceso con IAM para los servicios de consulta (Athena o Glue).&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Ejemplo de Datos Financieros
&lt;/h3&gt;

&lt;p&gt;Guarda un archivo CSV en el bucket de S3 configurado:&lt;/p&gt;

&lt;h4&gt;
  
  
  transactions.csv
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;transaction_id,amount,date,type
1,1200.50,2025-03-01,ingreso
2,850.75,2025-03-02,gasto
3,600.00,2025-03-03,ingreso
4,900.25,2025-03-04,gasto
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Crear la Tabla en AWS Glue
&lt;/h3&gt;

&lt;p&gt;Usa &lt;strong&gt;AWS Glue&lt;/strong&gt; para catalogar los datos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws glue create-table &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--database&lt;/span&gt; data_lake_db &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--table-input&lt;/span&gt; &lt;span class="s1"&gt;'{
    "Name": "financial_transactions",
    "StorageDescriptor": {
      "Columns": [
        {"Name": "transaction_id", "Type": "int"},
        {"Name": "amount", "Type": "double"},
        {"Name": "date", "Type": "string"},
        {"Name": "type", "Type": "string"}
      ],
      "Location": "s3://my-data-lake/transactions/"
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Paso 2: Crear una API con AWS API Gateway
&lt;/h2&gt;

&lt;p&gt;Vamos a exponer los datos de Lake Formation a través de un endpoint REST.&lt;/p&gt;

&lt;h3&gt;
  
  
  Crear la API
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws apigateway create-rest-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"FinancialDashboardAPI"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Crear el Recurso
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws apigateway create-resource &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--rest-api-id&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;api_id&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--parent-id&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;parent_id&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--path-part&lt;/span&gt; transactions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Crear el Método GET
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws apigateway put-method &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--rest-api-id&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;api_id&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--resource-id&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;resource_id&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--http-method&lt;/span&gt; GET &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--authorization-type&lt;/span&gt; NONE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Integración con Lambda
&lt;/h3&gt;

&lt;p&gt;Usa una función Lambda para consultar los datos en tiempo real:&lt;/p&gt;

&lt;h4&gt;
  
  
  index.js
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;glue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Glue&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`SELECT * FROM financial_transactions`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;DatabaseName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data_lake_db&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Sql&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;glue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getQueryResults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error al obtener datos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Paso 3: Visualización con Recharts y D3.js
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Instalación de Dependencias
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;recharts d3 @apollo/client graphql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuración del Cliente GraphQL
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ApolloClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;InMemoryCache&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@apollo/client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ApolloClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.myapp.com/graphql&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InMemoryCache&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Crear el Dashboard con Recharts
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Dashboard.js
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LineChart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Line&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;XAxis&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;YAxis&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CartesianGrid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Tooltip&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;recharts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Dashboard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.myapp.com/transactions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Transacciones&lt;/span&gt; &lt;span class="nx"&gt;Financieras&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LineChart&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CartesianGrid&lt;/span&gt; &lt;span class="nx"&gt;strokeDasharray&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;3 3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;XAxis&lt;/span&gt; &lt;span class="nx"&gt;dataKey&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;date&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;YAxis&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Tooltip&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Line&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;monotone&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;dataKey&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;amount&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;stroke&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#8884d8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/LineChart&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Dashboard&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Buenas Prácticas de Seguridad
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Autenticación con AWS Cognito:&lt;/strong&gt; Asegúrate de proteger los endpoints de la API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filtrado de Datos:&lt;/strong&gt; Aplica reglas para evitar la exposición de datos sensibles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoreo con CloudWatch:&lt;/strong&gt; Detecta anomalías en el consumo de datos.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Los dashboards interactivos utilizando &lt;strong&gt;Recharts&lt;/strong&gt; y &lt;strong&gt;D3.js&lt;/strong&gt; combinados con la potencia de &lt;strong&gt;AWS Lake Formation&lt;/strong&gt; son una excelente manera de visualizar datos financieros en tiempo real. Al integrar &lt;strong&gt;AWS API Gateway&lt;/strong&gt; y &lt;strong&gt;Lambda&lt;/strong&gt;, logramos una arquitectura serverless escalable y segura.&lt;/p&gt;

&lt;p&gt;¿Tienes dudas o sugerencias? ¡Déjalas en los comentarios!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Conectando Frontend React con APIs Serverless en AWS con GraphQL</title>
      <dc:creator>Gustavo Ramirez</dc:creator>
      <pubDate>Thu, 27 Mar 2025 19:39:19 +0000</pubDate>
      <link>https://dev.to/geramireze/conectando-frontend-react-con-apis-serverless-en-aws-con-graphql-47m3</link>
      <guid>https://dev.to/geramireze/conectando-frontend-react-con-apis-serverless-en-aws-con-graphql-47m3</guid>
      <description>&lt;p&gt;Las aplicaciones modernas necesitan ser rápidas, escalables y eficientes en el manejo de datos. Una de las combinaciones más potentes para lograr esto es utilizar GraphQL con AWS AppSync en el backend y React en el frontend. En este artículo vamos a ver cómo crear un backend serverless con GraphQL utilizando AppSync y cómo conectar el frontend con Apollo Client. Además, cubriremos la autenticación con AWS Cognito para asegurar nuestras rutas.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Por qué utilizar AWS AppSync y GraphQL?
&lt;/h2&gt;

&lt;p&gt;AWS AppSync es un servicio de GraphQL totalmente gestionado que facilita la creación de APIs flexibles y en tiempo real. Al usar AppSync, podemos conectar directamente nuestras aplicaciones frontend a servicios serverless, bases de datos como DynamoDB e incluso integrarlo con Lambda para lógica de negocio.&lt;/p&gt;

&lt;h3&gt;
  
  
  Beneficios de AppSync:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Consultas y mutaciones rápidas mediante GraphQL.&lt;/li&gt;
&lt;li&gt;Actualizaciones en tiempo real con suscripciones.&lt;/li&gt;
&lt;li&gt;Autenticación y autorización robustas con AWS Cognito.&lt;/li&gt;
&lt;li&gt;Integración nativa con otros servicios de AWS.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Paso 1: Configurar el Backend con AWS AppSync
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Crear un Proyecto con Amplify CLI
&lt;/h3&gt;

&lt;p&gt;Instala Amplify si aún no lo tienes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @aws-amplify/cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inicializa el proyecto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;amplify init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Agregar el Servicio AppSync
&lt;/h3&gt;

&lt;p&gt;Añade GraphQL a tu proyecto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;amplify add api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Selecciona las opciones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tipo de API:&lt;/strong&gt; GraphQL&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Autenticación:&lt;/strong&gt; Amazon Cognito User Pool&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Perfil de autenticación:&lt;/strong&gt; Default configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Paso 2: Definir el Esquema de GraphQL
&lt;/h2&gt;

&lt;p&gt;Vamos a crear un esquema básico para manejar tareas.&lt;/p&gt;

&lt;h4&gt;
  
  
  Archivo schema.graphql
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Implementar el Backend
&lt;/h3&gt;

&lt;p&gt;Ejecuta el siguiente comando para desplegar la API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;amplify push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esto generará el endpoint de AppSync y la configuración de GraphQL en el archivo &lt;code&gt;aws-exports.js&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Paso 3: Configuración del Frontend con Apollo Client
&lt;/h2&gt;

&lt;p&gt;Instala Apollo Client y Amplify en tu proyecto React:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @apollo/client graphql aws-amplify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configurar Amplify en React
&lt;/h3&gt;

&lt;p&gt;Agrega la configuración en el archivo &lt;code&gt;index.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ReactDOM&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Amplify&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-amplify&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;awsconfig&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./aws-exports&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ApolloProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ApolloClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;InMemoryCache&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@apollo/client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;Amplify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;awsconfig&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ApolloClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;awsconfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_appsync_graphqlEndpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InMemoryCache&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;idToken&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ApolloProvider&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ApolloProvider&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;,
&lt;/span&gt;  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Paso 4: Crear Consultas y Mutaciones
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Crear la Mutación en Apollo
&lt;/h3&gt;

&lt;h4&gt;
  
  
  mutations.js
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@apollo/client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CREATE_TASK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt;&lt;span class="s2"&gt;`
  mutation CreateTask($title: String!, $description: String, $completed: Boolean!) {
    createTask(input: {title: $title, description: $description, completed: $completed}) {
      id
      title
      description
      completed
    }
  }
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Crear la Consulta
&lt;/h3&gt;

&lt;h4&gt;
  
  
  queries.js
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@apollo/client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GET_TASKS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt;&lt;span class="s2"&gt;`
  query ListTasks {
    listTasks {
      items {
        id
        title
        description
        completed
      }
    }
  }
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Paso 5: Implementar el Frontend
&lt;/h2&gt;

&lt;h4&gt;
  
  
  App.js
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useMutation&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@apollo/client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GET_TASKS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CREATE_TASK&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./graphql/queries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;GET_TASKS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;createTask&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMutation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CREATE_TASK&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTask&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSubmit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createTask&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nf"&gt;setTask&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Cargando&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Lista&lt;/span&gt; &lt;span class="nx"&gt;de&lt;/span&gt; &lt;span class="nx"&gt;Tareas&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Título&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTask&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;})}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Crear&lt;/span&gt; &lt;span class="nx"&gt;Tarea&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;listTasks&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/li&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;))}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ul&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Buenas Prácticas de Estructuración
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Modularización del Código:&lt;/strong&gt; Organiza consultas y mutaciones en directorios específicos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Autenticación Centralizada:&lt;/strong&gt; Maneja los tokens en un contexto o servicio compartido.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tipado con TypeScript:&lt;/strong&gt; Utiliza tipos para garantizar la integridad de los datos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Control de Errores:&lt;/strong&gt; Implementa manejadores para los errores comunes de Apollo y GraphQL.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Con AWS AppSync y React, podemos construir aplicaciones rápidas y escalables utilizando GraphQL. La integración con Apollo Client facilita el consumo de datos en tiempo real y la autenticación con Cognito garantiza la seguridad del acceso. ¡Implementa esta combinación y lleva tu aplicación a otro nivel!&lt;/p&gt;

&lt;p&gt;¿Tienes dudas o sugerencias? ¡Déjamelo saber en los comentarios!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Mejorando la Experiencia de Usuario con Notificaciones Push en Aplicaciones Web Usando AWS SNS</title>
      <dc:creator>Gustavo Ramirez</dc:creator>
      <pubDate>Thu, 27 Mar 2025 19:32:47 +0000</pubDate>
      <link>https://dev.to/geramireze/mejorando-la-experiencia-de-usuario-con-notificaciones-push-en-aplicaciones-web-usando-aws-sns-1n03</link>
      <guid>https://dev.to/geramireze/mejorando-la-experiencia-de-usuario-con-notificaciones-push-en-aplicaciones-web-usando-aws-sns-1n03</guid>
      <description>&lt;p&gt;Las notificaciones push son una herramienta poderosa para mantener a los usuarios actualizados en tiempo real sin necesidad de recargar la página. Integrarlas en aplicaciones web utilizando AWS Simple Notification Service (SNS) y AWS Lambda nos permite gestionar eventos de manera eficiente y escalable. En este artículo, veremos cómo implementar notificaciones push desde el frontend aprovechando el ecosistema de AWS.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Por qué Usar Notificaciones Push con AWS SNS?
&lt;/h2&gt;

&lt;p&gt;AWS SNS es un servicio de mensajería totalmente gestionado que facilita el envío de mensajes a dispositivos móviles, correos electrónicos y servicios HTTP/HTTPS. Combinándolo con AWS Lambda, podemos automatizar el envío de notificaciones en respuesta a eventos específicos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Beneficios de la implementación:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Notificaciones en tiempo real sin recarga de página.&lt;/li&gt;
&lt;li&gt;Integración con múltiples servicios backend usando Lambda.&lt;/li&gt;
&lt;li&gt;Escalabilidad automática y baja latencia.&lt;/li&gt;
&lt;li&gt;Manejo eficiente de eventos en la nube.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Arquitectura General
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Frontend (React o Angular)&lt;/strong&gt; para recibir las notificaciones push.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS SNS&lt;/strong&gt; para la gestión de mensajes y distribución.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS Lambda&lt;/strong&gt; para procesar los eventos y enviar las notificaciones.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Paso 1: Configuración de AWS SNS
&lt;/h2&gt;

&lt;p&gt;Primero, crearemos un tópico en SNS para manejar las notificaciones push.&lt;/p&gt;

&lt;h3&gt;
  
  
  Crear un Tópico SNS
&lt;/h3&gt;

&lt;p&gt;Ejecuta el siguiente comando para crear el tópico:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws sns create-topic &lt;span class="nt"&gt;--name&lt;/span&gt; pushNotifications
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Obtén el ARN del tópico:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws sns list-topics
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuración de Permisos
&lt;/h3&gt;

&lt;p&gt;Es importante asegurarse de que el tópico permita recibir mensajes desde Lambda:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws sns set-topic-attributes &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--topic-arn&lt;/span&gt; arn:aws:sns:us-east-1:123456789012:pushNotifications &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--attribute-name&lt;/span&gt; Policy &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--attribute-value&lt;/span&gt; &lt;span class="s1"&gt;'{
    "Version": "2012-10-17",
    "Statement": [
      {
        "Effect": "Allow",
        "Principal": "*",
        "Action": "SNS:Publish",
        "Resource": "arn:aws:sns:us-east-1:123456789012:pushNotifications"
      }
    ]
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Paso 2: Crear la Función Lambda
&lt;/h2&gt;

&lt;p&gt;AWS Lambda procesará los eventos y enviará las notificaciones a SNS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Crear la Función Lambda
&lt;/h3&gt;

&lt;p&gt;Vamos a crear una función que publique mensajes en el tópico SNS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws lambda create-function &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--function-name&lt;/span&gt; pushNotificationHandler &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--runtime&lt;/span&gt; nodejs20.x &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--role&lt;/span&gt; arn:aws:iam::123456789012:role/lambda-execution-role &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--handler&lt;/span&gt; index.handler &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--zip-file&lt;/span&gt; fileb://function.zip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Código de la Función (index.js)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SNS&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Notificación genérica&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;TopicArn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;arn:aws:sns:us-east-1:123456789012:pushNotifications&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Notificación enviada con éxito&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error enviando notificación&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sube la función a AWS Lambda:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws lambda update-function-code &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--function-name&lt;/span&gt; pushNotificationHandler &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--zip-file&lt;/span&gt; fileb://function.zip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Paso 3: Configuración del Frontend para Recibir Notificaciones
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Registro del Service Worker (React)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;serviceWorker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/sw.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;registration&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Service Worker registrado&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error al registrar el SW:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Archivo sw.js
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;push&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Mensaje sin contenido&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;registration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;showNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Notificación&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/icon.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Suscripción desde el Frontend
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;subscribeToPush&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;registration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;registration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pushManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;userVisibleOnly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;applicationServerKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;VAPID_PUBLIC_KEY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Suscripción exitosa:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;subscribeToPush&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Paso 4: Disparar Notificaciones desde el Backend
&lt;/h2&gt;

&lt;p&gt;Podemos desencadenar una notificación enviando una solicitud a Lambda:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws lambda invoke &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--function-name&lt;/span&gt; pushNotificationHandler &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--payload&lt;/span&gt; &lt;span class="s1"&gt;'{"message":"¡Nuevo evento en la aplicación!"}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  response.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Buenas Prácticas de Seguridad
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Uso de Políticas de IAM:&lt;/strong&gt; Asegúrate de que las funciones Lambda tengan permisos mínimos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Protección contra Spam:&lt;/strong&gt; Implementa verificaciones para evitar abusos de notificaciones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Control de Suscripciones:&lt;/strong&gt; Maneja las suscripciones de los usuarios de manera segura y eficiente.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verificación de Identidad:&lt;/strong&gt; Utiliza tokens seguros en el frontend para identificar dispositivos.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Implementar notificaciones push usando AWS SNS y Lambda brinda una arquitectura escalable y eficiente para aplicaciones web modernas. Las notificaciones en tiempo real mejoran la experiencia del usuario, manteniéndolos informados sin necesidad de recargar la página.&lt;/p&gt;

&lt;p&gt;¿Tienes dudas o quieres compartir tu experiencia? ¡Deja tus comentarios!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Optimización de Performance en Single Page Applications (SPA) en AWS S3 y CloudFront</title>
      <dc:creator>Gustavo Ramirez</dc:creator>
      <pubDate>Thu, 27 Mar 2025 19:15:37 +0000</pubDate>
      <link>https://dev.to/geramireze/optimizacion-de-performance-en-single-page-applications-spa-en-aws-s3-y-cloudfront-32g1</link>
      <guid>https://dev.to/geramireze/optimizacion-de-performance-en-single-page-applications-spa-en-aws-s3-y-cloudfront-32g1</guid>
      <description>&lt;p&gt;Las aplicaciones de una sola página (SPA) son conocidas por su capacidad de brindar experiencias fluidas al usuario. Sin embargo, el rendimiento puede verse afectado si no se configuran adecuadamente los recursos estáticos y el manejo de caché. AWS S3 y CloudFront son una combinación poderosa para hospedar y distribuir aplicaciones SPA con alto rendimiento y baja latencia. En este artículo, veremos cómo optimizar el rendimiento de una SPA utilizando estos servicios.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Por qué AWS S3 y CloudFront para SPA?
&lt;/h2&gt;

&lt;p&gt;AWS S3 es ideal para almacenar archivos estáticos de manera segura y económica, mientras que CloudFront proporciona una red de distribución de contenido (CDN) para entregar estos archivos rápidamente desde ubicaciones cercanas al usuario. Al combinar ambos servicios, podemos lograr tiempos de carga rápidos y una experiencia fluida.&lt;/p&gt;

&lt;h3&gt;
  
  
  Beneficios de la optimización:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Carga rápida de recursos estáticos.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Distribución global con baja latencia.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Actualizaciones inmediatas gracias a la invalidación de caché.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reducción en el consumo de ancho de banda.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Paso 1: Crear y Configurar el Bucket S3
&lt;/h2&gt;

&lt;p&gt;Primero, necesitamos crear un bucket en S3 para almacenar nuestra aplicación.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws s3api create-bucket &lt;span class="nt"&gt;--bucket&lt;/span&gt; my-spa-app &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Habilitar el Hosting Estático
&lt;/h3&gt;

&lt;p&gt;Configura el bucket para servir contenido estático:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws s3 website s3://my-spa-app/ &lt;span class="nt"&gt;--index-document&lt;/span&gt; index.html &lt;span class="nt"&gt;--error-document&lt;/span&gt; index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configurar Políticas de Acceso Público
&lt;/h3&gt;

&lt;p&gt;Asegúrate de que el bucket sea accesible públicamente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PublicReadGetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::my-spa-app/*"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aplica la política con el siguiente comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws s3api put-bucket-policy &lt;span class="nt"&gt;--bucket&lt;/span&gt; my-spa-app &lt;span class="nt"&gt;--policy&lt;/span&gt; file://policy.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Paso 2: Subir la Aplicación a S3
&lt;/h2&gt;

&lt;p&gt;Construye tu aplicación SPA (React, Angular o Vue):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sube los archivos al bucket:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws s3 &lt;span class="nb"&gt;sync &lt;/span&gt;build/ s3://my-spa-app &lt;span class="nt"&gt;--delete&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Paso 3: Configurar CloudFront para Entrega Global
&lt;/h2&gt;

&lt;p&gt;CloudFront permite que la aplicación se cargue rápidamente desde cualquier parte del mundo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Crear la Distribución de CloudFront
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws cloudfront create-distribution &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--origin-domain-name&lt;/span&gt; my-spa-app.s3.amazonaws.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--default-root-object&lt;/span&gt; index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuración de Caché y Headers
&lt;/h3&gt;

&lt;p&gt;Actualiza la configuración de la distribución para habilitar la compresión Gzip y el almacenamiento en caché.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws cloudfront update-distribution &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--id&lt;/span&gt; YOUR_DISTRIBUTION_ID &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--default-cache-behavior&lt;/span&gt; &lt;span class="s1"&gt;'{
    "ViewerProtocolPolicy": "redirect-to-https",
    "Compress": true,
    "AllowedMethods": ["GET", "HEAD"],
    "MinTTL": 0,
    "DefaultTTL": 86400,
    "MaxTTL": 31536000
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Paso 4: Invalidación de Caché para Actualizaciones Rápidas
&lt;/h2&gt;

&lt;p&gt;Cuando despliegues una nueva versión, debes invalidar la caché para garantizar que los usuarios reciban los archivos actualizados.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws cloudfront create-invalidation &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--distribution-id&lt;/span&gt; YOUR_DISTRIBUTION_ID &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--paths&lt;/span&gt; &lt;span class="s2"&gt;"/*"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esto forzará a CloudFront a obtener los archivos más recientes de S3 en lugar de servir archivos en caché.&lt;/p&gt;

&lt;h2&gt;
  
  
  Paso 5: Pruebas de Velocidad y Comparación
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Herramientas Recomendadas
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PageSpeed Insights (Google)&lt;/strong&gt; para analizar el rendimiento general.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WebPageTest&lt;/strong&gt; para pruebas de latencia desde diferentes ubicaciones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lighthouse&lt;/strong&gt; para medir métricas de carga y renderizado.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Comparativa de Velocidad
&lt;/h3&gt;

&lt;p&gt;Realiza pruebas antes y después de implementar CloudFront para ver la diferencia en tiempos de carga y rendimiento. Puedes utilizar herramientas como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s2"&gt;"
Time: %{time_total}s
"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="nt"&gt;-s&lt;/span&gt; https://d1234.cloudfront.net
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Mejores Prácticas para Optimización
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Minificar y comprimir archivos CSS y JS.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Habilitar el uso de Brotli o Gzip en CloudFront.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Configurar políticas de caché adecuadas según el tipo de recurso.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Utilizar versiones con hash en los nombres de archivo para asegurar el almacenamiento en caché.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Monitorizar con AWS CloudWatch para detectar problemas de rendimiento.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Implementar técnicas de optimización en AWS S3 y CloudFront no solo mejora la experiencia del usuario final, sino que también reduce el consumo de ancho de banda y garantiza la entrega rápida de contenido estático. Siguiendo estos pasos, tu aplicación SPA estará lista para soportar tráfico elevado con una experiencia de usuario sin interrupciones.&lt;/p&gt;

&lt;p&gt;¿Tienes alguna duda o sugerencia? ¡Déjalo en los comentarios!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Desplegando Aplicaciones Frontend en AWS App Runner: Desde el Build hasta el Escalamiento</title>
      <dc:creator>Gustavo Ramirez</dc:creator>
      <pubDate>Thu, 27 Mar 2025 19:09:32 +0000</pubDate>
      <link>https://dev.to/geramireze/desplegando-aplicaciones-frontend-en-aws-app-runner-desde-el-build-hasta-el-escalamiento-4d60</link>
      <guid>https://dev.to/geramireze/desplegando-aplicaciones-frontend-en-aws-app-runner-desde-el-build-hasta-el-escalamiento-4d60</guid>
      <description>&lt;p&gt;Si estás trabajando en proyectos frontend modernos, probablemente ya te hayas enfrentado al desafío de desplegar y escalar aplicaciones sin necesidad de gestionar infraestructura compleja. AWS App Runner llega para simplificar el proceso de despliegue continuo de aplicaciones web. En este artículo, vamos a ver cómo desplegar una aplicación frontend utilizando AWS App Runner desde el build hasta el escalamiento automático.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Por qué usar AWS App Runner para Frontend?
&lt;/h2&gt;

&lt;p&gt;AWS App Runner es un servicio completamente gestionado que permite implementar aplicaciones directamente desde un repositorio de código fuente o una imagen de contenedor. Lo mejor es que elimina la necesidad de preocuparse por la infraestructura subyacente, lo que lo convierte en una excelente opción para proyectos frontend.&lt;/p&gt;

&lt;h3&gt;
  
  
  Beneficios de usar AWS App Runner para frontend:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Despliegue continuo integrado desde GitHub o AWS ECR.&lt;/li&gt;
&lt;li&gt;Escalamiento automático según la demanda.&lt;/li&gt;
&lt;li&gt;Certificados HTTPS automáticos y balanceo de carga.&lt;/li&gt;
&lt;li&gt;Integración nativa con servicios de AWS.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Arquitectura del Proyecto
&lt;/h2&gt;

&lt;p&gt;Vamos a desplegar una aplicación React como ejemplo, pero los conceptos se aplican a cualquier aplicación frontend que puedas contenerizar. Utilizaremos los siguientes componentes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Docker para crear la imagen del frontend.&lt;/li&gt;
&lt;li&gt;AWS ECR para almacenar la imagen del contenedor.&lt;/li&gt;
&lt;li&gt;AWS App Runner para el despliegue.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Paso 1: Crear el Proyecto React
&lt;/h2&gt;

&lt;p&gt;Comencemos creando una aplicación React de ejemplo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-react-app my-app-runner
&lt;span class="nb"&gt;cd &lt;/span&gt;my-app-runner
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vamos a construir la aplicación para producción:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esto generará una carpeta &lt;code&gt;build/&lt;/code&gt; con el contenido optimizado para despliegue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Paso 2: Crear el Dockerfile
&lt;/h2&gt;

&lt;p&gt;Ahora vamos a contenerizar nuestra aplicación utilizando un &lt;code&gt;Dockerfile&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dockerfile
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Etapa de construcción&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:20-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;builder&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package*.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build

&lt;span class="c"&gt;# Etapa de producción&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; nginx:stable-alpine&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /app/build /usr/share/nginx/html&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 80&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["nginx", "-g", "daemon off;"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este Dockerfile utiliza dos etapas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Builder:&lt;/strong&gt; Construye la aplicación utilizando Node.js.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Producción:&lt;/strong&gt; Utiliza un contenedor Nginx para servir los archivos estáticos.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Paso 3: Crear el Repositorio en AWS ECR
&lt;/h2&gt;

&lt;p&gt;Primero, inicia sesión en AWS CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws configure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Crea un repositorio en AWS ECR:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ecr create-repository &lt;span class="nt"&gt;--repository-name&lt;/span&gt; my-app-runner
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Obtén el URI del repositorio:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;aws ecr describe-repositories &lt;span class="nt"&gt;--repository-name&lt;/span&gt; my-app-runner &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'repositories[0].repositoryUri'&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; text&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Paso 4: Construir y Subir la Imagen
&lt;/h2&gt;

&lt;p&gt;Autentícate en ECR:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ecr get-login-password | docker login &lt;span class="nt"&gt;--username&lt;/span&gt; AWS &lt;span class="nt"&gt;--password-stdin&lt;/span&gt; &amp;lt;aws-account-id&amp;gt;.dkr.ecr.&amp;lt;region&amp;gt;.amazonaws.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Construye la imagen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; my-app-runner &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Etiqueta la imagen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker tag my-app-runner:latest &amp;lt;aws-account-id&amp;gt;.dkr.ecr.&amp;lt;region&amp;gt;.amazonaws.com/my-app-runner:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sube la imagen al repositorio ECR:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker push &amp;lt;aws-account-id&amp;gt;.dkr.ecr.&amp;lt;region&amp;gt;.amazonaws.com/my-app-runner:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Paso 5: Crear el Servicio en AWS App Runner
&lt;/h2&gt;

&lt;p&gt;Usaremos AWS CLI para crear el servicio.&lt;/p&gt;

&lt;h3&gt;
  
  
  Crear el Servicio
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws apprunner create-service &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--service-name&lt;/span&gt; my-app-runner &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--source-configuration&lt;/span&gt; &lt;span class="nv"&gt;ImageRepository&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;&lt;span class="nv"&gt;ImageIdentifier&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;aws-account-id&amp;gt;.dkr.ecr.&amp;lt;region&amp;gt;.amazonaws.com/my-app-runner:latest,ImageRepositoryType&lt;span class="o"&gt;=&lt;/span&gt;ECR&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--auto-deployments-enabled&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Verificar el Servicio
&lt;/h3&gt;

&lt;p&gt;Después de un par de minutos, el servicio estará desplegado. Puedes verificar el estado del servicio con:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws apprunner describe-service &lt;span class="nt"&gt;--service-arn&lt;/span&gt; &amp;lt;service-arn&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Paso 6: Configurar el Escalamiento Automático
&lt;/h2&gt;

&lt;p&gt;AWS App Runner escala automáticamente según el tráfico, pero podemos ajustar los parámetros si es necesario.&lt;/p&gt;

&lt;h3&gt;
  
  
  Actualizar el Servicio
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws apprunner update-service &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--service-arn&lt;/span&gt; &amp;lt;service-arn&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--auto-scaling-configuration-name&lt;/span&gt; default &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--min-capacity&lt;/span&gt; 1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--max-capacity&lt;/span&gt; 10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Paso 7: Pruebas de Despliegue
&lt;/h2&gt;

&lt;p&gt;Para verificar el despliegue, visita la URL proporcionada por App Runner. Realiza pruebas para asegurarte de que todo esté funcionando correctamente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consideraciones Finales
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;AWS App Runner&lt;/strong&gt; hace que el despliegue de aplicaciones frontend sea eficiente y escalable sin necesidad de administrar servidores o infraestructura compleja. Su integración con ECR garantiza que siempre puedas desplegar la última versión de tu aplicación con solo actualizar la imagen.&lt;/p&gt;

&lt;p&gt;Si tienes dudas o problemas durante el despliegue, ¡déjamelo saber en los comentarios! 😊&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Integración de PWA con AWS Amplify: Llevando tu Aplicación al Siguiente Nivel</title>
      <dc:creator>Gustavo Ramirez</dc:creator>
      <pubDate>Thu, 27 Mar 2025 19:05:52 +0000</pubDate>
      <link>https://dev.to/geramireze/integracion-de-pwa-con-aws-amplify-llevando-tu-aplicacion-al-siguiente-nivel-1bao</link>
      <guid>https://dev.to/geramireze/integracion-de-pwa-con-aws-amplify-llevando-tu-aplicacion-al-siguiente-nivel-1bao</guid>
      <description>&lt;p&gt;Las aplicaciones web progresivas (PWA) están revolucionando la manera en que construimos experiencias en la web. El rendimiento y la capacidad de trabajar sin conexión son esenciales en muchas aplicaciones modernas, y AWS Amplify ofrece una manera eficiente de llevar tu PWA a la nube sin complicaciones. En este artículo, vamos a ver cómo puedes configurar y desplegar una PWA utilizando AWS Amplify, paso a paso y con ejemplos prácticos.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Por qué usar AWS Amplify con PWA?
&lt;/h2&gt;

&lt;p&gt;Desplegar una PWA en AWS Amplify trae múltiples ventajas. No solo permite alojar contenido estático de forma eficiente, sino que también habilita características avanzadas como el despliegue continuo y la distribución global a través de CloudFront. Vamos a sumergirnos directamente en el proceso.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beneficios de usar AWS Amplify con PWA:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Despliegue continuo y gestión de versiones.&lt;/li&gt;
&lt;li&gt;Almacenamiento seguro de contenido estático en S3.&lt;/li&gt;
&lt;li&gt;Distribución de contenido global con CloudFront.&lt;/li&gt;
&lt;li&gt;Integración con servicios serverless como API Gateway y Lambda.&lt;/li&gt;
&lt;li&gt;Monitoreo y análisis con AWS CloudWatch.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Preparación del Entorno
&lt;/h2&gt;

&lt;p&gt;Antes de comenzar, asegúrate de tener configurado AWS CLI y Amplify CLI. Si no lo tienes instalado, puedes hacerlo ejecutando el siguiente comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @aws-amplify/cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configura Amplify con tus credenciales de AWS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;amplify configure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esto abrirá una página en tu navegador para iniciar sesión en AWS. Luego, selecciona la región y configura el perfil con un nombre fácil de identificar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inicialización del Proyecto
&lt;/h2&gt;

&lt;p&gt;Si ya tienes una aplicación frontend (por ejemplo, en React o Angular), ve al directorio del proyecto. De lo contrario, puedes crear una nueva aplicación con React usando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-react-app my-pwa
&lt;span class="nb"&gt;cd &lt;/span&gt;my-pwa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inicia el proyecto Amplify dentro del directorio del frontend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;amplify init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Responde a las preguntas de configuración:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nombre del proyecto: my-pwa&lt;/li&gt;
&lt;li&gt;Ambiente: dev&lt;/li&gt;
&lt;li&gt;Tipo de aplicación: javascript&lt;/li&gt;
&lt;li&gt;Framework: React&lt;/li&gt;
&lt;li&gt;Editor de código: Visual Studio Code&lt;/li&gt;
&lt;li&gt;Autenticación: No&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configuración del Hosting
&lt;/h2&gt;

&lt;p&gt;Vamos a habilitar el hosting directamente desde Amplify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;amplify add hosting
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Selecciona la opción de hosting con S3 y CloudFront. Esto garantiza un rendimiento óptimo en cualquier región.&lt;/p&gt;

&lt;p&gt;Para desplegar la aplicación, ejecuta:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;amplify publish
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este comando construye la aplicación y la despliega en el bucket de S3, configurando CloudFront para la entrega rápida de contenido.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementación de PWA
&lt;/h2&gt;

&lt;p&gt;Manifest.json&lt;/p&gt;

&lt;p&gt;Crea el archivo manifest.json en el directorio public/:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"short_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MyPWA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"My Progressive Web App"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"display"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"standalone"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"background_color"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#ffffff"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"theme_color"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#000000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"icons"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"src"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/logo192.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"image/png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"sizes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"192x192"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Service Worker
&lt;/h2&gt;

&lt;p&gt;Crea el archivo service-worker.js en src/ para manejar el caché:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;install&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;caches&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-pwa-cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addAll&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/logo192.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fetch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respondWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;caches&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Registro del Service Worker
&lt;/h2&gt;

&lt;p&gt;Modifica el archivo index.js para registrar el Service Worker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;serviceWorker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/service-worker.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Service Worker registrado con éxito&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error al registrar el SW:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Despliegue Final
&lt;/h2&gt;

&lt;p&gt;Finalmente, publica la aplicación ejecutando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;amplify publish
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El resultado incluirá una URL de CloudFront donde puedes acceder a tu aplicación PWA.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validación y Monitoreo
&lt;/h2&gt;

&lt;p&gt;Puedes monitorear el estado de la aplicación y el rendimiento desde el panel de AWS Amplify o usando CloudWatch para analizar los logs y métricas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reflexiones Finales
&lt;/h2&gt;

&lt;p&gt;Combinar PWA con AWS Amplify no solo mejora el rendimiento de tus aplicaciones web, sino que también aprovecha el poder de la nube para escalar fácilmente. Con estos pasos claros, tienes una aplicación progresiva lista para cualquier reto.&lt;/p&gt;

</description>
      <category>pwa</category>
      <category>aws</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Integrando Amazon Location Services en Angular 17: Guía Paso a Paso</title>
      <dc:creator>Gustavo Ramirez</dc:creator>
      <pubDate>Mon, 04 Mar 2024 20:08:24 +0000</pubDate>
      <link>https://dev.to/geramireze/integrando-amazon-location-services-en-angular-17-guia-paso-a-paso-dfj</link>
      <guid>https://dev.to/geramireze/integrando-amazon-location-services-en-angular-17-guia-paso-a-paso-dfj</guid>
      <description>&lt;h2&gt;
  
  
  Introducción
&lt;/h2&gt;

&lt;p&gt;Amazon Location Service proporciona capacidades de geolocalización como mapas y seguimiento de posiciones, todo mientras protege la privacidad del usuario. En este artículo, aprenderemos cómo integrar Amazon Location Service en una aplicación Angular 17, sin necesidad de Amplify, para agregar funciones de geolocalización.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requisitos previos
&lt;/h2&gt;

&lt;p&gt;Para seguir esta guía, necesitas lo siguiente:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Una cuenta de AWS con permisos adecuados.&lt;/li&gt;
&lt;li&gt;Angular CLI instalado y configurado (versión 17).&lt;/li&gt;
&lt;li&gt;Conocimientos básicos de TypeScript y Angular.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configuración en AWS
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Crear un recurso de Amazon Location Service&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ve a la consola de Amazon Location Service y crea un nuevo recurso, como un Mapa o un Índice de lugares.&lt;/li&gt;
&lt;li&gt;Anota el nombre del recurso, lo necesitarás más tarde.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Establecer permisos de IAM&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Crea una nueva política de IAM que permita el acceso a tu recurso de Amazon Location Service y asígnala a un usuario o rol.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Obtener credenciales de acceso&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ve a la consola de IAM y crea unas nuevas credenciales de acceso. Anota el Access Key ID y el Secret Access Key.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Configuración del proyecto Angular
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Crea un nuevo proyecto Angular&lt;/strong&gt; si aún no tienes uno:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   ng new my-location-app
   &lt;span class="nb"&gt;cd &lt;/span&gt;my-location-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Instala AWS SDK&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   npm &lt;span class="nb"&gt;install &lt;/span&gt;aws-sdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Configura tus credenciales y recurso en &lt;code&gt;environment.ts&lt;/code&gt;&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;   &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;production&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;awsConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tu-region&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="na"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="na"&gt;accessKeyId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tu-access-key-id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="na"&gt;secretAccessKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tu-secret-access-key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
       &lt;span class="p"&gt;},&lt;/span&gt;
       &lt;span class="na"&gt;locationService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="na"&gt;mapName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tu-nombre-de-mapa&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Implementación del servicio de ubicación
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Crea un servicio Angular para Amazon Location Service&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   ng generate service services/location
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Implementa métodos en tu servicio &lt;code&gt;location.service.ts&lt;/code&gt;&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Injectable&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../environments/environment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Location&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-sdk/clients/location&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
     &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
   &lt;span class="p"&gt;})&lt;/span&gt;
   &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LocationService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

     &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
         &lt;span class="na"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;awsConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;awsConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;region&lt;/span&gt;
       &lt;span class="p"&gt;});&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;

     &lt;span class="c1"&gt;// Método para obtener la posición actual (ejemplo)&lt;/span&gt;
     &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;getCurrentPosition&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="c1"&gt;// Implementa la lógica para obtener la posición actual&lt;/span&gt;
       &lt;span class="c1"&gt;// Esto dependerá de tu caso de uso específico&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Integración en componentes Angular
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Modifica tu componente para usar el servicio de ubicación&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;En tu componente, inyecta el &lt;code&gt;LocationService&lt;/code&gt; y utiliza sus métodos para obtener datos de ubicación o renderizar mapas.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LocationService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./services/location.service&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
     &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;templateUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.component.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;styleUrls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.component.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
   &lt;span class="p"&gt;})&lt;/span&gt;
   &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;locationService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LocationService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

     &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;locationService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCurrentPosition&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
         &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
         &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Pruebas y depuración
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Ejecuta tu aplicación Angular&lt;/strong&gt; para probar la integración:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   ng serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Navega a tu aplicación en el navegador y verifica que la integración funcione como se espera. Revisa la consola para cualquier log de error o mensaje relevante.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Al integrar Amazon Location Service en una aplicación Angular, puedes agregar fácilmente funcionalidades de geolocalización. Asegúrate de seguir las mejores prácticas de seguridad, como no exponer tus credenciales de AWS en el código de cliente y utilizar&lt;/p&gt;

&lt;p&gt;roles IAM adecuados.&lt;/p&gt;

&lt;p&gt;Espero que esta guía te haya sido útil. ¡Feliz codificación!&lt;/p&gt;

&lt;h2&gt;
  
  
  Referencias
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/location/index.html"&gt;Documentación oficial de Amazon Location Services&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://angular.io/guide/setup-local"&gt;Guía de Angular&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/sdk-for-javascript/index.html"&gt;Documentación de AWS SDK para JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Explorando el Rol del Frontend Data Engineer y Herramientas AWS para Especializarse</title>
      <dc:creator>Gustavo Ramirez</dc:creator>
      <pubDate>Mon, 04 Mar 2024 13:46:48 +0000</pubDate>
      <link>https://dev.to/geramireze/explorando-el-rol-del-frontend-data-engineer-y-herramientas-aws-para-especializarse-540p</link>
      <guid>https://dev.to/geramireze/explorando-el-rol-del-frontend-data-engineer-y-herramientas-aws-para-especializarse-540p</guid>
      <description>&lt;p&gt;En el mundo en constante evolución del desarrollo web, surge una nueva especialización: el Frontend Data Engineer. Esta disciplina combina la ingeniería de datos con el desarrollo frontend para crear experiencias de usuario ricas y personalizadas basadas en datos. En este artículo, exploraremos qué es un Frontend Data Engineer, sus fortalezas y qué herramientas de AWS puedes usar para ejecutar esta especialización de frontend.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué es un Frontend Data Engineer?
&lt;/h2&gt;

&lt;p&gt;Un Frontend Data Engineer es un profesional que se especializa en el manejo, procesamiento y visualización de datos en el lado del cliente. Este rol implica más que solo diseñar interfaces de usuario; también se trata de integrar y transformar datos de manera eficiente para mejorar la interacción del usuario y ofrecer insights en tiempo real.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fortalezas del Frontend Data Engineer:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Integración de Datos:&lt;/strong&gt; Capacidad para integrar diversas fuentes de datos y APIs para ofrecer una experiencia cohesiva y basada en datos.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Procesamiento y Análisis de Datos:&lt;/strong&gt; Habilidades para procesar y analizar datos en el navegador, permitiendo filtrados, ordenamientos y otros tipos de transformaciones de datos en tiempo real.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Visualización de Datos:&lt;/strong&gt; Competencia en implementar librerías de visualización para mostrar datos complejos de manera comprensible y atractiva.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Rendimiento y Optimización:&lt;/strong&gt; Conocimiento para asegurar que las aplicaciones manejen los datos de manera eficiente, minimizando el tiempo de carga y mejorando la experiencia del usuario.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Seguridad de Datos:&lt;/strong&gt; Conciencia crítica de las consideraciones de seguridad al manejar datos en el frontend.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Herramientas AWS para el Frontend Data Engineer
&lt;/h2&gt;

&lt;p&gt;AWS proporciona una serie de herramientas que pueden empoderar a los Frontend Data Engineers para construir soluciones robustas y basadas en datos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AWS Amplify:&lt;/strong&gt; Es un conjunto de herramientas y servicios que pueden ayudar a los desarrolladores frontend a construir aplicaciones fullstack escalables y seguras. Amplify facilita la integración con backend de AWS, autenticación, almacenamiento de datos, y más.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Amazon S3 y Amazon CloudFront:&lt;/strong&gt; Para almacenar y distribuir datos y archivos estáticos a escala. Estos servicios son fundamentales para manejar grandes volúmenes de datos y asegurar una entrega rápida y global.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AWS AppSync:&lt;/strong&gt; Permite crear aplicaciones impulsadas por datos con sincronización en tiempo real y programación offline. AppSync es excelente para aplicaciones que necesitan manejar datos en tiempo real y proporcionar experiencias de usuario interactivas.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Amazon Athena y Amazon QuickSight:&lt;/strong&gt; Para análisis y visualización de datos. Athena permite realizar consultas SQL directamente sobre datos almacenados en S3, y QuickSight puede usarse para crear visualizaciones interactivas y dashboards.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AWS Lambda:&lt;/strong&gt; Para ejecutar código en respuesta a eventos, lo que permite procesar datos en el backend sin administrar servidores. Esto es especialmente útil para tareas de procesamiento de datos que son demasiado intensivas para el cliente.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;En conclusión el papel del Frontend Data Engineer es vital en la creación de aplicaciones modernas, ricas en datos y centradas en el usuario. Al combinar habilidades de frontend con ingeniería de datos, estos profesionales pueden transformar datos brutos en experiencias de usuario significativas y perspicaces.&lt;/p&gt;

&lt;p&gt;Al utilizar herramientas de AWS, los Frontend Data Engineers pueden aprovechar la potencia de la nube para manejar datos a gran escala, mejorar la seguridad y la entrega de aplicaciones, y proporcionar análisis y visualizaciones poderosas directamente en el navegador.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Guía Paso a Paso para Probar la Responsividad de tu Sitio Web con AWS Device Farm</title>
      <dc:creator>Gustavo Ramirez</dc:creator>
      <pubDate>Mon, 04 Mar 2024 13:39:06 +0000</pubDate>
      <link>https://dev.to/geramireze/guia-paso-a-paso-para-probar-la-responsividad-de-tu-sitio-web-con-aws-device-farm-1bde</link>
      <guid>https://dev.to/geramireze/guia-paso-a-paso-para-probar-la-responsividad-de-tu-sitio-web-con-aws-device-farm-1bde</guid>
      <description>&lt;p&gt;En la era de los múltiples dispositivos, asegurar que tu sitio web sea 100% responsive es más crucial que nunca. AWS Device Farm ofrece una plataforma robusta que permite probar tu sitio web en una amplia gama de dispositivos reales. Aquí te mostraré cómo usar AWS Device Farm para validar la responsividad de tu sitio web de manera efectiva.&lt;/p&gt;

&lt;h2&gt;
  
  
  Paso 1: Preparativos
&lt;/h2&gt;

&lt;p&gt;Antes de comenzar, asegúrate de tener una cuenta de AWS. Si aún no tienes una, puedes crearla en el sitio web de AWS. También, familiarízate con AWS Device Farm y sus capacidades visitando la documentación oficial.&lt;/p&gt;

&lt;h2&gt;
  
  
  Paso 2: Configurar tu Proyecto en AWS Device Farm
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Inicia sesión&lt;/strong&gt; en tu consola de AWS y navega a AWS Device Farm.&lt;/li&gt;
&lt;li&gt;En la página de inicio de Device Farm, selecciona &lt;strong&gt;'Start a new project'&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Asigna un nombre a tu proyecto y haz clic en &lt;strong&gt;'Create'&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Paso 3: Crear una Prueba de Navegador Web
&lt;/h2&gt;

&lt;p&gt;Una vez que tu proyecto esté configurado, es hora de crear una nueva prueba para tu sitio web:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Dentro de tu proyecto, selecciona &lt;strong&gt;'Create a new run'&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Ahora, verás opciones para probar aplicaciones móviles o pruebas de navegador web. Selecciona &lt;strong&gt;'Web browser testing'&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Paso 4: Configurar las Pruebas
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Selecciona dispositivos:&lt;/strong&gt; AWS Device Farm ofrece una amplia gama de dispositivos reales. Selecciona los dispositivos en los que deseas probar tu sitio web. Puedes elegir diferentes dispositivos, sistemas operativos y configuraciones de navegador para asegurarte de que tu sitio sea completamente responsive.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Configura tu prueba:&lt;/strong&gt; Ingresa la URL de tu sitio web. Además, puedes configurar parámetros adicionales como tiempos de espera, capturas de pantalla y resoluciones de pantalla.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Paso 5: Ejecutar y Monitorear las Pruebas
&lt;/h2&gt;

&lt;p&gt;Una vez que hayas configurado todo:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Haz clic en &lt;strong&gt;'Start run'&lt;/strong&gt; para iniciar tus pruebas.&lt;/li&gt;
&lt;li&gt;Monitorea el progreso de tus pruebas en tiempo real. AWS Device Farm te proporcionará un informe detallado de la prueba, incluyendo capturas de pantalla, videos y registros.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Paso 6: Analizar los Resultados
&lt;/h2&gt;

&lt;p&gt;Después de que las pruebas se hayan completado:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Revisa los informes de las pruebas. AWS Device Farm proporciona una visión detallada de cómo se ve y se comporta tu sitio web en diferentes dispositivos y navegadores.&lt;/li&gt;
&lt;li&gt;Analiza problemas como elementos desalineados, textos ilegibles, imágenes que no se cargan o problemas de navegación.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Paso 7: Realizar Ajustes y Repetir
&lt;/h2&gt;

&lt;p&gt;Basándote en los resultados:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Realiza los ajustes necesarios en tu sitio web para abordar cualquier problema identificado.&lt;/li&gt;
&lt;li&gt;Vuelve a ejecutar las pruebas en AWS Device Farm para validar los cambios.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;AWS Device Farm es una herramienta poderosa que te permite asegurar que tu sitio web ofrezca una experiencia de usuario consistente y de alta calidad en todos los dispositivos y navegadores. Al integrar AWS Device Farm en tu flujo de trabajo de desarrollo y pruebas, puedes identificar y corregir problemas de responsividad antes de que afecten a tus usuarios finales.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Implementando Multi-Ambiente con `amplify.yml` en la Implementación de Angular 17 con SSR en AWS Amplify</title>
      <dc:creator>Gustavo Ramirez</dc:creator>
      <pubDate>Mon, 04 Mar 2024 13:30:10 +0000</pubDate>
      <link>https://dev.to/geramireze/implementando-multi-ambiente-con-amplifyyml-en-la-implementacion-de-angular-17-con-ssr-en-aws-amplify-3pb</link>
      <guid>https://dev.to/geramireze/implementando-multi-ambiente-con-amplifyyml-en-la-implementacion-de-angular-17-con-ssr-en-aws-amplify-3pb</guid>
      <description>&lt;p&gt;La implementación de diferentes ambientes (como desarrollo, pruebas y producción) es esencial para un flujo de trabajo de desarrollo eficiente y seguro. AWS Amplify permite una configuración detallada para múltiples ambientes utilizando el archivo &lt;code&gt;amplify.yml&lt;/code&gt;. A continuación, te muestro cómo configurar este archivo para manejar múltiples entornos en tu proyecto Angular con SSR.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuración del archivo &lt;code&gt;amplify.yml&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Cuando trabajas con AWS Amplify, el archivo &lt;code&gt;amplify.yml&lt;/code&gt; controla el proceso de construcción y despliegue de tu aplicación. Para configurar múltiples ambientes, puedes definir variables de entorno y comandos específicos para cada fase del despliegue. Aquí tienes un ejemplo de cómo estructurar tu &lt;code&gt;amplify.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="na"&gt;applications&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;frontend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;phases&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;preBuild&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm install&lt;/span&gt;
        &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm run build:ssr&lt;/span&gt;
      &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;baseDirectory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dist/mi-aplicacion-angular&lt;/span&gt;
        &lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;**/*'&lt;/span&gt;
      &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;node_modules/**/*&lt;/span&gt;
    &lt;span class="na"&gt;appRoot&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mi-aplicacion-angular&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este es un archivo de configuración básico. Ahora, vamos a añadir soporte para múltiples ambientes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Múltiples Ambientes
&lt;/h2&gt;

&lt;p&gt;Para manejar diferentes ambientes, puedes utilizar variables de entorno dentro de tu aplicación Angular y referenciarlas en tu archivo &lt;code&gt;amplify.yml&lt;/code&gt;. AWS Amplify permite definir estas variables para cada entorno directamente desde la consola de Amplify.&lt;/p&gt;

&lt;p&gt;Aquí tienes cómo puedes modificar el archivo &lt;code&gt;amplify.yml&lt;/code&gt; para utilizar variables de entorno:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="na"&gt;applications&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;frontend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;phases&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;preBuild&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm install&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;if&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;[&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"$AMPLIFY_ENV"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"production"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;];&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;then&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;npm&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;run&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;config:prod;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;else&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;npm&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;run&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;config:dev;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;fi'&lt;/span&gt;
        &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm run build:ssr&lt;/span&gt;
      &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;baseDirectory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dist/mi-aplicacion-angular/browser&lt;/span&gt;
        &lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;**/*'&lt;/span&gt;
      &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;node_modules/**/*&lt;/span&gt;
    &lt;span class="na"&gt;appRoot&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mi-aplicacion-angular&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En este ejemplo, &lt;code&gt;$AMPLIFY_ENV&lt;/code&gt; es una variable de entorno que puedes configurar en AWS Amplify para cada ambiente. Los comandos &lt;code&gt;npm run config:prod&lt;/code&gt; y &lt;code&gt;npm run config:dev&lt;/code&gt; deben ser scripts definidos en tu &lt;code&gt;package.json&lt;/code&gt; que configuren tu aplicación para cada entorno respectivamente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuración en la Consola de Amplify
&lt;/h2&gt;

&lt;p&gt;Para definir las variables de entorno en AWS Amplify:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ve a tu aplicación en la consola de Amplify.&lt;/li&gt;
&lt;li&gt;Selecciona "Configuración de la aplicación" y luego "Variables de entorno".&lt;/li&gt;
&lt;li&gt;Define &lt;code&gt;AMPLIFY_ENV&lt;/code&gt; con valores como &lt;code&gt;development&lt;/code&gt;, &lt;code&gt;production&lt;/code&gt;, etc., según tus ambientes.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Al configurar tu archivo &lt;code&gt;amplify.yml&lt;/code&gt; y utilizar las funcionalidades de AWS Amplify, puedes facilitar el manejo de múltiples ambientes para tu aplicación Angular con SSR. Esto no solo mejora la organización y la seguridad de tu flujo de trabajo de desarrollo, sino que también asegura que cada entorno esté correctamente configurado con las variables y configuraciones adecuadas.&lt;/p&gt;

&lt;p&gt;Siguiendo estos pasos, podrás desplegar eficientemente tu aplicación Angular en diferentes ambientes, maximizando la eficiencia y la efectividad de tus prácticas de CI/CD.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Configuración y Despliegue Avanzados de WordPress en AWS: Un Enfoque Moderno con RDS, App Runner y Copilot</title>
      <dc:creator>Gustavo Ramirez</dc:creator>
      <pubDate>Mon, 04 Mar 2024 13:05:27 +0000</pubDate>
      <link>https://dev.to/geramireze/configuracion-y-despliegue-avanzados-de-wordpress-en-aws-un-enfoque-moderno-con-rds-app-runner-y-copilot-3bo2</link>
      <guid>https://dev.to/geramireze/configuracion-y-despliegue-avanzados-de-wordpress-en-aws-un-enfoque-moderno-con-rds-app-runner-y-copilot-3bo2</guid>
      <description>&lt;p&gt;En este tutorial, exploraremos cómo llevar WordPress al siguiente nivel utilizando los servicios de AWS. Implementaremos WordPress con una base de datos Amazon RDS, lo alojaremos en AWS App Runner para una gestión sin servidor, y utilizaremos AWS Copilot para un despliegue eficiente. Además, introduciremos cómo integrar GraphQL para extender las capacidades del back-end de WordPress.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparativos Iniciales
&lt;/h2&gt;

&lt;p&gt;Antes de sumergirnos, asegúrate de tener una cuenta de AWS y las AWS CLI y Copilot CLI instaladas y configuradas en tu máquina. También necesitarás Docker para la creación y gestión de contenedores.&lt;/p&gt;

&lt;h2&gt;
  
  
  Paso 1: Configurando la Base de Datos con Amazon RDS
&lt;/h2&gt;

&lt;p&gt;Primero, configuraremos una base de datos segura y escalable utilizando Amazon RDS:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Crear la base de datos:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ve a la consola de RDS en AWS.&lt;/li&gt;
&lt;li&gt;Selecciona "Crear base de datos", elige MySQL o MariaDB (ambos compatibles con WordPress).&lt;/li&gt;
&lt;li&gt;Configura las opciones según tus necesidades, estableciendo un nombre de usuario y contraseña que deberás recordar para más adelante.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Seguridad:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Asegúrate de que la base de datos esté en una VPC segura y accesible para tu servicio de App Runner.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Conexión:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Anota el endpoint de RDS y los detalles de conexión para su uso posterior en la configuración de WordPress.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Paso 2: Preparando WordPress para App Runner y Docker
&lt;/h2&gt;

&lt;p&gt;Ahora, vamos a preparar WordPress para el despliegue:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Dockerfile:&lt;/strong&gt;
Crea un &lt;code&gt;Dockerfile&lt;/code&gt; en la raíz de tu proyecto WordPress con el siguiente contenido:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;   FROM wordpress:latest
   RUN docker-php-ext-install pdo pdo_mysql
   EXPOSE 80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este Dockerfile parte de la imagen oficial de WordPress, instala extensiones de PHP necesarias y expone el puerto 80.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Configuración de WordPress:&lt;/strong&gt;
Asegúrate de que el archivo &lt;code&gt;wp-config.php&lt;/code&gt; de WordPress esté configurado para usar las credenciales de tu base de datos RDS.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Paso 3: Implementando con AWS Copilot
&lt;/h2&gt;

&lt;p&gt;Con AWS Copilot, simplificaremos el proceso de despliegue:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Inicializar la aplicación:&lt;/strong&gt;
En tu terminal, navega a la carpeta de tu proyecto WordPress y ejecuta:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   copilot app init my-wordpress-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Crear y desplegar el servicio:&lt;/strong&gt;
Sigue las instrucciones para configurar tu servicio con App Runner:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   copilot svc init &lt;span class="nt"&gt;--name&lt;/span&gt; wordpress-service &lt;span class="nt"&gt;--dockerfile&lt;/span&gt; ./Dockerfile &lt;span class="nt"&gt;--deploy&lt;/span&gt;
   copilot svc deploy &lt;span class="nt"&gt;--name&lt;/span&gt; wordpress-service &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copilot construirá tu imagen Docker, la subirá a Amazon ECR y desplegará la aplicación en App Runner.&lt;/p&gt;

&lt;h2&gt;
  
  
  Paso 4: Integrando GraphQL con WordPress
&lt;/h2&gt;

&lt;p&gt;Para extender las capacidades de WordPress como un servicio de back-end, instala y activa el plugin WPGraphQL en tu instalación de WordPress. Esto proporcionará una API GraphQL de tus datos de WordPress que podrás consultar desde cualquier cliente front-end.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verificación y Pruebas
&lt;/h2&gt;

&lt;p&gt;Una vez completado el despliegue, AWS Copilot proporcionará una URL para acceder a tu servicio. Verifica que puedes acceder a tu sitio WordPress y que la conexión con la base de datos RDS funciona correctamente. Además, prueba la API GraphQL accediendo a &lt;code&gt;tusitio.com/graphql&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Al completar este tutorial, has logrado crear una instalación moderna y escalable de WordPress en AWS, utilizando servicios gestionados como Amazon RDS y AWS App Runner, y herramientas de despliegue como AWS Copilot. Esta configuración no solo mejora la seguridad y la escalabilidad, sino que también facilita la gestión de tu infraestructura.&lt;/p&gt;

&lt;p&gt;Además, al integrar GraphQL, has ampliado las capacidades de tu back-end de WordPress, permitiendo una interacción más flexible y potente con tus datos desde cualquier cliente front-end.&lt;/p&gt;

&lt;p&gt;Esperamos que este tutorial te haya proporcionado los conocimientos y herramientas necesarios para llevar tus proyectos de WordPress al siguiente nivel con AWS.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
