<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Gerard Sans on Medium]]></title>
        <description><![CDATA[Stories by Gerard Sans on Medium]]></description>
        <link>https://medium.com/@gerard-sans?source=rss-9530b046d2ac------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*0nZnCkNHZwj4-IN-5cIiFw.png</url>
            <title>Stories by Gerard Sans on Medium</title>
            <link>https://medium.com/@gerard-sans?source=rss-9530b046d2ac------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 01:53:13 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@gerard-sans/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Building Advanced AI Voice Assistants Using Google Gemini 3.1 Live and Angular]]></title>
            <link>https://medium.com/google-cloud/building-advanced-ai-voice-assistants-using-google-gemini-3-1-live-and-angular-1e8a516ebcb1?source=rss-9530b046d2ac------2</link>
            <guid isPermaLink="false">https://medium.com/p/1e8a516ebcb1</guid>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[voice-assistant]]></category>
            <category><![CDATA[gemini-live]]></category>
            <category><![CDATA[angular]]></category>
            <dc:creator><![CDATA[Gerard Sans]]></dc:creator>
            <pubDate>Sun, 24 May 2026 07:34:32 GMT</pubDate>
            <atom:updated>2026-05-24T07:34:32.548Z</atom:updated>
            <content:encoded><![CDATA[<p>Explore the Gemini Live API — a real-time, multimodal API for creating advanced, voice-first user experiences using the latest Gemini 3.1 Live models and the official Google GenAI SDK.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/900/0*0l0nrSIc9Wn5RSlx.png" /></figure><p>This article presents a quick-start project demonstrating Gemini 3.1 Live’s real-time, multimodal AI capabilities within an Angular web application.</p><h3>What’s Gemini Live?</h3><p>Gemini Live API is part of the <strong>Google Gemini</strong> model family, enabling a new generation of dynamic, multimodal, real-time AI experiences, as showcased in Pixel phones and the Gemini mobile app.</p><p>Gemini Live powers innovative applications across devices and platforms:</p><ul><li><strong>Hands-free AI Assistance</strong>: Users interact naturally through voice while cooking, driving, or multitasking.</li><li><strong>Real-time Visual Understanding</strong>: Get instant AI responses as you show objects, documents, or scenes through your camera.</li><li><strong>Smart Home Automation</strong>: Control your environment with natural voice commands — from adjusting lights to managing thermostats.</li><li><strong>Seamless Shopping</strong>: Browse products, compare options, and complete purchases through conversation.</li><li><strong>Live Problem Solving</strong>: Share your screen to get real-time guidance, troubleshooting, or explanations.</li><li><strong>Integration with Google services</strong>: Leverage existing Google services like Search or Maps to enhance its capabilities.</li></ul><h3>Try Gemini Live in the Gemini app (for iOS and Android)</h3><p>Gemini is <a href="https://blog.google/products-and-platforms/products/gemini/">now available on iPhone and Android</a>, so you can enjoy free, natural conversations with Gemini Live and get the most out of Google’s personal AI assistant.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ba9Yj7wyVOnXJKMV.jpeg" /></figure><h3>Try Gemini Live in Google AI Studio</h3><p>Before diving into the code, explore Gemini Live’s capabilities — voice interactions, webcam, and screen sharing — by using <a href="https://www.google.com/url?sa=E&amp;q=https%3A%2F%2Faistudio.google.com%2Flive">Google AI Studio Live</a>. This interactive playground will help you understand the available features and integration options before adding them to your projects.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*eycQQLHGnU7ZzQ0y.png" /></figure><h3>First step: Obtaining your API key from Google AI Studio</h3><p>Navigate to <a href="https://aistudio.google.com/app/apikey">aistudio.google.com</a> and generate an <strong>API key</strong>. You can check the global availability of the API <a href="https://ai.google.dev/gemini-api/docs/available-regions">here</a>.</p><h3>Cloning the Angular Application</h3><p>Run the following command in a folder of your choice to create a local copy of the project:</p><pre>$ git clone https://github.com/gsans/gemini-3-live-angular.git<br>&gt; Cloning into `Spoon-Knife`...<br>&gt; remote: Counting objects: 10, done.<br>&gt; remote: Compressing objects: 100% (8/8), done.<br>&gt; remove: Total 10 (delta 1), reused 10 (delta 1)<br>&gt; Unpacking objects: 100% (10/10), done.<br>$ cd gemini-3-live-angular<br>$ npm install</pre><p>These commands will download the complete repository and install its dependencies.</p><h3>System Requirements</h3><ul><li>Node.js and npm (latest stable version)</li><li>Angular CLI (globally installed via npm install -g @angular/cli)</li></ul><h3>Setting up the project</h3><p>Add a new environment by running the following command:</p><pre>ng g environments</pre><p>This creates the necessary files for development and production environments:</p><pre>src/environments/environment.development.ts<br>src/environments/environment.ts</pre><p>Modify the development file, replacing &lt;YOUR-API-KEY&gt; with your actual <strong>API Key</strong>:</p><pre>// src/environments/environment.development.ts<br>export const environment = {<br>  API_KEY: &quot;&lt;YOUR-API-KEY&gt;&quot;,<br>};</pre><p>To execute the code, run the following command in the terminal and navigate to localhost:4200 in your browser:</p><pre>ng serve</pre><h3>Usage Guide: Getting Started</h3><ol><li>Launch the application and click the Connect button under Connection Status.</li><li>This project requires a <strong>WebSocket connection</strong>, which will be used to send and receive real-time voice, images, and video from the Gemini Live API.</li><li>Monitor the browser’s <strong>Developer Tools Console</strong> for connection issues.</li><li>You can also use the <strong>Control Tray</strong>, located in the top right corner, to: toggle the microphone, share your screen or webcam, and use the play/pause button to start a conversation.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*1m7Jct2MdnNgHoi1.png" /></figure><h3>A few examples using Gemini’s Tools</h3><p>You can try any of the prompts you already use with Gemini. The following examples explore Gemini’s Tools that access real-time data via Google Search, execute Python code, or execute actions through external APIs.</p><h3>Gemini real-time access via Google Search</h3><p>Gemini can use Google Search to provide real-time information beyond the training data cut-off date and grounding to minimize hallucinations.</p><pre>Tell me the scores for the last 3 games of FC Barcelona.</pre><h3>Gemini using a Python sandbox via Code Execution</h3><p>Gemini can access a Python sandbox to generate and execute code as part of its response. This sandbox has access to libraries such as altair, chess, cv2, matplotlib, mpmath, numpy, pandas, pdfminer, reportlab, seaborn, sklearn, statsmodels, striprtf, sympy, and tabulate. matplotlib can generate 2D/3D diagrams as images.</p><blockquote>You can try this option in<em> </em><a href="https://aistudio.google.com/">Google AI Studio</a>. Enable<em> </em><em>_Code execution_ </em>in the<em> </em><em>_Tools_ </em>section of the<em> </em><em>_Run settings_ </em>panel.</blockquote><pre>What’s the 50th prime number?</pre><pre>What’s the square root of 342.12?</pre><h3>Gemini running an external weather API (mock) via Function Calling</h3><p>The function calling feature in <strong>Gemini</strong> allows you to provide users with access to tools: external APIs that provide real-time data or perform actions (e.g., making restaurant reservations or ordering food). These tools remain available throughout the conversation.</p><p>This example demonstrates this capability using a mock weather API. The model doesn’t directly call the function; instead, it generates structured output specifying the function name and suggested arguments. You’ll need to add code to handle the user request (as identified by Gemini) by calling the external API. Finally, provide the API’s output to Gemini, which formats the final answer for the user.</p><pre>What’s the weather in London?</pre><h3>Configuration Options</h3><p>The main configuration is handled in src/gemini/gemini-client.service.ts within the MultimodalLiveService class. You can customize the LiveConnectConfig settings, including response modalities (e.g. text vs. audio), proactivity features, and tools.</p><p>The application utilizes a dynamic model selection mechanism in getCustomConfig() based on the features enabled in the user interface Control Tray:</p><pre>// src/gemini/gemini-client.service.ts<br>if (user.affectiveAudio || user.proactiveAudio) {<br>  // Both Affective Dialog and Proactive Audio features are unsupported in gemini-3.1-flash-live-preview.<br>  model = &quot;gemini-2.5-flash-native-audio-latest&quot;;<br>} else {<br>  model = &quot;gemini-3.1-flash-live-preview&quot;;<br>}</pre><p>This ensures that advanced voice features like emotional tone sensing (Affective Dialog) and smart turn-taking (Proactive Audio) connect seamlessly using the specialized native-audio model, while normal sessions default to the fast, low-latency gemini-3.1-flash-live-preview model.</p><blockquote><strong>Usage Limits</strong>. Daily and session-based limits apply. Token count restrictions are in place to prevent abuse. If limits are exceeded, wait until the next day to resume.</blockquote><p>With the upgrade to Gemini 3.1 and the GenAI SDK, the application now natively supports bidirectional audio transcription directly via the inputAudioTranscription and outputAudioTranscription session configuration parameters. The service buffers and logs the live transcripts, displaying them in the side panel without requiring any third-party speech-to-text APIs.</p><h3>Technical Overview: Data Flow, Events and UI</h3><p>Compared to a standard Gemini’s client, this project introduces significant complexity due to its real-time streaming capabilities for audio (microphone and Gemini’s voice) and video (screen and webcam). This requires two clients: one for Gemini and another for the WebSocket. The following diagram illustrates the methods, observables, and events involved in the data flow.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*qZqjYc1y3YOalpMd.png" /></figure><h3>Managing the real-time connection (over WebSocket)</h3><p>Contrary to a REST API that follows a request-response protocol, WebSockets follow a bidirectional flow, meaning that both sides of the WebSocket channel can initiate or interrupt the communication. This creates three stages: setup handshake (open connection), bidirectional message exchange (connection remains open), and termination (one side closes the connection).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/507/0*IIhCPS0OvMMhbVAd.png" /></figure><h3>Processing Audio (Web Audio API)</h3><p>This section of the project manages both user microphone input (outgoing audio) and Gemini’s voice response (incoming audio) using the AudioRecorder and AudioStreamer classes, respectively.</p><blockquote><em>Audio processing within the </em><strong><em>Web Audio API</em></strong><em> occurs in a separate thread from the main UI thread, ensuring smooth performance, even under heavy load.</em></blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*5zHGUVgj-CgNX-k4.png" /></figure><ul><li>The AudioRecorder captures audio from the user’s microphone and sends it to the Gemini’s client via the sendRealtimeInput() method. This is accomplished using two <a href="https://developer.chrome.com/blog/audio-worklet">audio worklets</a>: worklet.audio-processing.ts and worklet.audio-meter.ts. The first worklet, worklet.audio-processing.ts, handles the core audio capture from navigator.mediaDevices.getUserMedia({ audio: true }), performing buffering and converting the audio data to a suitable format for transmission. The second worklet, worklet.audio-meter.ts, provides volume level data, used by the audio-pulse control to visually represent the audio levels from both the AudioRecorder (microphone) and the AudioStreamer (Gemini’s voice).</li><li>The AudioStreamer receives Gemini’s voice data through the ws.audio event handler (indicating audio data received from the WebSocket). It manages buffering and scheduling of audio chunks to ensure smooth, gap-free playback, even with network fluctuations. The Gemini’s client calls the AudioStreamer&#39;s addPCM16() method to pass the received audio data for playback.</li></ul><h3>Processing Video (WebRTC)</h3><p>This part of the project uses WebRTC to stream the screen or webcam to a video element. Using a separate process, we render a frame via a canvas element and send it over to the Gemini Live API using sendRealtimeInput().</p><blockquote><em>Current FPS is set to 0.5, or a frame every 2 seconds.</em></blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*pHZBw2En3Hlqm8NY.png" /></figure><h3>User Interface: connection, chat window, and control tray</h3><p>The user interface is split into three main blocks: the connection, the chat window, and the control tray. The chat window is followed by the video and canvas elements used by the control tray component. Below is a diagram showing the main methods behind each button, component inputs, and events.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*j--zYWdFWlLcSGTG.png" /></figure><h3>Gemini Live API Setup and Tools</h3><p>The Gemini Live API configuration is dynamically assembled in getCustomConfig() within src/gemini/gemini-client.service.ts based on active feature toggles (Affective Dialog, Proactive Audio) from the UI Control Tray component, falling back to the standard configurations on MultimodalLiveService. I recommend starting with a simpler project where you can learn each Gemini Tool separately. You can get started with this article below.</p><h3>Conclusion</h3><p>Congratulations! You have successfully accessed the <strong>Gemini Live API</strong>. Use the <a href="https://github.com/gsans/gemini-3-live-angular">completed GitHub project</a> as a reference to create your own features.</p><p>This tutorial covered the following:</p><ul><li>Introduction to the <strong>Gemini Live API</strong>.</li><li><strong>Project setup</strong> and getting started.</li><li>A few examples to showcase <strong>Gemini’s Tools</strong> (Code Execution, Google Search, and Function Calling).</li></ul><p>This project shows how to create a Gemini Live Client using WebSockets to stream images, documents, audio (microphone and Gemini Live voices), and video (screen sharing and webcam) from an Angular project.</p><h3>Building your own Voice-First Assistant Applications</h3><p>Use this project to start familiarizing yourself with real-time voice user interactions and build your own. These are some ideas to get you started:</p><ul><li>An <a href="https://gist.github.com/gsans/b730adb0239825eebc67dff7cccdcbf3">AI booking assistant</a> with access to your schedule, capable of handling dentist bookings and cancellations (via voice or chatbot interface).</li><li>An <a href="https://gist.github.com/gsans/41b2632650e4e27eeb562c45cceada9a">automated robot cafe</a> that takes orders and relays them to a robot barista (using voice, text, or visual interactive controls).</li></ul><h3>Thanks for reading!</h3><p>Do you have any questions? Feel free to leave your comments below or contact me on Twitter at @<a href="https://twitter.com/gerardsans">gerardsans</a>.</p><h3>Resources</h3><ul><li><a href="https://github.com/googleapis/js-genai">Google AI TypeScript SDK</a></li><li><a href="https://ai.google.dev/gemini-api/docs/live-api">Multimodal (Gemini) Live API</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1e8a516ebcb1" width="1" height="1" alt=""><hr><p><a href="https://medium.com/google-cloud/building-advanced-ai-voice-assistants-using-google-gemini-3-1-live-and-angular-1e8a516ebcb1">Building Advanced AI Voice Assistants Using Google Gemini 3.1 Live and Angular</a> was originally published in <a href="https://medium.com/google-cloud">Google Cloud - Community</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building Advanced AI Voice Assistants Using Google Gemini 2.0 and Angular]]></title>
            <link>https://gerard-sans.medium.com/building-advanced-ai-voice-assistants-using-google-gemini-2-0-and-angular-81ca0fa68ff6?source=rss-9530b046d2ac------2</link>
            <guid isPermaLink="false">https://medium.com/p/81ca0fa68ff6</guid>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[angular]]></category>
            <category><![CDATA[google-ai]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[google-gemini]]></category>
            <dc:creator><![CDATA[Gerard Sans]]></dc:creator>
            <pubDate>Sun, 09 Mar 2025 01:37:54 GMT</pubDate>
            <atom:updated>2026-05-23T16:17:42.642Z</atom:updated>
            <content:encoded><![CDATA[<p>Explore the Gemini Live API (Experimental) — a real-time, multimodal API for creating advanced, voice-first user experiences.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/900/1*YWbHffsZf4WBNxwrwukD6Q.png" /></figure><p>This article presents a quick-start project demonstrating Gemini 2.0’s real-time, multimodal AI capabilities within an Angular web application.</p><blockquote><em>This project originated as an Angular adaptation of the</em> <a href="https://www.google.com/url?sa=E&amp;q=https%3A%2F%2Fgithub.com%2Fgoogle-gemini%2Fmultimodal-live-api-web-console"><em>Multimodal Live API — Web console</em></a><em>, which is presently only available in React. The Gemini Live API is in active development and may change; there is currently no official JavaScript client or SDK.</em></blockquote><h3>What’s Gemini Live?</h3><p>Gemini Live API is part of <strong>Google Gemini 2.0</strong>, enabling a new generation of dynamic, multimodal, real-time AI experiences, as showcased in Pixel 9 phones and the Gemini app for Mobile (iOS and Android).</p><p>Gemini Live powers innovative applications across devices and platforms:</p><ul><li><strong>Hands-free AI Assistance</strong>: Users interact naturally through voice while cooking, driving, or multitasking.</li><li><strong>Real-time Visual Understanding</strong>: Get instant AI responses as you show objects, documents, or scenes through your camera.</li><li><strong>Smart Home Automation</strong>: Control your environment with natural voice commands — from adjusting lights to managing thermostats.</li><li><strong>Seamless Shopping</strong>: Browse products, compare options, and complete purchases through conversation.</li><li><strong>Live Problem Solving</strong>: Share your screen to get real-time guidance, troubleshooting, or explanations.</li><li><strong>Integration with Google services</strong>: Leverage existing Google services like Search or Maps to enhance its capabilities.</li></ul><h4>Try Gemini Live in the Gemini app (for iOS and Android)</h4><p>Gemini is <a href="https://blog.google/products/gemini/gemini-iphone-app/">now available on iPhone and Android</a>, so you can enjoy free, natural conversations with Gemini Live and get the most out of Google’s personal AI assistant.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*bzztNrvH8TzSmby27lwrrw@2x.jpeg" /></figure><h4>Try Gemini Live in Google AI Studio</h4><p>Before diving into the code, explore Gemini Live’s capabilities — voice interactions, webcam, and screen sharing — by using <a href="https://www.google.com/url?sa=E&amp;q=https%3A%2F%2Faistudio.google.com%2Flive">Google AI Studio Live</a>. This interactive playground will help you understand the available features and integration options before adding them to your projects.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*OYpLxTSKSctT8YOYrlgY5Q@2x.jpeg" /></figure><h3>First step: Obtaining your API key from Google AI Studio</h3><p>Navigate to <a href="https://aistudio.google.com/app/apikey">aistudio.google.com</a> and generate an <strong>API key</strong>. You can check the global availability of the API <a href="https://ai.google.dev/gemini-api/docs/available-regions">here</a>.</p><h3>Cloning the Angular Application</h3><p>Run the following command in a folder of your choice to create a local copy of the project:</p><pre>$ git clone https://github.com/gsans/gemini-2-live-angular.git<br><br>&gt; Cloning into `Spoon-Knife`...<br>&gt; remote: Counting objects: 10, done.<br>&gt; remote: Compressing objects: 100% (8/8), done.<br>&gt; remove: Total 10 (delta 1), reused 10 (delta 1)<br>&gt; Unpacking objects: 100% (10/10), done.<br><br>$ cd gemini-2-live-angular<br>$ npm install</pre><p>These commands will download the complete repository and install its dependencies.</p><h4>System Requirements</h4><ul><li>Node.js and npm (latest stable version)</li><li>Angular CLI (globally installed via npm install -g @angular/cli)</li></ul><h4>Setting up the project</h4><p>Add a new environment by running the following command:</p><pre>ng g environments</pre><p>This creates the necessary files for development and production environments:</p><pre>src/environments/environment.development.ts<br>src/environments/environment.ts</pre><p>Modify the development file, replacing &lt;YOUR-API-KEY&gt; with your actual <strong>API Key</strong>:</p><pre>// src/environments/environment.development.ts<br>export const environment = {<br>  API_KEY: &quot;&lt;YOUR-API-KEY&gt;&quot;,<br>  WS_URL: &quot;wss://generativelanguage.googleapis.com/ws/google.ai.generativelanguage.v1alpha.GenerativeService.BidiGenerateContent&quot;,<br>};</pre><p>To execute the code, run the following command in the terminal and navigate to localhost:4200 in your browser:</p><pre>ng serve</pre><h3>Usage Guide: Getting Started</h3><ol><li>Launch the application and click the Connect button under Connection Status.</li><li>This project requires a <strong>WebSocket connection</strong>, which will be used to send and receive real-time voice, images, and video from the Gemini Live API.</li><li>Monitor the browser’s <strong>Developer Tools Console</strong> for connection issues.</li><li>You can also use the <strong>Control Tray</strong>, located in the top right corner, to: toggle the microphone, share your screen or webcam, and use the play/pause button to start a conversation.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CaMoyGP4XaSkkqrxGzgujA.png" /></figure><h3>A few examples using Gemini’s Tools</h3><p>You can try any of the prompts you already use with Gemini. The following examples explore Gemini’s Tools that access real-time data via Google Search, execute Python code, or execute actions through external APIs.</p><h4>Gemini real-time access via Google Search</h4><p>Gemini can use Google Search to provide real-time information beyond the training data cut-off date and grounding to minimize hallucinations.</p><pre>Tell me the scores for the last 3 games of FC Barcelona.</pre><h4>Gemini using a Python sandbox via Code Execution</h4><p>Gemini can access a Python sandbox to generate and execute code as part of its response. This sandbox has access to libraries such as altair, chess, cv2, matplotlib, mpmath, numpy, pandas, pdfminer, reportlab, seaborn, sklearn, statsmodels, striprtf, sympy, and tabulate. matplotlib can generate 2D/3D diagrams as images.</p><blockquote><em>You can try this option in </em><a href="https://aistudio.google.com/"><em>Google AI Studio</em></a><em>. Enable </em><em>Code execution in the </em><em>Tools section of the </em><em>Run settings panel.</em></blockquote><pre>What’s the 50th prime number?</pre><pre>What’s the square root of 342.12?</pre><h4>Gemini running an external weather API (mock) via Function Calling</h4><p>The function calling feature in <strong>Gemini</strong> allows you to provide users with access to tools: external APIs that provide real-time data or perform actions (e.g., making restaurant reservations or ordering food). These tools remain available throughout the conversation.</p><p>This example demonstrates this capability using a mock weather API. The model doesn’t directly call the function; instead, it generates structured output specifying the function name and suggested arguments. You’ll need to add code to handle the user request (as identified by Gemini) by calling the external API. Finally, provide the API’s output to Gemini, which formats the final answer for the user.</p><pre>What’s the weather in London?</pre><p>For a more complex example of Function Calling implementing CRUD, see <a href="https://github.com/google-gemini/multimodal-live-api-web-console/tree/demos/genlist">GenList</a>.</p><h3>Configuration Options</h3><p>The main configuration is handled in src/app.component. You can toggle between audio and text modalities:</p><pre>let config: LiveConfig = {<br>  model: &quot;models/gemini-2.0-flash-exp&quot;,<br>  generationConfig: {<br>    // For text responses in chat window<br>    responseModalities: &quot;text&quot;,<br>    <br>    // For audio responses (uncomment to enable)<br>    // responseModalities: &quot;audio&quot;,<br>    // speechConfig: {<br>    //   voiceConfig: { prebuiltVoiceConfig: { voiceName: &quot;Aoede&quot; } },<br>    // },<br>  },<br>}</pre><blockquote><strong><em>Usage Limits</em></strong><em>. Daily and session-based limits apply. Token count restrictions are in place to prevent abuse. If limits are exceeded, wait until the next day to resume.</em></blockquote><p>At the moment, the audio option is not sending over the transcript or corresponding text to your voice commands or Gemini’s voice responses. You can use an external speech-to-text API to achieve this, like <a href="https://deepgram.com/learn/best-speech-to-text-apis">Deepgram</a>. This exercise is left to the reader to avoid adding further complexity to the current project. Let me know if you don’t know how to approach this task.</p><h3>Technical Overview: Data Flow, Events and UI</h3><p>Compared to a standard Gemini’s client, this project introduces significant complexity due to its real-time streaming capabilities for audio (microphone and Gemini’s voice) and video (screen and webcam). This requires two clients: one for Gemini and another for the WebSocket. The following diagram illustrates the methods, observables, and events involved in the data flow.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4M5psp3uYxD78OC81yQyRg.png" /></figure><h4>Managing the real-time connection (over WebSocket)</h4><p>Contrary to a REST API that follows a request-response protocol, WebSockets follow a bidirectional flow, meaning that both sides of the WebSocket channel can initiate or interrupt the communication. This creates three stages: setup handshake (open connection), bidirectional message exchange (connection remains open), and termination (one side closes the connection).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/507/1*iD4b3cpktXvBVa1mMJC1Uw.png" /><figcaption>Comparison of HTTP/REST and WebSocket communication protocols. WebSockets maintain an open connection for bidirectional communication.</figcaption></figure><h4>Processing Audio (Web Audio API)</h4><p>This section of the project manages both user microphone input (outgoing audio) and Gemini’s voice response (incoming audio) using the <strong>AudioRecorder</strong> and <strong>AudioStreamer</strong> classes, respectively.</p><blockquote>Audio processing within the <strong>Web Audio API</strong> occurs in a separate thread from the main UI thread, ensuring smooth performance, even under heavy load.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7ttyiSjrr__GHKIJZnPUXw.png" /></figure><ul><li>The <strong>AudioRecorder</strong> captures audio from the user’s microphone and sends it to the Gemini’s client via the sendRealtimeInput() method. This is accomplished using two <a href="https://developer.chrome.com/blog/audio-worklet">audio worklets</a>: worklet.audio-processing.ts and worklet.audio-meter.ts. The first worklet, worklet.audio-processing.ts, handles the core audio capture from navigator.mediaDevices.getUserMedia({ audio: true }), performing buffering and converting the audio data to a suitable format for transmission. The second worklet, worklet.audio-meter.ts, provides volume level data, used by the audio-pulse control to visually represent the audio levels from both the AudioRecorder (microphone) and the AudioStreamer (Gemini’s voice).</li><li>The <strong>AudioStreamer</strong> receives Gemini’s voice data through the ws.audio event handler (indicating audio data received from the WebSocket). It manages buffering and scheduling of audio chunks to ensure smooth, gap-free playback, even with network fluctuations. The Gemini’s client calls the AudioStreamer&#39;s addPCM16() method to pass the received audio data for playback.</li></ul><h4>Processing Video (WebRTC)</h4><p>This part of the project uses WebRTC to stream the screen or webcam to a video element. Using a separate process, we render a frame via a canvas element and send it over to the Gemini Live API using sendRealtimeInput().</p><blockquote>Current FPS is set to 0.5, or a frame every 2 seconds.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ioRQqQuz7jZ_sN40tv19ow.png" /></figure><h4>User Interface: connection, chat window, and control tray</h4><p>The user interface is split into three main blocks: the connection, the chat window, and the control tray. The chat window is followed by the video and canvas elements used by the control tray component. Below is a diagram showing the main methods behind each button, component inputs, and events.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mRHcEvhU_0ur_fyuIcw5zg.png" /><figcaption>Overview of the user interface components and their interactions. The app-control-tray component manages user input for microphone, webcam, and screen sharing.</figcaption></figure><h4>Gemini Live API Setup and Tools</h4><p>The Gemini Live API configuration can be found in the connect method in src/app/app.component.ts and, if left empty, in the config property in the MultimodalLiveService. I recommend starting with a simpler project where you can learn each Gemini Tool separately. You can get started with this article below.</p><p><a href="https://gerard-sans.medium.com/building-advanced-chatbots-with-angular-and-google-gemini-2-0-real-time-data-tools-and-apis-c917d3c594ba">Building Advanced Chatbots with Angular and Google Gemini 2.0: Real-Time Data, Tools, and APIs</a></p><h3>Conclusion</h3><p>Congratulations! You have successfully accessed the <strong>Gemini Live API</strong>. Use the <a href="https://github.com/gsans/gemini-2-live-angular">completed GitHub project</a> as a reference to create your own features.</p><p>This tutorial covered the following:</p><ul><li>Introduction to the <strong>Gemini Live API</strong>.</li><li><strong>Project setup</strong> and getting started.</li><li>A few examples to showcase <strong>Gemini’s Tools</strong> (Code Execution, Google Search, and Function Calling).</li></ul><p>This project shows how to create a Gemini Live Client using WebSockets to stream images, documents, audio (microphone and Gemini Live voices), and video (screen sharing and webcam) from an Angular project.</p><h3>Building your own Voice-First Assistant Applications</h3><p>Use this project to start familiarizing yourself with real-time voice user interactions and build your own. These are some ideas to get you started:</p><ul><li>An <a href="https://gist.github.com/gsans/b730adb0239825eebc67dff7cccdcbf3">AI booking assistant</a> with access to your schedule, capable of handling dentist bookings and cancellations (via voice or chatbot interface).</li><li>An <a href="https://gist.github.com/gsans/41b2632650e4e27eeb562c45cceada9a">automated robot cafe</a> that takes orders and relays them to a robot barista (using voice, text, or visual interactive controls).</li></ul><p>There are <a href="https://github.com/google-gemini/multimodal-live-api-web-console">more examples</a> available created by the Gemini team using React.</p><h3>Thanks for reading!</h3><p>Do you have any questions? Feel free to leave your comments below or contact me on Twitter at @<a href="https://twitter.com/gerardsans">gerardsans</a>.</p><h3>Resources</h3><ul><li><a href="https://github.com/google/generative-ai-js">Google AI JavaScript SDK</a></li><li><a href="https://ai.google.dev/gemini-api/docs/multimodal-live">Multimodal (Gemini) Live API</a></li></ul><h3>Final Warning</h3><p>The official version of the Gemini Live API in the JavaScript SDK, once released, will likely have a different implementation and API design, with improvements in security and performance (possibly using WebAssembly). This project is at the forefront of innovation and may already be outdated by the time you read this. However, it is still a great way to get ahead and learn about the future of voice AI assistants today.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=81ca0fa68ff6" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Build AI-Powered Angular Apps with Google Gemini]]></title>
            <link>https://medium.com/google-cloud/build-ai-powered-angular-apps-with-google-gemini-5bf5e905ca1d?source=rss-9530b046d2ac------2</link>
            <guid isPermaLink="false">https://medium.com/p/5bf5e905ca1d</guid>
            <category><![CDATA[google-gemini]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[vertex-ai]]></category>
            <category><![CDATA[google-cloud-platform]]></category>
            <category><![CDATA[angular]]></category>
            <dc:creator><![CDATA[Gerard Sans]]></dc:creator>
            <pubDate>Mon, 26 Feb 2024 23:36:43 GMT</pubDate>
            <atom:updated>2024-02-27T02:59:36.005Z</atom:updated>
            <content:encoded><![CDATA[<p>A step-by-step guide to integrating Google Gemini into your Angular applications.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DPd7v78cGIKescuSa7KQuw.png" /></figure><p>In this post, you are going to learn how to access <strong>Gemini APIs</strong> to create the next generation of AI-enabled Applications using <strong>Angular</strong>.</p><p>We’ll build a simple application to test <strong>Gemini Pro </strong>and<strong> Gemini Pro Visual </strong>via the official client. As a bonus, we will also show how you can use <strong>Vertex AI</strong> via its REST API.</p><p>Here’s what we’ll cover:</p><ul><li><a href="#4026">Introduction to <strong>Google Gemini</strong></a></li><li><a href="#538f">Getting your <strong>API key </strong>from Google AI Studio</a></li><li><a href="#bb13">Creating the <strong>Angular Application</strong></a></li><li><a href="#1480">Generate text from <strong>text-only input</strong> (text)</a></li><li><a href="#8645">Generate text from <strong>text-and-images input</strong> (multimodal)</a></li><li><a href="#b2d7">Build <strong>multi-turn conversations</strong> (chat)</a></li><li><a href="#14f6">Generate content using <strong>streaming</strong> (stream)</a></li><li><a href="#07a8">Bonus: generate AI content with <strong>Vertex AI</strong> via the REST API</a></li><li><a href="#5117">Running the code</a> and <a href="#5b8e">verifying the response</a></li><li><a href="#f02a">Conclusions</a></li></ul><h3>Introduction to Google Gemini</h3><p>Google Gemini is a family of large language models (LLMs) offering state-of-the-art AI capabilities created by Google AI. Gemini models include:</p><ul><li><strong>Gemini Ultra</strong>. The largest and most powerful model, excels in complex tasks like coding, logical reasoning, and creative collaboration. Available through Gemini Advanced (formerly Bard).</li><li><strong>Gemini Pro.</strong> A mid-size model optimised for diverse tasks, offers performance comparable to Ultra. Available through Gemini Chatbot and in Google Workspace and Google Cloud. <strong>Gemini</strong> <strong>Pro 1.5 </strong>has improved performance, including a breakthrough in long-context understanding up to a million tokens including text, code, images, audio and video.</li><li><strong>Gemini Nano</strong>. A lightweight model designed for on-device use, brings AI capabilities to mobile phones and small devices. Available on Pixel 8 and Samsung S24 series.</li><li><strong>Gemma.</strong> Open-source models inspired by Gemini, offers state-of-the-art performance at smaller sizes and designed with responsible AI principles in mind.</li></ul><h3>Getting your API key from Google AI Studio</h3><p>Go to <a href="https://aistudio.google.com/app/apikey">aistudio.google.com</a> and create an <strong>API key</strong>. If you are not based in the US, you can use <strong>Vertex AI</strong> which is available globally or use a VPN service.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*SEkWei5incODflt47_o7xQ.png" /><figcaption>Use the API Key together with Google AI JavaScript SDK or the REST API.</figcaption></figure><h3>Creating the Angular Application</h3><p>Use the <strong>Angular CLI</strong> to generate a new application:</p><pre>ng new google-ai-gemini-angular</pre><p>This scaffolds a new project with the latest Angular version.</p><h4>Setting up the project</h4><p>Run this command to add a new environment:</p><pre>ng g environments</pre><p>This will create the following files for development and production:</p><pre>src/environments/environment.development.ts<br>src/environments/environment.ts</pre><p>Edit the development file to include your <strong>API Key</strong>:</p><pre>// src/environments/environment.development.ts<br>export const environment = {<br>  API_KEY: &quot;&lt;YOUR-API-KEY&gt;&quot;,<br>};</pre><h3>Google AI JavaScript SDK</h3><p>This is the official client to access Gemini models. We will use it to:</p><ul><li>Generate text from text-only input (text)</li><li>Generate text from text-and-images input (multimodal)</li><li>Build multi-turn conversations (chat)</li><li>Generate content as is created using streaming (stream)</li></ul><p>Add this package to your project:</p><pre>npm install @google/generative-ai</pre><h3>Initialise your model</h3><p>Before calling Gemini we need to go through the model initialisation. This includes the following steps:</p><ol><li>Initialising GoogleGenerativeAI client with your <strong>API key</strong>.</li><li>Choosing a Gemini model: gemini-pro or gemini-pro-vision.</li><li>Setting up model parameters including safetySettings, temperature, top_p, top_k and maxOutputTokens.</li></ol><pre>import {<br>  GoogleGenerativeAI, HarmBlockThreshold, HarmCategory <br>} from &#39;@google/generative-ai&#39;;<br><br>...<br>const genAI = new GoogleGenerativeAI(environment.API_KEY);<br>const generationConfig = {<br>  safetySettings: [<br>    {<br>      category: HarmCategory.HARM_CATEGORY_HARASSMENT,<br>      threshold: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE,<br>    },<br>  ],<br>  temperature: 0.9,<br>  top_p: 1,<br>  top_k: 32,<br>  maxOutputTokens: 100, // limit output<br>};<br>const model = genAI.getGenerativeModel({<br>  model: &#39;gemini-pro&#39;, // or &#39;gemini-pro-vision&#39;<br>  ...generationConfig,<br>});<br>...</pre><p>For <a href="https://ai.google.dev/docs/safety_setting_gemini">Safety settings</a> you can use the defaults (block medium or high) or adjust them to your needs. In the example, we increased the threshold for harassment to block outputs with low probability or above to be unsafe. You can find a more detailed explanation <a href="https://ai.google.dev/docs/safety_setting_gemini">here</a>.</p><p>These are all the <a href="https://ai.google.dev/models/gemini">models available</a> and their default settings. Theres a limit of 60 request per minute. You can learn more about model parameters <a href="https://ai.google.dev/docs/concepts#model-parameters">here</a>.</p><h3>Generate text from text-only input (text)</h3><p>Below you can see a code snippet demonstrating <strong>Gemini Pro</strong> with a text-only input.</p><pre>async TestGeminiPro() {<br>  // Model initialisation missing for brevity<br><br>  const prompt = &#39;What is the largest number with a name?&#39;;<br>  const result = await model.generateContent(prompt);<br>  const response = await result.response;<br>  console.log(response.text());<br>}</pre><h3>Generate text from text-and-images input (multimodal)</h3><p>This example demonstrates how to use <strong>Gemini Pro Vision</strong> with text and images as input. We are using an image in src/assets for convenience.</p><pre>async TestGeminiProVisionImages() {<br>  try {<br>    let imageBase64 = await this.fileConversionService.convertToBase64(<br>      &#39;assets/baked_goods_2.jpeg&#39;<br>    );<br>  <br>    // Check for successful conversion to Base64<br>    if (typeof imageBase64 !== &#39;string&#39;) {<br>      console.error(&#39;Image conversion to Base64 failed.&#39;);<br>      return;<br>    }<br>    // Model initialisation missing for brevity<br>    let prompt = [<br>      {<br>        inlineData: {<br>          mimeType: &#39;image/jpeg&#39;,<br>          data: imageBase64,<br>        },<br>      },<br>      {<br>        text: &#39;Provide a recipe.&#39;,<br>      },<br>    ];<br>    const result = await model.generateContent(prompt);<br>    const response = await result.response;<br>    console.log(response.text());<br>  } catch (error) {<br>    console.error(&#39;Error converting file to Base64&#39;, error);<br>  }<br>}</pre><p>In order to convert the input image into Base64 you can use the FileConversionService below or an external library.</p><pre>// file-conversion.service.ts<br>import { Injectable } from &#39;@angular/core&#39;;<br>import { HttpClient } from &#39;@angular/common/http&#39;;<br>import { firstValueFrom } from &#39;rxjs&#39;;<br><br>@Injectable({<br>  providedIn: &#39;root&#39;,<br>})<br>export class FileConversionService { <br>  constructor(private http: HttpClient) {}<br>  async convertToBase64(filePath: string): Promise&lt;string | ArrayBuffer | null&gt; {<br>    const blob = await firstValueFrom(this.http.get(filePath, { responseType: &#39;blob&#39; }));<br>    return new Promise((resolve, reject) =&gt; {<br>      const reader = new FileReader();<br>      reader.onloadend = () =&gt; {<br>        const base64data = reader.result as string; <br>        resolve(base64data.substring(base64data.indexOf(&#39;,&#39;) + 1)); // Extract only the Base64 data<br>      };<br>      reader.onerror = error =&gt; {<br>        reject(error);<br>      };<br>      reader.readAsDataURL(blob);<br>    });<br>  }<br>}</pre><p>Image requirements for Gemini:</p><ul><li>Supported <a href="https://developers.google.com/drive/api/guides/ref-export-formats">MIME types</a>: image/png, image/jpeg, image/webp, image/heic and image/heif.</li><li>Maximum of 16 images.</li><li>Maximum of 4MB including images and text.</li><li>Large images are scaled down to fit 3072 x 3072 pixels while preserving their original aspect ratio.</li></ul><h3>Build multi-turn conversations (chat)</h3><p>This example shows how to use <strong>Gemini Pro</strong> to build a multi-turn conversation.</p><pre>async TestGeminiProChat() {<br>  // Model initialisation missing for brevity<br>  <br>  const chat = model.startChat({<br>    history: [<br>      {<br>        role: &quot;user&quot;,<br>        parts: &quot;Hi there!&quot;,<br>      },<br>      {<br>        role: &quot;model&quot;,<br>        parts: &quot;Great to meet you. What would you like to know?&quot;,<br>      },<br>    ],<br>    generationConfig: {<br>      maxOutputTokens: 100,<br>    },<br>  });<br>  const prompt = &#39;What is the largest number with a name? Brief answer.&#39;;<br>  const result = await chat.sendMessage(prompt);<br>  const response = await result.response;<br>  console.log(response.text());<br>  }</pre><blockquote>You can use the initial user message in the history as a <strong>system prompt</strong>. Just remember to include a model response acknowledging the instructions. Example: User: adopt the role and writing style of a pirate. Don’t lose character. Reply understood if you understand these instructions. Model: Understood.</blockquote><h3>Generate content as is created using streaming (stream)</h3><p>This example demonstrates how to use <strong>Gemini Pro</strong> to generate content using streaming.</p><pre>async TestGeminiProStreaming() {<br>  // Model initialisation missing for brevity<br>  <br>  const prompt = {<br>    contents: [<br>      {<br>        role: &#39;user&#39;,<br>        parts: [<br>          {<br>            text: &#39;Generate a poem.&#39;,<br>          },<br>        ],<br>      },<br>    ],<br>  };<br>  const streamingResp = await model.generateContentStream(prompt);<br>  for await (const item of streamingResp.stream) {<br>    console.log(&#39;stream chunk: &#39; + item.text());<br>  }<br>  console.log(&#39;aggregated response: &#39; + (await streamingResp.response).text());<br>}</pre><p>As a result of generateContentStream you will receive and object where you can read each chunk stream as is generated and the final response.</p><h3>Bonus: generate AI content with Vertex AI via the REST API</h3><p>As an alternative to the official JavaScript client you can use the Gemini REST API provided by Vertex AI. Vertex AI is a full AI platform made available as a managed service in Google Cloud where you can train and deploy AI models including Gemini.</p><p>To secure your REST API access, you need to create an account and get the credentials for your application so only you can access it. Here are the steps:</p><ol><li>Sign up for a <a href="https://cloud.google.com/free">Google Cloud account</a> and <a href="https://cloud.google.com/billing/docs/how-to/create-billing-account">enable billing</a> — this gives you access to <strong>Vertex AI</strong>.</li><li><a href="https://developers.google.com/workspace/guides/create-project">Create a new project</a> in the Cloud Console. Make note of the <strong>project ID</strong>.</li><li><a href="https://cloud.google.com/vertex-ai">Enable the Vertex AI API</a> for your project.</li><li><a href="https://cloud.google.com/sdk/docs/install">Install the gcloud CLI</a> and run gcloud auth print-access-token. Save the printed access token - you’ll use this for authentication.</li></ol><p>Once you have the <strong>project ID</strong> and <strong>access token</strong>, you’re ready to move on to the Angular app. To verify everything is setup correctly you can try these <a href="https://cloud.google.com/vertex-ai/docs/generative-ai/model-reference/gemini#sample_requests">curl commands</a>.</p><p>Edit the development file to include the <strong>project ID</strong> and <strong>access token</strong>:</p><pre>// src/environments/environment.development.ts<br>export const environment = {<br>  API_KEY: &quot;&lt;YOUR-API-KEY&gt;&quot;, // Google AI JavaScript SDK access<br>  PROJECT_ID: &quot;&lt;YOUR-PROJECT-ID&gt;&quot;, // Vertex AI access<br>  GCLOUD_AUTH_PRINT_ACCESS_TOKEN: &quot;&lt;YOUR-GCLOUD-AUTH-PRINT-ACCESS-TOKEN&gt;&quot;, // Vertex AI access<br>};</pre><p>To make <strong>requests </strong>via the <strong>REST</strong> <strong>API</strong>, you need to include the <strong>HttpClient</strong> provider:</p><pre>// app.config.ts<br>import { provideHttpClient } from &quot;@angular/common/http&quot;;<br><br>export const appConfig: ApplicationConfig = {<br>  providers: [<br>    provideRouter(routes),<br>    provideHttpClient()<br>  ]<br>};</pre><p>With this import, we can inject <strong>HttpClient</strong> into any component or service to make web requests.</p><pre>// app.component.ts<br>import { HttpClient } from &#39;@angular/common/http&#39;;<br><br>@Component({<br>  selector: &#39;app-root&#39;,<br>  standalone: true,<br>  ...<br>})<br>export class AppComponent implements OnInit {<br>  constructor(public http: HttpClient) {}<br>}</pre><p>To access <strong>Vertex AI</strong> via REST API we need to do a bit more work as there’s no client available. Without any help, it takes a bit more effort to build the request and read the response.</p><pre>async TestGeminiProWithVertexAIViaREST() {<br>  // Docs: https://cloud.google.com/vertex-ai/docs/generative-ai/model-reference/gemini#request_body<br>  const prompt = this.buildPrompt(&#39;What is the largest number with a name?&#39;);<br>  const endpoint = this.buildEndpointUrl(environment.PROJECT_ID);<br>  let headers = this.getAuthHeaders(<br>    environment.GCLOUD_AUTH_PRINT_ACCESS_TOKEN<br>  );<br><br>  this.http.post(endpoint, prompt, { headers }).subscribe((response: any) =&gt; {<br>    console.log(response.candidates?.[0].content.parts[0].text);<br>  });<br>}<br><br>buildPrompt(text: string) {<br>  return {<br>    contents: [<br>      {<br>        role: &#39;user&#39;,<br>        parts: [<br>          {<br>            text: text,<br>          },<br>        ],<br>      },<br>    ],<br>    safety_settings: {<br>      category: &#39;HARM_CATEGORY_SEXUALLY_EXPLICIT&#39;,<br>      threshold: &#39;BLOCK_LOW_AND_ABOVE&#39;,<br>    },<br>    generation_config: {<br>      temperature: 0.9,<br>      top_p: 1,<br>      top_k: 32,<br>      max_output_tokens: 100,<br>    },<br>  };<br>}<br><br>buildEndpointUrl(projectId: string) {<br>  const BASE_URL = &#39;https://us-central1-aiplatform.googleapis.com/&#39;;<br>  const API_VERSION = &#39;v1&#39;; // may be different at this time<br>  const MODEL = &#39;gemini-pro&#39;;<br>  let url = BASE_URL; // base url<br>  url += API_VERSION; // api version<br>  url += &#39;/projects/&#39; + projectId; // project id<br>  url += &#39;/locations/us-central1&#39;; // google cloud region<br>  url += &#39;/publishers/google&#39;; // publisher<br>  url += &#39;/models/&#39; + MODEL; // model<br>  url += &#39;:generateContent&#39;; // action<br>  return url;<br>}<br><br>getAuthHeaders(accessToken: string) {<br>  const headers = new HttpHeaders().set(<br>    &#39;Authorization&#39;,<br>    `Bearer ${accessToken}`<br>  );<br>  return headers;<br>}</pre><h3>Running the code</h3><p>Uncomment the code you want to test within the ngOnInit body from the <a href="https://github.com/gsans/google-ai-gemini-angular">GitHub project</a>.</p><pre>ngOnInit(): void {<br>  // Google AI<br>  this.TestGeminiPro();<br>  //this.TestGeminiProChat();<br>  //this.TestGeminiProVisionImages();<br>  //this.TestGeminiProStreaming();<br>  <br>  // Vertex AI<br>  //this.TestGeminiProWithVertexAIViaREST();<br>}</pre><p>In order to run the code run this command in the terminal and navigate to localhost:4200.</p><pre>ng serve</pre><h3>Verifying the response</h3><p>To verify the response, you can quickly check the <strong>Console output</strong> in your browser.</p><pre>console.log(response.text());</pre><pre>The largest number with a name is a googolplex. A googolplex is a 1 followed by 100 zeroes.</pre><p>Congratulations! You now have access to<strong> Gemini</strong> capabilities.</p><h3>Conclusions</h3><p>By completing this tutorial, you learned:</p><ul><li>How to obtain an <strong>API Key</strong> and set up access to <strong>Gemini APIs</strong></li><li>How to call <strong>Gemini Pro</strong> using text and chat</li><li>How to handle input images for <strong>Gemini Pro Vision</strong></li><li>Bonus: How to setup and call <strong>Gemini </strong>using <strong>Vertex AI</strong> via the REST API</li><li>How to handle the response and outputs</li></ul><p>You now have the foundation to start building <strong>AI-powered features</strong> like advanced text generation into your <strong>Angular apps</strong> using <strong>Gemini</strong>. The complete code is available on <a href="https://github.com/gsans/google-ai-gemini-angular">GitHub</a>.</p><h3>Want to see a more complex project?</h3><p>I built a full blown Gemini Chatbot using Angular Material, <a href="https://github.com/KillerCodeMonkey/ngx-quill">ngx-quill</a> and <a href="https://github.com/jfcere/ngx-markdown">ngx-markdown</a> showcasing text, chat and multimodal capabilities.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HLsbV-pT9RFXNdMyfOnG8Q.png" /></figure><p>Feel free to fork the project <a href="https://github.com/gsans/mini-bard-palm2-angular">here</a>. If you like this project don’t forget to leave a star to show support of my work and to other contributors in the Angular community.</p><h3>Thanks for reading!</h3><p>Have you got any questions? Feel free to leave your comments below or reach out to me on Twitter at @<a href="https://twitter.com/gerardsans">gerardsans</a>.</p><h3>Resources</h3><ul><li><a href="https://github.com/google/generative-ai-js">Google AI JavaScript SDK</a></li><li><a href="https://ai.google.dev/tutorials/web_quickstart">Gemini on the Web</a></li><li><a href="https://cloud.google.com/vertex-ai/docs/generative-ai/model-reference/gemini">Vertex AI: Gemini REST API</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5bf5e905ca1d" width="1" height="1" alt=""><hr><p><a href="https://medium.com/google-cloud/build-ai-powered-angular-apps-with-google-gemini-5bf5e905ca1d">Build AI-Powered Angular Apps with Google Gemini</a> was originally published in <a href="https://medium.com/google-cloud">Google Cloud - Community</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Getting Started with Generative AI in Angular]]></title>
            <link>https://medium.com/google-cloud/getting-started-with-generative-ai-in-angular-b72737a59982?source=rss-9530b046d2ac------2</link>
            <guid isPermaLink="false">https://medium.com/p/b72737a59982</guid>
            <category><![CDATA[google-cloud-platform]]></category>
            <category><![CDATA[generative-ai]]></category>
            <category><![CDATA[gcp-app-dev]]></category>
            <category><![CDATA[angular]]></category>
            <category><![CDATA[vertex-ai]]></category>
            <dc:creator><![CDATA[Gerard Sans]]></dc:creator>
            <pubDate>Mon, 14 Aug 2023 14:38:31 GMT</pubDate>
            <atom:updated>2024-03-12T13:46:31.226Z</atom:updated>
            <content:encoded><![CDATA[<h3>Vertex AI is Google Cloud platform for state-of-the-art Generative AI including PaLM 2</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DhEIPvxJotW7S_BGVK2pTw.png" /></figure><blockquote>IMPORTANT: Google Gemini, a new model, has become the default and a new JavaScript client is available from Google AI. For an updated article check <a href="https://medium.com/google-cloud/build-ai-powered-angular-apps-with-google-gemini-5bf5e905ca1d">here</a></blockquote><p>In this post, you are going to learn how to access to the just released <strong>PaLM APIs</strong> to create the next generation of AI-enabled Applications using <strong>Angular</strong>.</p><blockquote>If you are based in the US, you can skip to the annex at the end using an <strong>API key from MakerSuite</strong>. This tutorial, covers accessing Vertex AI with <strong>Google Cloud</strong> credentials for countries where MakerSuite is not available yet.</blockquote><blockquote>For <strong>Firebase based projects</strong>, you can use <a href="https://extensions.dev/extensions/googlecloud/palm-secure-backend">Call PaLM API Securely</a>, a Firebase extension. Find more details about how to set it up <a href="https://github.com/google/generative-ai-docs/tree/main/demos/palm/web/list-it#developer-setup">here</a>.</blockquote><p>We’ll use <strong>Angular</strong> to build a simple application that prompts the <strong>PaLM for Text</strong> model. Once you get this working, you are set to use any of the other models. Here’s what we’ll cover:</p><ul><li><a href="#099b">Introduction to <strong>Generative AI</strong></a></li><li><a href="#3791"><strong>Responsible AI</strong></a></li><li><a href="#a16e">Getting <strong>API credentials</strong> for Vertex AI</a></li><li><a href="#51a8">Setup for API access via <strong>Google Cloud</strong></a></li><li><a href="#6679">Creating the <strong>Angular Application</strong></a></li><li><a href="#5b6b">Making the <strong>Prediction Request</strong></a></li><li><a href="#101d">Handling the <strong>Prediction Response</strong></a></li><li><a href="#34c7">Conclusion</a></li><li><a href="#ee98">Annex 1: using <strong>API key </strong>from <strong>MakerSuite</strong>?<strong> </strong>Join the waitlist otherwise</a></li><li><a href="#a54d">Annex 2: <strong>Prompt basics</strong>: temperature, topK and TopP</a></li><li><a href="#c4dd">Annex 3: <strong>Response Metadata:</strong> Citations,<strong> </strong>Safety Attributes and Billing</a></li></ul><p>This tutorial will help you get set up to Vertex AI so you can start adding AI-enabled features using models like PaLM in your applications. Let’s get started!</p><h3>Introduction to Generative AI</h3><p><strong>Vertex AI</strong> provides pre-trained models for tasks like text generation, chat, image editing, code, speech and more. You can access these via <strong>API requests</strong>.<strong> </strong>Alternatively,<strong> </strong>if you need managed services to create models from scratch and fine tune them you can also use these to create, host and manage your models for you.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9GgttxPK8otHcYgYNrliJw.png" /><figcaption>Vertex AI: Foundational Models. Embeddings available for text and images.</figcaption></figure><h4>What is Generative AI?</h4><p><strong>Generative AI</strong> is a very exciting new area within AI that falls into Artificial Intelligence (AI), Machine Learning (ML) and Neural Networks. <a href="https://research.google/pubs/pub46201/"><strong>The Transformer</strong></a><strong> </strong>together with the attention mechanism released back in 2017 by Google is what powers, the new wave of Generative AI and the Foundational models.</p><p>Large language models are pre-trained on massive text with the goal of predicting the next word in a sequence. Once trained, they can generate new text relevant to the given prompt being an open-ended paragraph in a novel, a list of ingredients for a recipe or providing an answer to a general knowledge question.</p><p>The training data includes public data available on <strong>the Internet</strong>, books and code repositories similar to GitHub.</p><h4>How are people using Generative AI today?</h4><p>Models based on the Transformer have surpassed many traditional ML approaches. Most recently, research has focused in multi-modal architectures that can be trained and combine inputs and outputs not only as text but as images, video and audio in a single model. This is the case for <strong>Gemini</strong>, a model being developed by DeepMind, the creators of AlphaGo.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3EuYcKMHKesjMSHVWSz7_w.png" /><figcaption>Some use cases for Generative AI sorted by output.</figcaption></figure><p>Some examples of how people are using Generative AI today:</p><ul><li>Creative text generation</li><li>Chatbots and virtual assistants</li><li>Summarisation of text</li><li>Image generation and editing</li></ul><h3>Responsible AI</h3><p>While Generative AI enables exciting new applications, these powerful models also introduce important ethical questions we must grapple with as developers. We have a responsibility to build AI thoughtfully by considering potential harms, setting appropriate constraints, and monitoring for misuse.</p><p>As we integrate these models into applications, we need to implement strategies like human review processes and sensitivity analysis to prevent abusive or dangerous uses of the technology.</p><p>Some questions you should ask before releasing any new AI features:</p><ul><li><strong>Auditing and traceability</strong> – How will we facilitate tracing back to the source of abusive or questionable AI usage? What logging and auditing capabilities should we implement?</li><li><strong>Prompt framing and grounding – </strong>How will we ensure our application provides proper context for AI-generated content? Without context, misinterpretation can easily occur.</li><li><strong>Outputs monitoring – </strong>If incorrect output does occur, how will it be corrected? What feedback mechanisms should exist for users?</li><li><strong>Bias mitigation</strong>. How might the AI output negatively impact or unfairly characterise underrepresented groups? How will we proactively test for bias?</li></ul><p>For more information, read <a href="https://cloud.google.com/responsible-ai#google-cloud%E2%80%99s-approach-to-responsible-ai">Google’s approach to responsible AI</a>.</p><p>Now that we’ve covered the key concepts, let’s walk through how to access Vertex AI and make requests from an Angular application.</p><h3>Getting API Credentials for Vertex AI</h3><p>In the previous section, we introduced Vertex AI and discussed the models and capabilities it provides. These are the steps to get credentials for accessing Vertex AI.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-rRrCsVicoF0e8VJKsyGeg.png" /><figcaption>General overview of the architecture.</figcaption></figure><blockquote>⚠️ Note that this approach is only temporary while no official <strong>Vertex AI Client for Web</strong> is available. If you are developing for the server-side do use available clients for <a href="https://cloud.google.com/java/docs/reference/google-cloud-aiplatform/latest/overview">Java</a>, <a href="https://cloud.google.com/nodejs/docs/reference/aiplatform/latest">Node.JS</a>, <a href="https://cloud.google.com/python/docs/reference/aiplatform/latest/index.html">Python</a> and <a href="https://cloud.google.com/go/docs/reference/cloud.google.com/go/aiplatform/latest/apiv1">Go</a>.</blockquote><h3>Setup for API access via Google Cloud</h3><p>To secure the API access, you need to create an account and get the credentials for your application so only you can access it. Here are the steps:</p><ol><li>Sign up for a <a href="https://cloud.google.com/free">Google Cloud account</a> and <a href="https://cloud.google.com/billing/docs/how-to/create-billing-account">enable billing</a> — this gives you access to Vertex AI.</li><li><a href="https://developers.google.com/workspace/guides/create-project">Create a new project</a> in the Cloud Console. Make note of the project ID.</li><li><a href="https://cloud.google.com/vertex-ai">Enable the Vertex AI API</a> for your project.</li><li><a href="https://cloud.google.com/sdk/docs/install">Install the gcloud CLI</a> and run gcloud auth print-access-token. Save the printed access token - you’ll use this for authentication.</li></ol><p>Once you have the <strong>project ID</strong> and <strong>access token</strong>, we’re ready to move on to the Angular app. To verify everything is setup correctly you can try these <a href="https://cloud.google.com/vertex-ai/docs/generative-ai/start/quickstarts/api-quickstart">curl commands</a>.</p><blockquote>Make sure that your <strong>access token</strong> remains private so you do not incur into expenses from unauthorised access.</blockquote><h3>Creating the Angular Application</h3><p>We’ll use the <strong>Angular CLI</strong> to generate a new application:</p><pre>ng new vertex-ai-palm2-angular</pre><p>This scaffolds a new project with the latest Angular version.</p><p>To make <strong>API requests</strong>, we need the <strong>HttpClient</strong> module:</p><pre>// app.module.ts<br>import {HttpClientModule} from &#39;@angular/common/http&#39;;<br><br>@NgModule({<br>  imports: [<br>    HttpClientModule<br>  ] <br>})</pre><p>With this import, we can inject <strong>HttpClient</strong> into any component or service to make web requests.</p><h3><strong>Making the prediction request</strong></h3><p>Let’s create a component to run our prompt:</p><pre>ng generate component predict</pre><p>In predict.component.ts, we’ll use the code below to set up the <strong>HttpClient</strong> and prepare the stage for the <strong>API request</strong>:</p><pre>import { Component, OnInit } from &#39;@angular/core&#39;;<br>import { HttpClient, HttpHeaders } from &#39;@angular/common/http&#39;;<br>import { createPrompt, TextRequest, TextResponse } from &#39;../models/vertex-ai&#39;;<br><br>@Component(...)<br>export class PredictComponent implements OnInit {<br>  endpoint: string = &quot;&quot;;<br>  headers: HttpHeaders | undefined;<br>  prompt: TextRequest = createPrompt(&quot;What is the largest number with a name?&quot;);<br><br>  constructor(public http: HttpClient) {<br>  }<br><br>  ngOnInit(): void {<br>    this.TestVertexAIWithoutApiKey();<br>  }<br>}</pre><p>To make the call, We’ll break this down into a few steps.</p><h4>Creating the prompt</h4><p>To create the prompt, we are using a helper function which will return the request <strong>JSON object</strong> that we will be used to send our prediction.</p><pre>/// src/app/models/vertex-ai.ts<br><br>export function createPrompt(<br>  prompt: string = &quot;What is the largest number with a name?&quot;,<br>  temperature: number = 0.7,<br>  maxOutputTokens: number = 100,<br>  topP: number = 0.95,<br>  topK: number = 40<br>): TextRequest {<br>  const request : TextRequest = {<br>    &quot;instances&quot;: [<br>      {<br>        &quot;prompt&quot;: `${prompt}`<br>      }<br>    ],<br>    &quot;parameters&quot;: {<br>      &quot;temperature&quot;: temperature,<br>      &quot;maxOutputTokens&quot;: maxOutputTokens,<br>      &quot;topP&quot;: topP,<br>      &quot;topK&quot;: topK<br>    }<br>  }<br>  return request;<br>}</pre><h4>Building the Endpoint URL</h4><p>The endpoint requires consolidating the base URL, API version, your <strong>project ID</strong>, <a href="https://cloud.withgoogle.com/region-picker">Google Cloud region</a>, publisher, the model name, and the specific action. We concatenate these together to form the full prediction endpoint URL.</p><pre>buildEndpointUrl(projectId: string) {<br>  const BASE_URL = &quot;https://us-central1-aiplatform.googleapis.com/&quot;;<br>  const API_VERSION = &#39;v1&#39;;        // may be different at this time<br>  const MODEL = &#39;text-bison&#39;;      <br><br>  let url = BASE_URL;              // base url<br>  url += API_VERSION;              // api version<br>  url += &quot;/projects/&quot; + projectId; // project id<br>  url += &quot;/locations/us-central1&quot;; // google cloud region<br>  url += &quot;/publishers/google&quot;;     // publisher<br>  url += &quot;/models/&quot; + MODEL;       // model<br>  url += &quot;:predict&quot;;               // action<br><br>  this.endpoint = url;<br>}</pre><p>This endpoint in particular calls the predict API on text-bison. If you want to try any of the other available APIs (chat, code, images, speech) find more details <a href="https://cloud.google.com/vertex-ai/docs/generative-ai/">here</a>. Just be aware that each API has different endpoints, requests and responses.</p><h4>Authentication</h4><p>Next, we added the access token retrieved earlier to the <strong>HTTP headers</strong> to authenticate the request:</p><pre>getAuthHeaders(accessToken: string) {<br>  this.headers = new HttpHeaders()<br>    .set(&#39;Authorization&#39;, `Bearer ${accessToken}`);<br>}</pre><p>In order to comply with the security credentials, we added an auth header.</p><blockquote>This <strong>access token</strong> is temporary so you may need to renew it by running this command again gcloud auth print-access-token.</blockquote><h4>Making the request</h4><p>Finally, we use all the previous steps to make a POST request to the prediction endpoint. To handle the response, we define a subscribe callback to print out to the console the content for the prediction. This is part of the response object as seen in the code below.</p><pre>TestVertexAIWithoutApiKey() {<br>  const PROJECT_ID = &#39;&lt;YOUR_PROJECT_ID&gt;&#39;;<br>  const GCLOUD_AUTH_PRINT_ACCESS_TOKEN = &#39;&lt;YOUR_GCLOUD_AUTH_PRINT_ACCESS_TOKEN&gt;&#39;;<br>  <br>  this.buildEndpointUrl(PROJECT_ID);<br>  this.getAuthHeaders(GCLOUD_AUTH_PRINT_ACCESS_TOKEN);<br>  <br>  this.http.post&lt;TextResponse&gt;(this.endpoint, this.prompt, { headers: this.headers })<br>    .subscribe(response =&gt; {<br>      console.log(response.predictions[0].content);<br>    });<br>}</pre><blockquote>Be sure to substitute your actual <strong>project ID</strong> and <strong>access token</strong> retrieved in the credential steps here.</blockquote><h3><strong>Handling the Prediction Response</strong></h3><p>In order to run the code run this command in the terminal and navigate to localhost:4200.</p><pre>ng serve</pre><h4>Verifying the response</h4><p>To verify the response from the prediction call, you can quickly check the <strong>Console output</strong> in your browser.</p><pre>console.log(response.predictions[0].content);</pre><pre>{<br>  &quot;predictions&quot;: [<br>    {<br>      &quot;content&quot;: &quot;The largest number with a name is a googolplex. A googolplex is a 1 followed by 100 zeroes.&quot;<br>    }<br>  ],<br>}</pre><p>Congratulations! You now have access to<strong> Vertex AI</strong> APIs. And that’s really all you need to integrate <strong>PaLM for Text</strong> predictions into an Angular application. The complete code is available on <a href="https://github.com/gsans/vertex-ai-palm2-angular">GitHub</a>.</p><h3>Conclusion</h3><p>By completing this tutorial, you learned:</p><ul><li>How to obtain credentials and set up access to the Vertex AI APIs</li><li>How to create an Angular application using the CLI</li><li>How to make a prediction request to a generative model</li><li>How to handle the response and output the generated text</li></ul><p>You now have the foundation to start building <strong>AI-powered features</strong> like advanced text generation into your own <strong>Angular apps</strong> using <strong>Vertex AI</strong>.</p><h3>Thanks for reading!</h3><p>Have you got any questions? Feel free to leave your comments below or reach out on Twitter at @<a href="https://twitter.com/gerardsans">gerardsans</a>.</p><h4>Credits: AI Assistants</h4><p>This post was co-created with the help of a few AI assistants. Claude collaborated with me throughout the writing process — from structuring ideas to drafting content. Their tireless efforts as my virtual writing buddies were instrumental in crafting this tutorial. Later, Bard and ChatGPT punctually help me out getting to the final version.</p><p>Try Claude for FREE here: <a href="https://claude.ai/">https://claude.ai</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LrcycPsbWquyd4uA7RJwzw.png" /></figure><h3>Annex 1: Using <strong>API key </strong>from <strong>MakerSuite</strong>?<strong> </strong>Join the waitlist</h3><p>In this annex you will learn how to use your API key to access Vertex AI. First, make sure you have a valid <strong>API key</strong> from <strong>MakerSuite</strong> or request joining the waitlist <a href="https://developers.generativeai.google/products/palm">here</a> if you live outside the US. Once you have it you can quickly verify it with a <a href="https://developers.generativeai.google/tutorials/setup">curl request</a>.</p><p>Once you receive your API key follow these steps:</p><h4>Changes to the Prediction Component</h4><p>Now the code to make the prediction call becomes:</p><pre>TestVertexAIWithApiKey() {<br>  const API_KEY = &#39;&lt;YOUR_API_KEY&gt;&#39;;<br><br>  this.buildEndpointUrlApiKey(API_KEY);<br><br>  this.http.post&lt;TextResponse&gt;(this.endpoint, this.prompt)<br>    .subscribe(response =&gt; {<br>      console.log(response.predictions[0].content);<br>    });<br>}</pre><p>Replace API_KEY with yours, pass the prompt text in the request body, and make a POST request to the prediction endpoint. Let’s quickly go through the remaining code. I tried to broke buildEndpointUrl down so you can see how each piece connects together.</p><pre>buildEndpointUrlApiKey(apikey: string) {<br>  const BASE_URL = &quot;https://generativelanguage.googleapis.com/&quot;;<br>  const API_VERSION = &#39;v1beta2&#39;;   // may be different at this time Eg: v1, v2, etc<br>  const MODEL = &#39;text-bison-001&#39;;  // may be different at this time<br><br>  let url = BASE_URL;              // base url<br>  url += API_VERSION;              // api version<br>  url += &quot;/models/&quot; + MODEL        // model<br>  url += &quot;:generateText&quot;;          // action<br>  url += &quot;?key=&quot; + apikey;         // api key<br><br>  this.endpoint = url;<br>}</pre><p>This endpoint in particular calls the generateText API on text-bison-001. If you want to try any of the other available APIs (chat, code, images, speech) find the details <a href="https://developers.generativeai.google/tutorials/curl_quickstart">here</a>. Just be aware that each API has different endpoints, requests and responses.</p><p>Notice how in this version of the code the API key is part of the query string.</p><p>Full code is available on <a href="https://github.com/gsans/vertex-ai-palm2-angular">GitHub</a>.</p><h3>Annex 2: Understanding prompt basics: temperature, topK and TopP</h3><p>Prompt parameters are some basic arguments that we can fiddle with to influence the output for a given prompt. For example, these can be used to get less common and more creative outputs.</p><h4>Tokens vs words</h4><p>While we submit prompts to the <a href="https://developers.generativeai.google/models/language#model_metadata">PaLM API</a> in the form of text, the API converts these strings into chunks called tokens. A token is approximately four characters. 100 tokens correspond to roughly 60 to 80 words.</p><pre>{<br>  &quot;predictions&quot;: [<br>    {<br>      &quot;content&quot;: &quot;The largest number with a name is a googolplex. A googolplex is a 1 followed by 100 zeroes.&quot;<br>    }<br>  ],<br>  &quot;metadata&quot;: {<br>    &quot;tokenMetadata&quot;: {<br>      &quot;inputTokenCount&quot;: {<br>        &quot;totalTokens&quot;: <br>      },<br>      &quot;outputTokenCount&quot;: {<br>        &quot;totalTokens&quot;: <br>      }<br>    }<br>  }<br>}</pre><p>Some tasks may require you to review the default settings for these parameters to get better results.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*TlEp3m7YDDdXGtWQ9yWmyw.png" /><figcaption>Diagrams by Cohere. How prompt parameters and temperature influence the output.</figcaption></figure><p>Let’s look at these in more detail:</p><ul><li>prompt. This parameter becomes the <strong>text input</strong>. Eg: What is the largest number with a name? Feel free to change this prompt as is only to test access to the API. Mandatory.</li><li>temperature. This parameter allows you to introduce less common options during the decoding strategy thus rising up the chances for a more creative or less repetitive responses. When set to 0 a <strong>greedy strategy</strong> is used and the first option is picked. Recommended.</li><li>maxOutputTokens. This parameter limits the total amount of tokens generated by this prompt. Note output can be truncated leaving part of the answer missing. Be aware of costs while testing. <a href="https://cloud.google.com/vertex-ai/docs/generative-ai/learn/models#foundation_models">The maximum value</a> is 1024. Recommended.</li></ul><p>Most of the time, <strong>the default values</strong> will be enough.</p><h4>Extending the reach for your responses: TopK and TopP</h4><p>Some times you will be testing a prompt and looking for different responses that can better fit your expectations or be a better match for the task at hand. In these cases you can use TopK and TopP to extend the scope for more and different responses.</p><blockquote>Note that these parameters require a deeper understanding of the model and how probability distributions work for a given prompt.</blockquote><p>As shown in the diagram below, given a certain temperature, you can introduce more variability by increasing topP and topK respectively. The final result will depend on the probability distribution present for that specific prompt.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UUO5X9CcqKFSLVetUb-Iew.png" /><figcaption>Diagrams by Cohere. Shows outputs changing TopP and TopK for different Temperatures</figcaption></figure><p>As a review:</p><ul><li>topK. This parameter limits the sampled options to k . Default value is set to 40. Optional.</li><li>topP. This parameter limits the aggregated probabilities up to p. Default value is 0.95. Values between 0 and 1. Optional.</li></ul><p>When both topK and topP are provided topK takes precedence before applying topP. Finally a random selection is made within the sampled tokens. The probabilities for each token are the result after the training for that model ends.</p><p>Common strategies when testing your prompts:</p><ul><li><strong>Limit response to the most common tokens seen in training</strong>. Set temperature to zero and topP to 0.2. This will respect the probabilities from the model and chose a token that seats within the 20% of cases seen by the model during training. This will also limit the variability for long-tail distributions if that’s the case for your prompt.</li><li><strong>Allow less common tokens and more creative responses</strong>: Set temperature to 0.7 and topK to 40. This will rise the probabilities for less common cases so they can show in the output. Note this strategy depends on each prompt and how many training data relevant to it was present during training.</li></ul><h4>Annex 3: <strong>Response Metadata:</strong> Citations,<strong> </strong>Safety Attributes and Billing</h4><p>As part of the response you will also get access some interesting metadata around citations, safety and billing. See below the whole structure for reference. For more details, see <a href="https://cloud.google.com/vertex-ai/docs/generative-ai/learn/responsible-ai#safety_filters_and_attributes">Responsible AI</a>.</p><pre>{<br>  &quot;predictions&quot;: [<br>    {<br>      &quot;content&quot;: &quot;The largest number with a name is a googolplex. A googolplex is a 1 followed by 100 zeroes.&quot;<br>      &quot;citationMetadata&quot;: {<br>        &quot;citations&quot;: []<br>      },<br>      &quot;safetyAttributes&quot;: {<br>        &quot;scores&quot;: [],<br>        &quot;blocked&quot;: false,<br>        &quot;categories&quot;: []<br>      }<br>    }<br>  ],<br>  &quot;metadata&quot;: {<br>    &quot;tokenMetadata&quot;: {<br>      &quot;inputTokenCount&quot;: {<br>        &quot;totalBillableCharacters&quot;: ,<br>        &quot;totalTokens&quot;: <br>      },<br>      &quot;outputTokenCount&quot;: {<br>        &quot;totalBillableCharacters&quot;: ,<br>        &quot;totalTokens&quot;: <br>      }<br>    }<br>  }<br>}</pre><h4>Safety</h4><p>Generative AI is still very new and while adding AI-enabled features to your Apps be aware of the current <a href="http://Limited Domain Expertise">PaLM API limitations</a>, including:</p><ul><li>Model Hallucinations, Grounding, and Factuality</li><li>Biases and Limited Domain Expertise</li></ul><p>Learn how you can mitigate these by following the recommendations found in <a href="https://cloud.google.com/vertex-ai/docs/generative-ai/learn/responsible-ai#safety_filters_and_attributes">Responsible AI</a>.</p><h4>Vertex AI Billing</h4><p>As a reference, 500 requests and corresponding 500 responses, will cost you (per 1,000 characters):</p><ul><li><strong>PaLM for Text: $1 (used in this post)</strong></li><li>PaLM for Chat or Codey: $0.5</li><li>Embeddings for text or images: $0.1</li></ul><p>Prices may vary over time. Note input and output are charged separately. See <a href="https://cloud.google.com/vertex-ai/pricing">latest pricing</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7jIUkDU2xfSAtBolGqfagQ.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b72737a59982" width="1" height="1" alt=""><hr><p><a href="https://medium.com/google-cloud/getting-started-with-generative-ai-in-angular-b72737a59982">Getting Started with Generative AI in Angular</a> was originally published in <a href="https://medium.com/google-cloud">Google Cloud - Community</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[OpenAI — The Start of a New Era in AI]]></title>
            <link>https://gerard-sans.medium.com/openai-the-start-of-a-new-era-in-ai-1eef98d0e2a3?source=rss-9530b046d2ac------2</link>
            <guid isPermaLink="false">https://medium.com/p/1eef98d0e2a3</guid>
            <category><![CDATA[dalle-2]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[codice]]></category>
            <category><![CDATA[openai]]></category>
            <category><![CDATA[gpt-3]]></category>
            <dc:creator><![CDATA[Gerard Sans]]></dc:creator>
            <pubDate>Tue, 11 Oct 2022 12:00:43 GMT</pubDate>
            <atom:updated>2022-10-11T12:30:35.362Z</atom:updated>
            <content:encoded><![CDATA[<h3>OpenAI — The Start of a New Era in AI</h3><p>Discussion hosted by Darek Kalbarczyk featuring Gerard Sans</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZPO8iAgPIHzsu29mr4CxlQ.png" /><figcaption>Image edition using DALL-E, one of the most popular products of OpenAI.</figcaption></figure><p>This is an edited and reviewed version of the <strong>transcript </strong>for <strong>JavaScript Master Podcast</strong> by Darek Kalbarczyk featuring Gerard Sans using GPT-3.</p><ul><li><a href="#ba6c">Introduction</a></li><li><a href="#d73e">How AI is going to replace some jobs?</a></li><li><a href="#bbec">Which jobs are more likely to be affected: writers, artists, or developers?</a></li><li><a href="#5c98">What is <strong>OpenAI</strong>?</a></li><li><a href="#4dd7">What products are being offered today by <strong>OpenAI</strong>?</a></li><li><a href="#bf93">What is <strong>GPT-3</strong> trying to solve?</a></li><li><a href="#4399">Cooking recipes created by an AI!?!</a></li><li><a href="#f457">How it could learn Japanese with almost no information?</a></li><li><a href="#f61c">What is <strong>Codex</strong> main purpose?</a></li><li><a href="http://62ca/">What is <strong>DALL-E</strong> and how people are using it?</a></li><li><a href="#eb9c">Can you use <strong>DALL-E</strong> for interior design?</a></li><li><a href="#b6ba">Can you use <strong>OpenAI</strong> today? How would that work?</a></li><li><a href="#9076">What are the benefits of using those tools? Are there any drawbacks?</a></li><li><a href="#6da4">What the future of AI may look like in five years?</a></li><li><a href="#e6f7">Do you think AI can help us build something we can’t do ourselves for now, like a super engine for a rocket?</a></li><li><a href="#7d4f">Can you give some advice to people who are starting their career in IT today? And for those who are old-timers?</a></li></ul><p>You can also listen to the original podcast at the end of this blogpost.</p><p><strong>Darek:</strong> Hi, Gerard. How are you?</p><p><strong>Gerard:</strong> Hello, Darek. I’m very good thanks!</p><p><strong>Darek:</strong> please tell us a bit about yourself.</p><p><strong>Gerard:</strong> my name is <strong>Gerard Sans</strong>. I’m a <strong>Developer Evangelist</strong> for Web and Cloud. I’ve been doing some research on <strong>Artificial Intelligence</strong> and <strong>Web3</strong> for the last year and I’m here to share some of my learnings with you.</p><p><strong>Darek:</strong> there’s been a lot of discussions around how AI is going to replace some jobs. What do you think about that?</p><p><strong>Gerard: </strong>these are very exciting times. We’ve seen a lot of improvements in AI in the past few years. Some of them will certainly change how people do their jobs. The most significant changes have happened in <strong>text-to-image generation</strong>. This is where an AI model generates images from scratch by using a prompt. We’ve seen amazing progress in this area. You can easily generate illustrations or even photorealistic images, and it keeps getting better and better. A lot of designers and digital artists are seeing how their jobs are suddenly in the spotlight. At this time, it’s not clear if people will care if an artwork was created by a digital artist or an AI.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/1*D8zetnZGy7WuWT0B8uqAGw.png" /><figcaption>This white t-shirt doesn’t exist, it was created by DALL-E.</figcaption></figure><p><strong>Darek:</strong> which jobs are more likely to be affected: writers, artists, or developers?</p><p><strong>Gerard:</strong> AI’s latest developments have been very surprising for me. Initially, I was in awe looking at some of the text generated by AIs. <strong>This technology is very similar to what I explained for image generation but writing</strong>. These AI models have been trained using a very large amount of data including publicly available books from the last few centuries. So these models can generate text in all the styles that you can imagine — commercial books, self-help, cooking recipes — but also philosophy, math, and all of the sciences. If you think about important authors like Shakespeare or other famous authors in history, their styles are also embedded in these models. So today, <strong>you can effortlessly generate text that resembles any of the most famous writers in the world</strong>. Like DALL-E generating an image in the style of Van Gogh. This is not just limited to literature but also includes all sorts of specific domains like marketing.</p><p>For example, if you are a writer, you could use these AI tools to avoid what’s called <strong>writer’s block</strong>. You can get inspiration from a history that you are stuck on and get a fresh start following your same style. People are using this technology to generate anything from blog posts to cooking recipes and anything in between. It’s quite exciting but also quite uncertain how it will affect jobs like technical writers or even novelists. These jobs are all in the spotlight. Most people know about these AI technologies but they don’t think that they will be affected by them.</p><blockquote>Most people know about these AI technologies but they don’t think that they will be affected by them</blockquote><p>It was only last year that OpenAI released <strong>Codex</strong>, which is the model behind <strong>GitHub Copilot</strong> a product by Microsoft. Codex can write code from scratch but also introduce changes following commands. This is anything that you need as a developer. You can write code and then iterate over it as many times as you need. <strong>These are only a few examples of what these tools are capable of today.</strong> So yeah, it’s looking like we are facing the birth of a new era of AIs.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rBpZv49lyrnEPPCllunPxQ.png" /><figcaption>Using Codex you can specify what you need in a comment and it will create the code for you.</figcaption></figure><p><strong>Darek:</strong> what is <strong>OpenAI</strong>?</p><p><strong>Gerard:</strong> <strong>OpenAI</strong> is a company that was founded by <strong>Elon Musk</strong>, <strong>Sam Altman</strong>,<strong> </strong>and<strong> Greg Brockman</strong>. Their mission is to build a safe <strong>Artificial General Intelligence (AGI)</strong> that benefits all humanity.</p><p>OpenAI was founded back in 2015 as a non-profit company. It took them a few years until 2018 to create the first GPT model which is a <strong>Generative Pre-trained Transformer</strong>. It is also known as a <strong>Large Language Model</strong> (LLM). They published a <strong>public API</strong> in 2020 which is when everyone started playing with this technology and started discovering its many applications. <strong>The first applications were focused on writing but very soon they realised that GPT-3 was able to do things like writing valid JavaScript</strong>. That was when they started working on <strong>Codex</strong> which was released to the public in 2021. This is a new technology only been around for a few years and is just fantastic.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fvmAhjaqpvV5fiHKvvhcTg.png" /><figcaption>NLP models up to 2022 (not included)</figcaption></figure><p><strong>Darek:</strong> what products are being offered today by <strong>OpenAI</strong>?</p><p><strong>Gerard:</strong> there are three different products available from <strong>OpenAI</strong>.</p><p>The first is <strong>GPT-3</strong>, a model that can write text indistinguishable from human writing. It works by providing a starting text, a prompt, and GPT-3 will keep writing in a way that matches the existing text. For example, you can use it to create a story, or continue a conversation between characters. Some of these capabilities were not planned at all by their creators. <strong>This model was created to generate text by predicting the next word following a prompt, but then they realised that the model could identify more complex patterns</strong>, like a series of questions and answers, or even a general conversation. During the beta access, users found out that GPT-3 was able to do a lot of different things. <strong>You can, for example, ask for cooking recipes and it will give you the ingredients and how to cook them</strong>. That’s not text generation anymore, in the sense of writing a story or writing a book, but it’s more like identifying a question and providing an answer to that question. <strong>During the initial stages, a lot of different applications were identified. One of these was that it could write HTML, CSS, and JavaScript</strong>.</p><p>This led to the creation of <strong>Codex</strong>, a product specialising in coding. This is when <strong>OpenAI</strong> partnered with <strong>Microsoft</strong>, getting access to 59 million GitHub repositories. The outcome was that it learned how to use 12 different languages, including SQL and Bash commands.</p><p>Finally, DALL-E is the one I started talking about at the beginning.</p><p><strong>Darek:</strong> what is <strong>GPT-3</strong> trying to solve?</p><p><strong>Gerard:</strong> GPT-3 is a <strong>Natural Language Processing (NLP)</strong> model that generates text. GPT-3 can be given a text input and then generate any number of words. Usually, a stop sequence is used, so that GPT-3 will stop after the first paragraph. However, you can create complex patterns, such as a <strong>question-and-answer</strong> text, and GPT-3 will follow that. <strong>You can also ask for instructions and it will provide the instructions to achieve a goal</strong>, such as cooking a recipe.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fRzrhN9UXzabWyv5s3aWUg.png" /><figcaption>Most common usages for GPT-3 by OpenAI.</figcaption></figure><p><strong>Darek:</strong> Cooking recipes created by an AI !?!</p><p><strong>Gerard:</strong> yeah. It’s quite an exciting development. The idea behind it is that these models are very large. <strong>GPT-3 is 175 billion parameters large</strong>. That means it can generate more combinations than atoms in the universe. So this is a very big model that we cannot begin to imagine. And of course, one of the things it contains is cooking recipes. But this is not the most surprising thing that you can find inside these models.</p><p>The model can code in JavaScript! But it doesn’t stop there. <strong>Now it has also learned Typescript, Python, Ruby, Go, C sharp, Swift, Rust, PHP</strong>; and all of these languages after just a little bit less than half a terabyte of extra training.</p><p>Probably the weirdest thing is that <strong>it can speak more than a hundred languages, even though it was only trained in English</strong>. This is very surprising. In some languages, GPT-3 was able to learn using less than one percent of data. We don’t know how that happened. It was only supposed to learn English.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xvYQAMc1-4MdO6XMq-1U1Q.png" /><figcaption>Training Dataset for GPT-3.</figcaption></figure><p>One of the largest sources of information was the <strong>Common Crawl</strong>. These are the top websites and all their accompanying raw files. That’s how it learned JavaScript because a lot of its content is HTML, CSS, and JavaScript files. But then it also took information from hundreds of years of public books (Books1–2). And funny enough, from <strong>Reddit</strong> too (WebText2). So there’s a lot of information from users and the links that these users provided. So anything you can imagine is in there.</p><blockquote>The <strong>Common Crawl</strong> corpus contains petabytes of data collected over 12 years of web crawling.</blockquote><p>Another resource was <strong>Wikipedia</strong>. So anything that is in Wikipedia is also part of the training data for GPT-3. It’s a massive amount of data. It can do things like translate between languages. So you can write something in French and it can give you the translation in Polish.</p><p>If you look at the complexity of a language like <strong>English</strong>, then you can understand how it’s able to learn JavaScript, because JavaScript is much simpler than English.</p><p><strong>Darek:</strong> Yeah exactly.</p><p><strong>Gerard:</strong> If you’re wondering how it could learn Japanese with almost no information, you’re not alone. This is just the beginning of what AI is capable of, and we’ve only seen a fraction of its potential.</p><p><strong>GPT-3 is so large that it would be impossible for any one person to explore its entire latent space</strong>. What we’ve seen so far is just a drop in the bucket. For example, GPT-3 being able to generate cooking recipes is a small feat compared to what it’s capable of.</p><blockquote><strong>latent space</strong> is a mathematical space that maps what a neural network has learned from training</blockquote><p>It’s been more than half a year since GPT-3 was first used in production with <strong>GitHub Copilot</strong>, and it’s still going strong. This shows that it’s not only capable of understanding JavaScript but also able to provide code to professional programmers who are building all sorts of applications.</p><p>In short, <strong>we haven’t seen anything yet. GPT-3 is just getting started, and its potential is massive</strong>.</p><p><strong>Darek</strong>:<strong> </strong>what is <strong>Codex</strong> main purpose?</p><p><strong>Gerard</strong>: the main purpose of <strong>Codex</strong> is to generate valid code. As we have explained before, <strong>it is capable of writing code in many different programming languages, which makes it a valuable tool for developers</strong>. However, it is important to keep in mind that <strong>Codex</strong> was trained with a snapshot of GitHub repositories from last year. Anything after that snapshot, will not be aware of. <strong>The reason for not being trained regularly is that the process is very expensive and requires massive amounts of computing</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*uSLY9ilFApopXiX76EF8ag.png" /><figcaption>Main languages supported by Codex.</figcaption></figure><p><strong>Darek:</strong> what is <strong>DALL-E</strong> and how people are using it?</p><p><strong>Gerard:</strong> DALL-E is a model from <strong>OpenAI</strong> that is trained to generate images from a prompt. It is by far the most popular. <strong>DALL-E is everywhere on social media, from TikTok to Twitter</strong>. We have seen how OpenAI models learned to generate text and code, and this is the same for images.</p><p>Everything that GPT-3 knows, DALL-E knows. This means that it’s a writer, it’s also a developer and now it has also data around images. <strong>DALL-E was trained with 400 million images along with its metadata</strong> (title, description, creation date, camera, lenses, geolocation, etc). This allowed DALL-E to establish relationships between images and words. As a result, it can generate any sort of image following a prompt very closely. <strong>You can either generate an image from scratch or edit images by giving it instructions</strong>.</p><p>For example, one of the experiments that I did recently was to create a photorealistic picture of a woman using DALL-E. I provided information about the composition, how the model was positioned, and the lighting, and the camera angle. I got the picture I was after, and then <strong>I changed the image and asked DALL-E to add a black leather jacket to the model</strong>. Not only did it add the jacket to the picture, but it also took into consideration the volume, the lighting, and just placed the jacket on the model in a realistic way!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZPO8iAgPIHzsu29mr4CxlQ.png" /><figcaption>From left to right: initial image, editing and final result. Face fixed using tencentarc/gfpgan.</figcaption></figure><p><strong>DALL-E can not only do photography, but pixel art, 3D models, games, and illustrations too</strong>. Of course, photography is the most impressive, but you can also do things like hand-drawn illustrations. It’s something else.</p><p><strong>People are using DALL-E to create games because creating 3D models requires quite a lot of work</strong>. Sometimes you may need to create textures. Let’s say you are creating a castle and there’s some pattern in the walls which is sometimes made of rock or wood. It’s a difficult task for a digital artist to create a lot of variations for these textures. Today, you can give it to DALL-E and it will create the textures and variations for you. You can then use it in a 3D model and in a few minutes, you have got everything ready to go. <strong>You can build games fast using tools like DALL-E</strong>.</p><p><strong>Darek:</strong> That sounds amazing.</p><p><strong>Gerard:</strong> Yeah, there are some fancy use cases for it. For example, I can see that you have a sofa in the background. So, <strong>you could take a picture of a room and ask DALL-E to add furniture</strong>. So, imagine something is missing, maybe you want to add some artwork. You can give this task to DALL-E and it will just decorate your room in different styles if you like.</p><p><strong>People are also using DALL-E to recreate historic scenes</strong>. For example, you could ask it to give you a selfie of a soldier in Normandy during World War II. It’s anything that you can imagine. DALL-E can use all the information that you give it. It’s more like having a creative director that puts all the information together and makes it work.</p><p>Of course, the technology is very new. <strong>We are talking about a technology that didn’t exist last year</strong>. So, in just one year it has made a lot of progress. But we will see many other things happening with all of these different products. DALL-E is probably the most surprising because it’s very visual.</p><p><strong>Darek: </strong>can you use OpenAI today? How would that work?</p><p><strong>Gerard:</strong> the <strong>OpenAI API</strong> is available to anyone since 2021 by creating an account and buying some credits. You just need to get your <strong>API key</strong>, like you do with similar services, and you are ready to go. For Codex API, you will need to <strong>apply for beta access</strong>. So far there’s no API for DALL-E but you can use all of the models using the <strong>OpenAI Playground</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*esvO4CbG8qOj6rxEQoMXrQ.png" /><figcaption>Available APIs from OpenAI.</figcaption></figure><p><strong>Darek:</strong> what are the benefits of using those tools? Are there any drawbacks?</p><p><strong>Gerard:</strong> I think one of <strong>the benefits of GPT-3 is that it can boost your productivity</strong>. So if you need to create a technical blog post, for example, GPT-3 can help you do that in a fraction of the time it would normally take. With other products, it may depend on what you want to use them for. Sometimes the quality isn’t quite there yet, but you can use parts of the results of the outputs to speed up your project. <strong>So it can just depend on what exactly you want to use it for, but GPT-3 can help you be more productive</strong>.</p><p>As a drawback, I would say that GPT-3’s reliance on statistical methods means that there is no easy way to know if the information it gives you is factual. So if you are writing a blog post and some of the information is not factual, it can be a problem. <strong>Depending on how much you rely on AI, you will need to review it</strong>. You cannot just take the output from GPT-3 and use it in a publication and release it without checking the facts as you may be embarrassed later on.</p><p>It just depends on what you’re trying to do. <strong>Sometimes when you try to do something complex, there can be some issues with the technology</strong>. For example, in DALL-E, when it creates an image, human faces in the pictures don’t always look perfect. But I think these errors or these drawbacks are going to be fixed and then it’s going to be much, much faster to use these tools.</p><p><strong>Darek:</strong> what the future of AI may look like in five years?</p><p><strong>Gerard:</strong> I just did a talk around this topic where I described the <strong>AI Revolution</strong>. This is from the work of different authors.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*f5UWlGec22Skl2Qsqbqh0Q.png" /></figure><p>The first stage is called the <strong>Cognitive Revolution</strong>. This is where we use <strong>AI Assistants</strong> to get our job done faster. And depending on what you do, that will work best or not. I mean, even for GitHub Copilot, it’s not that the tool is creating everything for you. It’s just giving you some kind of productivity boost.</p><p>The next step, which is a little bit more far-fetched and it’s probably not going to be that soon, is the <strong>Robotics Revolution</strong>. This means fully autonomous robots. I think I saw the first robot in Silicon Valley some years ago. They go around a complex and they can give you information about what you can visit. But of course, this is not something that you can find everywhere yet, but in the future, we will see more examples of these.</p><p>The third stage is when AIs get smarter than humans which is called <strong>Singularity</strong>. At this point, the AIs will be similar to the character in <strong>Star Trek</strong>, Data. This is an Android that helps Star Trek characters when they struggle or they go on adventures. If there’s some danger and they need to make a decision, they ask Data.</p><p>People are not certain when all of these different stages will happen but there’s a recent quote from Elon Musk where he said that <strong>we are going to be overtaken by AIs in the next five years</strong>.</p><p><strong>Darek:</strong> do you think AI can help us build something we can’t do ourselves for now, like a super engine for a rocket?</p><p><strong>Gerard:</strong> yes. What is happening is that with these models we have created some kind of super intelligence. This means that they have all the information accessible at the same time. So one of these technologies that are being used behind the scenes is neural networks. This allows for a faster response time, as they don’t need to calculate. <strong>The neural network is more like a human</strong> in that it doesn’t even think, it just gives you the answer right away. When you use the systems GPT-3 and Codex, it is not taking seconds or even milliseconds to answer back. That means that <strong>all of the information is accessible to them right now</strong>.</p><p><strong>Darek:</strong> so when you ask it for example how to build a rocket engine, it will give you the answer right away?</p><p><strong>Gerard:</strong> exactly. The moment you ask, it will give you the answer right away. It doesn’t need to think about it for a while and give you an answer next week. No. It gives you the answer right away.</p><p><strong>Darek: </strong>what’s your conclusion?</p><p><strong>Gerard:</strong> my conclusion is that nobody knows what is happening with these models but it’s exciting because people find new use cases and they find new things every day that you can use these models for. There has also been news about open-sourcing some of these technologies so you can use them in your projects which is also very exciting.</p><p><strong>Darek: </strong>can you give some advice to people who are starting their career in IT today? And for those who are old-timers?</p><p><strong>Gerard:</strong> I think a good piece of advice is to <strong>keep your mind open</strong> because everything is changing. People think that things don’t change, but in the area of AI, things are changing fast. AI was not a technology that has been changing a lot. It’s kind of an old area, but the discoveries made in the last few years have exploded. It’s more like JavaScript. You know the new JavaScript that happened a few years back. And people were surprised like, “Oh, can you do this with JavaScript?” I mean before we didn’t use JavaScript in this way. So <strong>we are facing now a new generation of AI and this will change everything</strong>. A lot of the jobs that we do today won’t exist in the future. So if you’re not retiring, I mean if you’re an old-timer you maybe still have five, ten years, or 15 years more in your career, I think you should look into what’s happening in blockchain, what’s happening in web3. <strong>Keep your mind open, because you can become obsolete very fast</strong>.</p><p>New generations, I think should also be careful about what they focus on. If you focus on learning a specialised skill and then realise that anyone can be productive in that technology because of AI assistants, you will have wasted your time. Why would you want to memorise things or understand things when an AI can help you? So then it’s not clear that you want to go through specialisation of 15 years and then find out that someone who doesn’t even have a specialisation is using a tool that helps them achieve the same results in just five years. So then you have lost 10 years learning something that wasn’t necessary. So that’s something to be careful about.</p><p><strong>Darek: </strong>thank you, Gerard, for joining today’s podcast and sharing your knowledge with us. I look forward to meeting you in Warsaw soon.</p><p><strong>Gerard:</strong> thanks a lot for inviting me. I’m looking forward to another edition of the conference. Thank you so much. Bye-bye, everyone!</p><h3>Thanks for reading!</h3><p>Have you got any questions? Feel free to leave your comments below or reach out on Twitter at <a href="https://twitter.com/gerardsans">gerardsans</a>.</p><h3>Resources</h3><p>You can also listen to the original podcast using the links below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gPKL2hC6AD1bol6YkuXifw.png" /></figure><p>Spotify: <a href="https://t.co/UJxUNdmpDx">https://spoti.fi/3CHg2Zb</a></p><p>Google: <a href="https://t.co/0uTnKLSNSw">https://bit.ly/JSMP-5</a></p><p>Apple: <a href="https://t.co/bZDdwWvI4S">https://apple.co/3CdOJUY</a></p><p>Anchor: <a href="https://t.co/7ezIIapNfU">https://bit.ly/JSMP-05</a></p><p>YouTube: <a href="https://t.co/oUqwpuf01D">https://bit.ly/JSMP-GS-5</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1eef98d0e2a3" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Offline-first made easy with GraphQL, Amplify DataStore and Vue]]></title>
            <link>https://medium.com/js-dojo/offline-first-made-easy-with-graphql-amplify-datastore-and-vue-540cbe96e893?source=rss-9530b046d2ac------2</link>
            <guid isPermaLink="false">https://medium.com/p/540cbe96e893</guid>
            <category><![CDATA[graphql]]></category>
            <category><![CDATA[pwa]]></category>
            <category><![CDATA[aws-amplify]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[vuejs]]></category>
            <dc:creator><![CDATA[Gerard Sans]]></dc:creator>
            <pubDate>Thu, 01 Oct 2020 15:33:39 GMT</pubDate>
            <atom:updated>2020-10-15T04:08:41.822Z</atom:updated>
            <content:encoded><![CDATA[<p>Create a PWA cloud-enabled offline-first chatroom using Vue</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*K7TdpB-Qxslznk4L.png" /></figure><p>In this article, you will create Chatty, a chatroom Progressive Web App (PWA) that stores data on the device while offline, and synchronises in real-time with other devices when online using Amplify DataStore, GraphQL and Amazon DynamoDB. We will cover:</p><ul><li>Introduction to <strong>Offline-first</strong>, <strong>PWAs</strong> and <strong>Amplify DataStore</strong></li><li>Setting up a new project with the <strong>Vue CLI</strong></li><li>Creating a new <strong>GraphQL API</strong></li><li><strong>Amplify DataStore</strong>: setup, data models and usage</li><li><strong>Creating the UI with Vue</strong>: the chatroom, sending and deleting messages; and doing real-time with subscriptions</li><li>Making Chatty a <strong>PWA</strong></li><li>Adding a <strong>PWA custom configuration</strong></li><li><strong>Improving UX</strong> while offline</li><li>Publishing your app via the <strong>AWS Amplify Console</strong></li><li>Installing Chatty in the <strong>Desktop and Mobile</strong></li><li>Cleaning up <strong>cloud services</strong></li></ul><blockquote><em>In order to follow this post you will need a basic knowledge of GraphQL. You can learn the basics following this tutorial at </em><a href="https://graphql.org/learn/"><em>graphql.org</em></a><em>. We will be referring to GraphQL schema, directives, types, queries, mutations, subscriptions and resolvers.</em></blockquote><p>Please let me know if you have any questions or want to learn more at <a href="https://twitter.com/intent/user?screen_name=gerardsans">@gerardsans</a>.</p><p>&gt; <a href="https://github.com/gsans/amplify-datastore-chatty-pwa-vue">Final solution</a> and step by step tutorial in <a href="https://github.com/gsans/amplify-datastore-chatty-vue">GitHub</a>.</p><h3>Introduction to Offline-first, PWAs and Amplify DataStore</h3><p>Offline-first is an approach to software development, where an application is built to function, with or without an internet connection. Using this approach, data is stored locally on the user’s device and periodically uploaded and replicated into the cloud. Features include:</p><ul><li><strong>Offline ready</strong>: application works offline. This usually comes with some limitations regarding feature set and device capabilities. Eg: PWAs require an install step where the user needs to be online to download all the necessary application assets.</li><li><strong>Great user experience</strong>: application loads fast and transitions seamlessly from online to offline improving user retention. The user is in control regarding app updates, data synchronisation, data conflict resolution and connectivity. Eg: App shell; user is informed about connectivity changes.</li><li><strong>Native-like features</strong>: application behaves similar to a native app. Eg: PWAs are able to run on multiple operating systems as standalone applications and don’t require the user to interact with the browser.</li><li><strong>Reliable storage</strong>: user can exit the application at any moment without losing data. Application stores user data securely on-device and synchronises with the cloud transparently when possible.</li></ul><h3>Progressive Web Apps</h3><p>Progressive Web Apps combine the benefits from native apps, while being able to run on more platforms, leveraging browser technologies. PWA features allow Web apps to close the gap with native applications while creating similar user experiences. PWA features:</p><ul><li>Works <strong>offline</strong> via service worker.</li><li><strong>Great</strong> <strong>performance</strong> via app shell and pre-cached assets.</li><li>Access to <strong>device APIs</strong> via <a href="https://whatwebcando.today/">Web APIs</a>.</li><li>Supports <strong>push notifications</strong> via service worker.</li><li>Works in <strong>Web, Mobile and Desktop</strong> via Web app manifest.</li></ul><p>The most important requirements for PWA are: security, must be served via HTTPS, the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers">service worker</a> and the <a href="https://developer.mozilla.org/en-US/docs/Web/Manifest">Web app manifest</a>. We will incorporate all of these to Chatty.</p><h3>Amplify DataStore</h3><p>Amplify DataStore, is an on device persistent repository for interacting with local data, and able to automatically synchronise via GraphQL. Using Amplify DataStore, you can provide a <strong>great offline-first experience</strong> for your users, while using a <strong>simple programming model</strong>.</p><blockquote><em>GraphQL knowledge is beneficial when using Amplify DataStore to understand its inner workings but not necessary to use DataStore APIs.</em></blockquote><p>Amplify takes care of all the heavy lifting regarding hosting your data source in the cloud using <strong>Amazon DynamoDB</strong>;<strong> </strong>and scaling real-time messaging, synchronising data and running conflict resolution with <strong>AWS AppSync </strong>and<strong> GraphQL.</strong></p><p>Amplify<strong> </strong>DataStore uses your <strong>GraphQL schema</strong> to generate data models. These will help keep your client code consistent with the type and fields defined in your GraphQL schema; and reduce type checks and data related run-time errors while enforcing <strong>GraphQL type safety</strong>.</p><p>Amplify DataStore behaves differently when in offline or online modes:</p><ul><li><strong>In offline mode, </strong>we use the <strong>DataStore API</strong> to manage the data on the device via the <strong>Storage Engine</strong> using GraphQL. The local <strong>Data Store</strong> being used will vary depending on the user device. This can either be IndexedDB in the browser or SQL Lite in Android and iOS.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*4-aOVRjjvMrfbcn1.png" /><figcaption>Amplify DataStore data flow in offline mode</figcaption></figure><ul><li><strong>In online mode, </strong>Amplify DataStore, will synchronise with the cloud using the <strong>Sync Engine</strong> via GraphQL to automatically synchronise with your GraphQL API. At the query level, this is implemented as an <strong>AWS AppSync resolver</strong> accessing <strong>Amazon DynamoDB</strong>, <strong>AWS Lambda</strong> or <strong>Amazon ElasticSearch</strong>.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*SXfm70Qy3Nt-NryF.png" /><figcaption>Amplify DataStore data flow in online mode</figcaption></figure><p>Amplify DataStore supports the following conflict resolution modes during synchronisation:</p><ul><li><strong>Optimistic concurrency</strong>, this mode rejects any incoming changes if there’s a mismatch in the tracking version between the incoming change and the item being changed. A further step on the client is required to resolve the conflict.</li><li><strong>Auto merge</strong> (default), this mode doesn’t require further steps to resolve conflicts. It accommodates mutations on a field-by-field basis as long as scalar types don’t clash. If they do, they are ignored but all other fields are merged, if possible.</li><li><strong>Custom</strong>, this mode uses<strong> </strong>AWS Lambda to allow more control and complex use cases.</li></ul><p>For more details read <a href="https://docs.aws.amazon.com/appsync/latest/devguide/conflict-detection-and-sync.html">conflict detection and sync</a>.</p><h3>Setting up a new project with the Vue CLI</h3><p>Before moving to the next section, please complete the steps described in “<a href="https://medium.com/@gerard.sans/build-your-first-full-stack-serverless-app-with-vue-and-aws-amplify-9ed7ef9e9926">Build your first full-stack serverless app with Vue</a>”. Here you will set up the initial project, familiarise with <strong>Amplify CLI</strong> and add an authorisation flow so users can register themselves via an automated verification code sent to their email and login.</p><h3>Creating a new GraphQL API</h3><p>First, we are going to create the GraphQL API to service <strong>Chatty</strong> chatroom. To create it, we will use the following command:</p><pre>amplify add api</pre><p>Answer the following questions</p><ul><li>Please select from one of the below mentioned services <strong>GraphQL</strong></li><li>Provide API name: <strong>ChattyAPI</strong></li><li>Choose the default authorization type for the API <strong>API key</strong></li><li>Enter a description for the API key: <strong>(empty)</strong></li><li>After how many days from now the API key should expire (1–365): <strong>7</strong></li></ul><blockquote><em>It’s important that you don’t miss the following steps to set up conflict detection. If you missed it, you can recover with </em><em>amplify api update</em></blockquote><ul><li>Do you want to configure advanced settings for the GraphQL API <strong>Yes, I want to make some additional changes.</strong></li><li>Configure additional auth types? <strong>No</strong></li><li>Configure conflict detection? <strong>Yes</strong></li><li>Select the default resolution strategy <strong>Auto Merge</strong></li><li>Do you want to override default per model settings? <strong>No</strong></li><li>Do you have an annotated GraphQL schema? <strong>No</strong></li><li>Choose a schema template: <strong>Single object with fields (e.g., “Todo” with ID, name, description)</strong></li><li>Do you want to edit the schema now? <strong>Yes</strong></li></ul><p>When prompted, replace the default schema with the following:</p><pre>type Chatty <strong>@model</strong> {<br>  id: ID!<br>  user: String!<br>  message: String!<br>  createdAt: AWSDateTime<br>}</pre><p>By adding@model to the Chatty type we are telling the <strong>Amplify CLI</strong> to create the resolvers to support queries, mutations and subscriptions in <strong>Amazon DynamoDB</strong>. Besides the regular <strong>CRUD operations</strong>, we are also getting some more advanced features like pagination, filtering and real-time synchronisation that we are going to use later.</p><h3>Pushing your GraphQL API to the cloud</h3><p>Let’s run the push command to create the GraphQL API:</p><pre>amplify push</pre><ul><li>Are you sure you want to continue? <strong>Yes</strong></li><li>Do you want to generate code for your newly created GraphQL API <strong>Yes</strong></li><li>Choose the code generation language target <strong>javascript</strong></li><li>Enter the file name pattern of graphql queries, mutations and subscriptions <strong>src/graphql/**/*.js</strong></li><li>Do you want to generate/update all possible GraphQL operations — queries, mutations and subscriptions <strong>Yes</strong></li><li>Enter maximum statement depth [increase from default if your schema is deeply nested] <strong>2</strong></li></ul><p>Write down your <strong>GraphQL endpoint</strong> and <strong>API KEY</strong>.</p><p>This is the resulting architecture with our new GraphQL API managed by <strong>AWS AppSync</strong> and <strong>Amazon DynamoDB</strong>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*mVnMy-qEdM5r06x_.png" /></figure><p>Run the command below to access the <strong>AWS AppSync console</strong>.</p><pre>amplify console api</pre><ul><li>Please select from one of the below mentioned services <strong>GraphQL</strong></li></ul><h3>Amplify DataStore setup</h3><p>Run the command below to install the necessary dependencies:</p><pre>npm install --save @aws-amplify/core @aws-amplify/datastore</pre><h3>Data model generation</h3><p>Generate the data models to manage our messages for our <strong>ChattyAPI</strong>.</p><pre>amplify codegen models</pre><blockquote><em>Important: DO NOT forget to regenerate your models every time you introduce a change in your schema.</em></blockquote><p>After running this command, <strong>AWS Amplify CLI</strong> has generated the necessary data models in a new folder. The files in this folder hold your data model classes and schema.</p><pre>&lt;amplify-app&gt;<br>    |_ src<br>      |_ models</pre><h3>Creating a message</h3><p>Now that the GraphQL API and <strong>data models</strong> are created, we can begin using the <strong>DataStore API</strong>. The first thing we’ll do is create a new message passing the generated <strong>data model</strong> to save.</p><blockquote><em>Using data models allow us to be always compliant with the GraphQL schema and prevent errors right in the client.</em></blockquote><pre>import { DataStore } from &quot;@aws-amplify/datastore&quot;;<br>import { Chatty } from &quot;./models&quot;;</pre><pre>await DataStore.save(new Chatty({<br>  user: &quot;amplify-user&quot;,<br>  message: &quot;Hi everyone!&quot;,<br>  createdAt: new Date().toISOString()<br>}))</pre><p>This will create a record locally in your device and synchronise it in the background using the underlying <strong>GraphQL API</strong> when in online mode.</p><h3>Querying data</h3><p>Let’s see how we can query the data using Amplify DataStore. In order to query our <strong>data model</strong> we will use a query and a predicate to indicate that we want all records.</p><pre>import { DataStore, Predicates } from &quot;@aws-amplify/datastore&quot;;<br>import { Chatty } from &quot;./models&quot;;</pre><pre>const messages = await DataStore.query(Chatty, Predicates.ALL);</pre><p>This will return an array of messages that we can display in our UI. <strong>Predicates</strong> also support filters for common types like Strings, Numbers and Lists.</p><blockquote><em>Find all supported filters at </em><a href="https://aws-amplify.github.io/docs/js/datastore#query-with-predicates"><em>query with Predicates</em></a><em>.</em></blockquote><h3>Creating the UI with Vue</h3><p>Now, let’s look at how we can create the UI to create and display messages for Chatty chatroom.</p><pre>&lt;template&gt;<br>  &lt;div v-for=&quot;message of sorted&quot; :key=&quot;message.id&quot;&gt;<br>    &lt;div&gt;{{ message.user }} - {{ moment(message.createdAt).format(&#39;YYYY-MM-DD HH:mm:ss&#39;)}})&lt;/div&gt;<br>    &lt;div&gt;{{ message.message }}&lt;/div&gt;<br>  &lt;/div&gt;<br>&lt;/template&gt;<br>&lt;script&gt;<br>import { DataStore, Predicates } from &quot;@aws-amplify/datastore&quot;;<br>import { Chatty } from &quot;./models&quot;;<br>import moment from &quot;moment&quot;;export default {<br>  name: &#39;app&#39;,<br>  data() {<br>    return {<br>      user: {},<br>      messages: [],<br>    }<br>  },<br>  computed: {<br>    sorted() {<br>      return [...this.messages].sort((a, b) =&gt; -a.createdAt.localeCompare(b.createdAt));<br>    }<br>  },<br>  created() {<br>    // authentication state managament<br>    onAuthUIStateChange((state, user) =&gt; {<br>      // set current user and load data after login<br>      switch (state) {<br>        case AuthState.SignedIn: {<br>          this.user = user;<br>          this.loadMessages();<br>          break;<br>        }<br>      }<br>    });<br>  },<br>  methods: {<br>    moment: () =&gt; moment(),<br>    loadMessages() {<br>      DataStore.query(Chatty, Predicates.ALL).then(messages =&gt; {<br>        this.messages = messages;<br>      });<br>    },<br>  }<br>}<br>&lt;/script&gt;</pre><p>After the user signs in, we call loadMessages. This fetches all the messages in our local store. We are sorting the list with a computed method sorted as we want our messages to show the most recent at the top. We are also using moment to format our time variables.</p><h3>Creating a message</h3><p>Now, let’s look at how we create new messages.</p><pre>&lt;template&gt;<br>  &lt;form v-on:submit.prevent&gt;<br>    &lt;input v-model=&quot;form.message&quot; placeholder=&quot;Enter your message...&quot; /&gt;<br>    &lt;button @click=&quot;sendMessage&quot;&gt;Send&lt;/button&gt;<br>  &lt;/form&gt;<br>&lt;/template&gt;<br>&lt;script&gt;<br>export default {<br>  data() {<br>    return {<br>      form: {},<br>    };<br>  }, <br>  methods: {<br>    sendMessage() {<br>      const { message } = this.form<br>      if (!message) return;<br>      DataStore.save(new Chatty({<br>        user: this.user.username,<br>        message: message,<br>        createdAt: new Date().toISOString()<br>      })).then(() =&gt; {<br>        this.form = { message: &#39;&#39; };<br>        this.loadMessages();<br>      }).catch(e =&gt; {<br>        console.log(&#39;error creating message...&#39;, e);<br>      });<br>    },<br>  }<br>}<br>&lt;/script&gt;</pre><p>We use a form to read the message from the user and call sendMessage with save passing the user and current date along with the message. Once the message has been created we reset the input field and reload all messages. Note how we use Amplify DataStore as our source of truth in this implementation.</p><h3>Deleting all messages</h3><p>One of the main advantages of working using Amplify DataStore is being able to run a series of GraphQL mutations without having to use a series of individual operations. See below how we can use delete together with a predicate to remove all messages.</p><pre>DataStore.delete(Chatty, Predicates.ALL).then(() =&gt; {<br>  console.log(&#39;messages deleted!&#39;);<br>});</pre><blockquote><em>When using Amplify DataStore records are never removed, but marked for removal. Records will then be automatically removed as defined in their </em><a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html"><em>TTL</em></a><em> attribute. At the time of writing, this is set to 30 days.</em></blockquote><h3>Real-time with GraphQL subscriptions</h3><p>Next, let’s see how we can create a GraphQL subscription. To do so, we will listen for changes of data in our API, and update the state whenever a new piece of data comes through. When the component is destroyed, we will unsubscribe to avoid memory leaks.</p><blockquote><em>As we are using Amplify DataStore, as our source of truth, we don’t need another copy of it at the app level so we just need to load the latest state with </em><em>loadMessages.</em></blockquote><pre>&lt;script&gt;<br>export default {<br>  data() {<br>    return {<br>      subscription: undefined;<br>    };<br>  },<br>  created() {<br>    //Subscribe to changes<br>    this.subscription = DataStore.observe(Chatty).subscribe(msg =&gt; {<br>      console.log(msg.model, msg.opType, msg.element);<br>      this.loadMessages();<br>    });<br>  }, <br>  destroyed() {<br>    if (!this.subscription) return;<br>    this.subscription.unsubscribe();<br>  },<br>}<br>&lt;/script&gt;</pre><p>At this point, the chatroom is fully working including authentication flow and data synchronisation in real-time.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*75bD7d25yoLhW7N4.png" /><figcaption>Real-time synchronisation using Chrome and Firefox clients side-by-side.</figcaption></figure><p>On the other hand, we haven’t made much progress in making it work offline or having native-like features. In order to tick these boxes, we are going to make our app a <strong>PWA</strong>.</p><h3>Making Chatty a PWA</h3><p>The <a href="https://cli.vuejs.org/core-plugins/pwa.html#vue-cli-plugin-pwa">PWA CLI plugin</a> can help us making Chatty a PWA by running a single command:</p><pre>vue add @vue/pwa</pre><p>This will make few changes to the project and add a few new assets necessary to run the app as a PWA. The most important change happens in src/main.js where we are now registering a <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers"><strong>service worker</strong></a><strong> </strong>that will allow Chatty to work offline.</p><p>Using the default settings, the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers"><strong>service worker</strong></a> is configured to pre-cache all the assets resulting from the build (js, css and public folder). Using this setup, the browser can access the cache to load the app while offline. See the diagram below:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*q7H-gNJTOVzWw5rt.png" /><figcaption>Service worker serving assets from the cache while offline</figcaption></figure><blockquote><em>Learn more about service workers at </em><a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers"><em>using service workers</em></a><em>.</em></blockquote><p>Run the build command to see changes:</p><pre>yarn build</pre><p>In your dist folder you should find the following:</p><pre>└── dist<br>  ├── css<br>  │   └── app.&lt;version&gt;.css<br>  ├── img/icons<br>  │   ├── android-chrome-&lt;size&gt;.png<br>  │   └── ...<br>  ├── js<br>  │   ├── app.&lt;version&gt;.png<br>  │   └── ...<br>  ├── favicon.ico<br>  ├── index.html<br>  ├── manifest.json<br>  ├── precache-manifest.&lt;version&gt;.json<br>  ├── robots.txt<br>  └── service-worker.js</pre><p>The index.html has been modified to include the <a href="https://developer.mozilla.org/en-US/docs/Web/Manifest">Web app manifest</a> manifest.json along with some meta tags and entries to support different devices and platforms. You can further customise these settings. The most important ismanifest.json/display set to standalone. This setting will give the app a look and feel like a native application for Desktop and Mobile. Learn about all the options available in <a href="https://developer.mozilla.org/en-US/docs/Web/Manifest">Web app manifest</a>.</p><p>Another important file is service-worker.js. This contains the implementation for the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers"><strong>service worker</strong></a> which determines the behaviour of the app while offline. As part of it, precache-manifest.&lt;version&gt;.json includes all files to be installed and pre-cached as part of the app. This will make the app load almost instantly as it won’t use the network. These files were created by the <a href="https://cli.vuejs.org/core-plugins/pwa.html#vue-cli-plugin-pwa">PWA CLI plugin</a> and include all the assets from your build.</p><p>Test the app running the following commands on a new terminal window:</p><pre>cd dist<br>python -m SimpleHTTPServer 8887  // open localhost:8887</pre><blockquote><em>Remember that in order to test the app you need to install the service worker first. This requires at least loading the app once.</em></blockquote><p>To test the app while offline you can use the <strong>Developer Tools</strong> or switch off your <strong>internet connection</strong>. See below a screen capture after refreshing the page while offline:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*jc9PgxWFbeYO3HRS.png" /><figcaption>Chatty app while offline.</figcaption></figure><p>As you can see in the screenshot above using Chrome, in the <strong>Network tab</strong>, the files are served by the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers"><strong>service worker</strong></a> while offline (in green). Unfortunately the default setup won’t include any custom assets like our <strong>SVG logo</strong> in the header (in red) or external fonts.</p><h3>Adding a PWA custom configuration</h3><p>Let’s fix the issue with our logo by using a <strong>custom configuration</strong>. Create vue.config.js with the following content at the root of your project:</p><pre>// vue.config.js<br>const manifest = require(&#39;./public/manifest.json&#39;)</pre><pre>module.exports = {<br>  pwa: {<br>    name: manifest.short_name,<br>    themeColor: manifest.theme_color,<br>    msTileColor: manifest.background_color,<br>    appleMobileWebAppCapable: &#39;yes&#39;,<br>    appleMobileWebAppStatusBarStyle: &#39;black&#39;,<br>    workboxPluginMode: &#39;InjectManifest&#39;,<br>    workboxOptions: {<br>      swSrc: &#39;src/service-worker.js&#39;,<br>    }<br>  }<br>}</pre><p>This file controls the <a href="https://cli.vuejs.org/core-plugins/pwa.html#vue-cli-plugin-pwa">PWA CLI plugin</a> and deal with settings in the <a href="https://developer.mozilla.org/en-US/docs/Web/Manifest">Web app manifest</a> and UX for different devices.</p><p>The custom configuration uses <a href="https://developers.google.com/web/tools/workbox">workbox</a> in injectManifest mode and points to the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers">service worker</a> implementation we want to use. Find all configuration options at the <a href="https://cli.vuejs.org/core-plugins/pwa.html#configuration">official website</a>. Now create src/service-worker.js with the following code</p><pre>// src/service-worker.js<br>workbox.core.setCacheNameDetails({ prefix: &#39;amplify-datastore&#39; })</pre><pre>workbox.core.skipWaiting()<br>workbox.core.clientsClaim()</pre><pre>const cacheFiles = [{<br> &quot;revision&quot;: &quot;e653ab4d124bf16b5232&quot;,<br> &quot;url&quot;: &quot;<a href="https://aws-amplify.github.io/img/amplify.svg">https://aws-amplify.github.io/img/amplify.svg</a>&quot;<br>}]</pre><pre>self.__precacheManifest = cacheFiles.concat(self.__precacheManifest || [])<br>workbox.precaching.precacheAndRoute(self.__precacheManifest, {})</pre><p>For our <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers"><strong>service worker</strong></a>, we are setting a prefix for our cache to easily find our files while using the <strong>Developer Tools</strong>. We are also setting the behaviour for new service worker versions. These will be applied immediately replacing any existing ones with skipWaiting and clientsClaim as explained <a href="https://developers.google.com/web/tools/workbox/modules/workbox-core#skip_waiting_and_clients_claim">here</a>. To fix our <strong>SVG issue</strong>, we are adding the url to the SVG file, to the <strong>pre-cached files</strong> defined in the <a href="https://developer.mozilla.org/en-US/docs/Web/Manifest">Web app manifest</a>.</p><h3>Improving UX while offline</h3><p>We are almost done. Our app can survive offline reloads, can store messages while offline and can synchronise when back online thanks to Amplify DataStore.</p><p>The only remaining issue now is <strong>improving the user experience</strong> as the user doesn’t know when the app is operating online or offline. This is not a great UX, as sometimes <strong>the user might inadvertently go offline</strong> and be confused as for not receiving any feedback or explanation from the app. We can fix this by using the code below:</p><pre>// &lt;div v-if=&quot;offline&quot;&gt;You are offline.&lt;/div&gt;<br>// &lt;div v-bind:class=&quot;{ offline: offline }&quot;&gt;</pre><pre>// App.vue<br>import { Hub } from &#39;aws-amplify&#39;;export default {<br>  data() {<br>    return { offline: undefined };<br>  },<br>  created() {<br>    this.listener = Hub.listen(&#39;datastore&#39;, {payload:{event}} =&gt; {<br>      if (event === &#39;networkStatus&#39;) {<br>        this.offline = !data.active;<br>      }<br>    })<br>  }<br>}</pre><p>We are using the <a href="https://docs.amplify.aws/lib/utilities/hub/q/platform/js"><strong>Amplify Hub</strong></a> to detect <strong>network changes</strong> and use it to set the offline flag. Once in place, we can use it to display messages or style the UI accordingly as shown at the beginning of the code above. We are now ready to publish <strong>Chatty</strong> to the cloud and test it using different devices.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/472/0*wNyltCbngZfLcpS1.png" /><figcaption>Chatty PWA informing the user of changes in the network status.</figcaption></figure><h3>Publishing your app via the AWS Amplify Console</h3><p>The first thing you need to do is <strong>create a new repo</strong> for this project. Once you’ve created the repo, copy the <strong>URL</strong> for the project to the clipboard and initialise git in your local project:</p><pre>git init<br>git remote add origin <a href="/service/mailto:repo@repoofyourchoice.com">repo@repoofyourchoice.com</a>:username/project-name.git<br>git add .git commit -m &#39;initial commit&#39;git push origin master</pre><p>Next visit the <a href="https://aws.amazon.com/amplify/console/"><strong>AWS Amplify Console</strong></a> in your <strong>AWS account</strong>. Click <strong>Get Started </strong>to create a new deployment. Next, authorise your repository provider as the repository service. Next, choose the new repository and branch for the project you just created and click <strong>Next</strong>. In the next screen, create a new role and use this role to allow the <strong>AWS Amplify Console</strong> to deploy these resources and click <strong>Next</strong>. Finally, click <strong>Save</strong> and <strong>Deploy</strong> to deploy your application!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*1aIsCKjYcBcD5W6D.png" /><figcaption>AWS Amplify Console deployment steps.</figcaption></figure><p>This will generate a public url that uses <strong>HTTPS</strong>, which is a requirement for <strong>PWAs.</strong> Congratulations! You can now test it in your browser, Desktop and Mobile.</p><h3>Installing the Chatty app in the Desktop and Mobile</h3><p>Due to the inclusion of the <a href="https://developer.mozilla.org/en-US/docs/Web/Manifest">Web app manifest</a> in our index.html page, you can now install the <strong>Chatty</strong> app in the Desktop and Mobile devices in Windows, Mac and Linux. The way it works, changes slightly depending the device and operating system you are using. Try it out following the steps in <a href="https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Add_to_home_screen">Add to Home screen</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/978/0*WlwWk9q0Ey_RgWiE.png" /><figcaption>Use add to Home screen to install in Desktop and Mobile.</figcaption></figure><h3>Cleaning up cloud services</h3><p>If at any time, you would like to delete a service from your project and your <strong>AWS Account</strong>, you can do this by running:</p><pre>amplify delete</pre><h3>Conclusion</h3><p>Congratulations! You successfully built your first <strong>offline-first app </strong>using <strong>Vue</strong> and <strong>Amplify</strong>. You created a chatroom <strong>PWA</strong> that stores data on the device while offline and when online synchronises in real-time with other devices using <strong>Amplify DataStore, AWS AppSync</strong>, <strong>GraphQL</strong> and <strong>Amazon DynamoDB</strong>. Thanks for following this tutorial.</p><p>If you prefer, you can follow the instructions in this video to build the chatroom app.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2Fvideoseries%3Flist%3DPLQX6IPseabtTLo28GsWh0Db-o0uH4TfHo&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DCXeRQn62Ptw&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FCXeRQn62Ptw%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/23b1a303a95bff9ab82a2d445a6198ef/href">https://medium.com/media/23b1a303a95bff9ab82a2d445a6198ef/href</a></iframe><h3>Thanks for reading!</h3><p>Have you got any questions about this tutorial or <strong>AWS Amplify</strong>? Feel free to reach me anytime at <a href="https://twitter.com/intent/user?screen_name=gerardsans">@gerardsans</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/360/0*2Qq62eF9HTBQDwbF.jpeg" /></figure><blockquote><em>My Name is </em><a href="https://twitter.com/gerardsans"><em>Gerard Sans</em></a><em>. I am a Developer Advocate at </em><a href="https://aws.amazon.com/products/mobile"><em>AWS Mobile</em></a><em> working with </em><a href="https://aws-amplify.github.io/"><em>AWS Amplify</em></a><em> and </em><a href="https://aws.amazon.com/appsync/"><em>AWS AppSync</em></a><em> teams.</em></blockquote><blockquote><em>GraphQL is an open source data query and manipulation language for APIs, and a runtime for fulfilling queries with existing data.</em></blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*hKsJf3Bo5IVylg_E.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=540cbe96e893" width="1" height="1" alt=""><hr><p><a href="https://medium.com/js-dojo/offline-first-made-easy-with-graphql-amplify-datastore-and-vue-540cbe96e893">Offline-first made easy with GraphQL, Amplify DataStore and Vue</a> was originally published in <a href="https://medium.com/js-dojo">Vue.js Developers</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Offline-first made easy with GraphQL, Amplify DataStore and Vue]]></title>
            <link>https://gerard-sans.medium.com/offline-first-made-easy-with-graphql-amplify-datastore-and-vue-f9f7eec03c2d?source=rss-9530b046d2ac------2</link>
            <guid isPermaLink="false">https://medium.com/p/f9f7eec03c2d</guid>
            <category><![CDATA[vuejs]]></category>
            <category><![CDATA[pwa]]></category>
            <category><![CDATA[graphql]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[aws-amplify]]></category>
            <dc:creator><![CDATA[Gerard Sans]]></dc:creator>
            <pubDate>Thu, 01 Oct 2020 10:30:10 GMT</pubDate>
            <atom:updated>2020-10-02T12:42:04.062Z</atom:updated>
            <content:encoded><![CDATA[<p>Create a PWA cloud-enabled offline-first chatroom using Vue</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Y6p-Vy2Gkh69BtCrfgOP8g.png" /></figure><p>In this article, you will create Chatty, a chatroom Progressive Web App (PWA) that stores data on the device while offline, and synchronises in real-time with other devices when online using Amplify DataStore, GraphQL and Amazon DynamoDB. We will cover:</p><ul><li>Introduction to <strong>Offline-first</strong>, <strong>PWAs</strong> and <strong>Amplify DataStore</strong></li><li>Setting up a new project with the <strong>Vue CLI</strong></li><li>Creating a new <strong>GraphQL API</strong></li><li><strong>Amplify DataStore</strong>: setup, data models and usage</li><li><strong>Creating the UI with Vue</strong>: the chatroom, sending and deleting messages; and doing real-time with subscriptions</li><li>Making Chatty a <strong>PWA</strong></li><li>Adding a <strong>PWA custom configuration</strong></li><li><strong>Improving UX</strong> while offline</li><li>Publishing your app via the <strong>AWS Amplify Console</strong></li><li>Installing Chatty in the <strong>Desktop and Mobile</strong></li><li>Cleaning up <strong>cloud services</strong></li></ul><blockquote><em>In order to follow this post you will need a basic knowledge of GraphQL. You can learn the basics following this tutorial at</em> <a href="https://graphql.org/learn/"><em>graphql.org</em></a><em>. We will be referring to GraphQL schema, directives, types, queries, mutations, subscriptions and resolvers.</em></blockquote><p>Please let me know if you have any questions or want to learn more at <a href="https://twitter.com/intent/user?screen_name=gerardsans">@gerardsans</a>.</p><p>&gt; <a href="https://github.com/gsans/amplify-datastore-chatty-pwa-vue">Final solution</a> and step by step tutorial in <a href="https://github.com/gsans/amplify-datastore-chatty-vue">GitHub</a>.</p><h3>Introduction to Offline-first, PWAs and Amplify DataStore</h3><p>Offline-first is an approach to software development, where an application is built to function, with or without an internet connection. Using this approach, data is stored locally on the user’s device and periodically uploaded and replicated into the cloud. Features include:</p><ul><li><strong>Offline ready</strong>: application works offline. This usually comes with some limitations regarding feature set and device capabilities. Eg: PWAs require an install step where the user needs to be online to download all the necessary application assets.</li><li><strong>Great user experience</strong>: application loads fast and transitions seamlessly from online to offline improving user retention. The user is in control regarding app updates, data synchronisation, data conflict resolution and connectivity. Eg: App shell; user is informed about connectivity changes.</li><li><strong>Native-like features</strong>: application behaves similar to a native app. Eg: PWAs are able to run on multiple operating systems as standalone applications and don’t require the user to interact with the browser.</li><li><strong>Reliable storage</strong>: user can exit the application at any moment without losing data. Application stores user data securely on-device and synchronises with the cloud transparently when possible.</li></ul><h4>Progressive Web Apps</h4><p>Progressive Web Apps combine the benefits from native apps, while being able to run on more platforms, leveraging browser technologies. PWA features allow Web apps to close the gap with native applications while creating similar user experiences. PWA features:</p><ul><li>Works <strong>offline</strong> via service worker.</li><li><strong>Great</strong> <strong>performance</strong> via app shell and pre-cached assets.</li><li>Access to <strong>device APIs</strong> via <a href="https://whatwebcando.today/">Web APIs</a>.</li><li>Supports <strong>push notifications</strong> via service worker.</li><li>Works in <strong>Web, Mobile and Desktop</strong> via Web app manifest.</li></ul><p>The most important requirements for PWA are: security, must be served via HTTPS, the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers">service worker</a> and the <a href="https://developer.mozilla.org/en-US/docs/Web/Manifest">Web app manifest</a>. We will incorporate all of these to Chatty.</p><h4>Amplify DataStore</h4><p>Amplify DataStore, is an on device persistent repository for interacting with local data, and able to automatically synchronise via GraphQL. Using Amplify DataStore, you can provide a <strong>great offline-first experience</strong> for your users, while using a <strong>simple programming model</strong>.</p><blockquote>GraphQL knowledge is beneficial when using Amplify DataStore to understand its inner workings but not necessary to use DataStore APIs.</blockquote><p>Amplify takes care of all the heavy lifting regarding hosting your data source in the cloud using <strong>Amazon DynamoDB</strong>;<strong> </strong>and scaling real-time messaging, synchronising data and running conflict resolution with <strong>AWS AppSync </strong>and<strong> GraphQL.</strong></p><p>Amplify<strong> </strong>DataStore uses your <strong>GraphQL schema</strong> to generate data models. These will help keep your client code consistent with the type and fields defined in your GraphQL schema; and reduce type checks and data related run-time errors while enforcing <strong>GraphQL type safety</strong>.</p><p>Amplify DataStore behaves differently when in offline or online modes:</p><ul><li><strong>In offline mode, </strong>we use the <strong>DataStore API</strong> to manage the data on the device via the <strong>Storage Engine</strong> using GraphQL. The local <strong>Data Store</strong> being used will vary depending on the user device. This can either be IndexedDB in the browser or SQL Lite in Android and iOS.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tfo7SD-FVUjTqqnvjUWQgQ.png" /><figcaption>Amplify DataStore data flow in offline mode</figcaption></figure><ul><li><strong>In online mode, </strong>Amplify DataStore, will synchronise with the cloud using the <strong>Sync Engine</strong> via GraphQL to automatically synchronise with your GraphQL API. At the query level, this is implemented as an <strong>AWS AppSync resolver</strong> accessing <strong>Amazon DynamoDB</strong>, <strong>AWS Lambda</strong> or <strong>Amazon ElasticSearch</strong>.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5Ts59jaZtvpwKyBorewthA.png" /><figcaption>Amplify DataStore data flow in online mode</figcaption></figure><p>Amplify DataStore supports the following conflict resolution modes during synchronisation:</p><ul><li><strong>Optimistic concurrency</strong>, this mode rejects any incoming changes if there’s a mismatch in the tracking version between the incoming change and the item being changed. A further step on the client is required to resolve the conflict.</li><li><strong>Auto merge</strong> (default), this mode doesn’t require further steps to resolve conflicts. It accommodates mutations on a field-by-field basis as long as scalar types don’t clash. If they do, they are ignored but all other fields are merged, if possible.</li><li><strong>Custom</strong>, this mode uses<strong> </strong>AWS Lambda to allow more control and complex use cases.</li></ul><p>For more details read <a href="https://docs.aws.amazon.com/appsync/latest/devguide/conflict-detection-and-sync.html">conflict detection and sync</a>.</p><h3>Setting up a new project with the Vue CLI</h3><p>Before moving to the next section, please complete the steps described in “<a href="https://medium.com/@gerard.sans/build-your-first-full-stack-serverless-app-with-vue-and-aws-amplify-9ed7ef9e9926">Build your first full-stack serverless app with Vue</a>”. Here you will set up the initial project, familiarise with <strong>Amplify CLI</strong> and add an authorisation flow so users can register themselves via an automated verification code sent to their email and login.</p><h3>Creating a new GraphQL API</h3><p>First, we are going to create the GraphQL API to service <strong>Chatty</strong> chatroom. To create it, we will use the following command:</p><pre>amplify add api</pre><p>Answer the following questions</p><ul><li>Please select from one of the below mentioned services <strong>GraphQL</strong></li><li>Provide API name: <strong>ChattyAPI</strong></li><li>Choose the default authorization type for the API <strong>API key</strong></li><li>Enter a description for the API key: <strong>(empty)</strong></li><li>After how many days from now the API key should expire (1–365): <strong>7</strong></li></ul><blockquote>It’s important that you don’t miss the following steps to set up conflict detection. If you missed it, you can recover with amplify api update</blockquote><ul><li>Do you want to configure advanced settings for the GraphQL API <strong>Yes, I want to make some additional changes.</strong></li><li>Configure additional auth types? <strong>No</strong></li><li>Configure conflict detection? <strong>Yes</strong></li><li>Select the default resolution strategy <strong>Auto Merge</strong></li><li>Do you want to override default per model settings? <strong>No</strong></li><li>Do you have an annotated GraphQL schema? <strong>No</strong></li><li>Choose a schema template: <strong>Single object with fields (e.g., “Todo” with ID, name, description)</strong></li><li>Do you want to edit the schema now? <strong>Yes</strong></li></ul><p>When prompted, replace the default schema with the following:</p><pre>type Chatty <strong>@model</strong> {<br>  id: ID!<br>  user: String!<br>  message: String!<br>  createdAt: AWSDateTime<br>}</pre><p>By adding@model to the Chatty type we are telling the <strong>Amplify CLI</strong> to create the resolvers to support queries, mutations and subscriptions in <strong>Amazon DynamoDB</strong>. Besides the regular <strong>CRUD operations</strong>, we are also getting some more advanced features like pagination, filtering and real-time synchronisation that we are going to use later.</p><h4>Pushing your GraphQL API to the cloud</h4><p>Let’s run the push command to create the GraphQL API:</p><pre>amplify push</pre><ul><li>Are you sure you want to continue? <strong>Yes</strong></li><li>Do you want to generate code for your newly created GraphQL API <strong>Yes</strong></li><li>Choose the code generation language target <strong>javascript</strong></li><li>Enter the file name pattern of graphql queries, mutations and subscriptions <strong>src/graphql/**/*.js</strong></li><li>Do you want to generate/update all possible GraphQL operations — queries, mutations and subscriptions <strong>Yes</strong></li><li>Enter maximum statement depth [increase from default if your schema is deeply nested] <strong>2</strong></li></ul><p>Write down your <strong>GraphQL endpoint</strong> and <strong>API KEY</strong>.</p><p>This is the resulting architecture with our new GraphQL API managed by <strong>AWS AppSync</strong> and <strong>Amazon DynamoDB</strong>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aNf0mRhG8vfnEmHl2fYq5g.png" /></figure><p>Run the command below to access the <strong>AWS AppSync console</strong>.</p><pre>amplify console api</pre><ul><li>Please select from one of the below mentioned services <strong>GraphQL</strong></li></ul><h3>Amplify DataStore setup</h3><p>Run the command below to install the necessary dependencies:</p><pre>npm install --save @aws-amplify/core @aws-amplify/datastore</pre><h4>Data model generation</h4><p>Generate the data models to manage our messages for our <strong>ChattyAPI</strong>.</p><pre>amplify codegen models</pre><blockquote><em>Important: DO NOT forget to regenerate your models every time you introduce a change in your schema.</em></blockquote><p>After running this command, <strong>AWS Amplify CLI</strong> has generated the necessary data models in a new folder. The files in this folder hold your data model classes and schema.</p><pre>&lt;amplify-app&gt;<br>    |_ src<br>      |_ models</pre><h4>Creating a message</h4><p>Now that the GraphQL API and <strong>data models</strong> are created, we can begin using the <strong>DataStore API</strong>. The first thing we’ll do is create a new message passing the generated <strong>data model</strong> to save.</p><blockquote>Using data models allow us to be always compliant with the GraphQL schema and prevent errors right in the client.</blockquote><pre>import { DataStore } from &quot;@aws-amplify/datastore&quot;;<br>import { Chatty } from &quot;./models&quot;;</pre><pre>await DataStore.save(new Chatty({<br>  user: &quot;amplify-user&quot;,<br>  message: &quot;Hi everyone!&quot;,<br>  createdAt: new Date().toISOString()<br>}))</pre><p>This will create a record locally in your device and synchronise it in the background using the underlying <strong>GraphQL API</strong> when in online mode.</p><h4>Querying data</h4><p>Let’s see how we can query the data using Amplify DataStore. In order to query our <strong>data model</strong> we will use a query and a predicate to indicate that we want all records.</p><pre>import { DataStore, Predicates } from &quot;@aws-amplify/datastore&quot;;<br>import { Chatty } from &quot;./models&quot;;</pre><pre>const messages = await DataStore.query(Chatty, Predicates.ALL);</pre><p>This will return an array of messages that we can display in our UI. <strong>Predicates</strong> also support filters for common types like Strings, Numbers and Lists.</p><blockquote><em>Find all supported filters at </em><a href="https://aws-amplify.github.io/docs/js/datastore#query-with-predicates"><em>query with Predicates</em></a><em>.</em></blockquote><h3>Creating the UI with Vue</h3><p>Now, let’s look at how we can create the UI to create and display messages for Chatty chatroom.</p><pre>&lt;template&gt;<br>  &lt;div v-for=&quot;message of sorted&quot; :key=&quot;message.id&quot;&gt;<br>    &lt;div&gt;{{ message.user }} - {{ moment(message.createdAt).format(&#39;YYYY-MM-DD HH:mm:ss&#39;)}})&lt;/div&gt;<br>    &lt;div&gt;{{ message.message }}&lt;/div&gt;<br>  &lt;/div&gt;<br>&lt;/template&gt;<br>&lt;script&gt;<br>import { DataStore, Predicates } from &quot;@aws-amplify/datastore&quot;;<br>import { Chatty } from &quot;./models&quot;;<br>import moment from &quot;moment&quot;;</pre><pre>export default {<br>  name: &#39;app&#39;,<br>  data() {<br>    return {<br>      user: {},<br>      messages: [],<br>    }<br>  },<br>  computed: {<br>    sorted() {<br>      return [...this.messages].sort((a, b) =&gt; -a.createdAt.localeCompare(b.createdAt));<br>    }<br>  },<br>  created() {<br>    // authentication state managament<br>    onAuthUIStateChange((state, user) =&gt; {<br>      // set current user and load data after login<br>      switch (state) {<br>        case AuthState.SignedIn: {<br>          this.user = user;<br>          this.loadMessages();<br>          break;<br>        }<br>      }<br>    });<br>  },<br>  methods: {<br>    moment: () =&gt; moment(),<br>    loadMessages() {<br>      DataStore.query(Chatty, Predicates.ALL).then(messages =&gt; {<br>        this.messages = messages;<br>      });<br>    },<br>  }<br>}<br>&lt;/script&gt;</pre><p>After the user signs in, we call loadMessages. This fetches all the messages in our local store. We are sorting the list with a computed method sorted as we want our messages to show the most recent at the top. We are also using moment to format our time variables.</p><h4>Creating a message</h4><p>Now, let’s look at how we create new messages.</p><pre>&lt;template&gt;<br>  &lt;form v-on:submit.prevent&gt;<br>    &lt;input v-model=&quot;form.message&quot; placeholder=&quot;Enter your message...&quot; /&gt;<br>    &lt;button @click=&quot;sendMessage&quot;&gt;Send&lt;/button&gt;<br>  &lt;/form&gt;<br>&lt;/template&gt;<br>&lt;script&gt;<br>export default {<br>  data() {<br>    return {<br>      form: {},<br>    };<br>  }, <br>  methods: {<br>    sendMessage() {<br>      const { message } = this.form<br>      if (!message) return;<br>      DataStore.save(new Chatty({<br>        user: this.user.username,<br>        message: message,<br>        createdAt: new Date().toISOString()<br>      })).then(() =&gt; {<br>        this.form = { message: &#39;&#39; };<br>        this.loadMessages();<br>      }).catch(e =&gt; {<br>        console.log(&#39;error creating message...&#39;, e);<br>      });<br>    },<br>  }<br>}<br>&lt;/script&gt;</pre><p>We use a form to read the message from the user and call sendMessage with save passing the user and current date along with the message. Once the message has been created we reset the input field and reload all messages. Note how we use Amplify DataStore as our source of truth in this implementation.</p><h4>Deleting all messages</h4><p>One of the main advantages of working using Amplify DataStore is being able to run a series of GraphQL mutations without having to use a series of individual operations. See below how we can use delete together with a predicate to remove all messages.</p><pre>DataStore.delete(Chatty, Predicates.ALL).then(() =&gt; {<br>  console.log(&#39;messages deleted!&#39;);<br>});</pre><blockquote>When using Amplify DataStore records are never removed, but marked for removal. Records will then be automatically removed as defined in their <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html">TTL</a> attribute. At the time of writing, this is set to 30 days.</blockquote><h4>Real-time with GraphQL subscriptions</h4><p>Next, let’s see how we can create a GraphQL subscription. To do so, we will listen for changes of data in our API, and update the state whenever a new piece of data comes through. When the component is destroyed, we will unsubscribe to avoid memory leaks.</p><blockquote>As we are using Amplify DataStore, as our source of truth, we don’t need another copy of it at the app level so we just need to load the latest state with loadMessages.</blockquote><pre>&lt;script&gt;<br>export default {<br>  data() {<br>    return {<br>      subscription: undefined;<br>    };<br>  },<br>  created() {<br>    //Subscribe to changes<br>    this.subscription = DataStore.observe(Chatty).subscribe(msg =&gt; {<br>      console.log(msg.model, msg.opType, msg.element);<br>      this.loadMessages();<br>    });<br>  }, <br>  destroyed() {<br>    if (!this.subscription) return;<br>    this.subscription.unsubscribe();<br>  },<br>}<br>&lt;/script&gt;</pre><p>At this point, the chatroom is fully working including authentication flow and data synchronisation in real-time.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-OHzDfpbijDHrJG3lWtWnA.png" /><figcaption>Real-time synchronisation using Chrome and Firefox clients side-by-side.</figcaption></figure><p>On the other hand, we haven’t made much progress in making it work offline or having native-like features. In order to tick these boxes, we are going to make our app a <strong>PWA</strong>.</p><h3>Making Chatty a PWA</h3><p>The <a href="https://cli.vuejs.org/core-plugins/pwa.html#vue-cli-plugin-pwa">PWA CLI plugin</a> can help us making Chatty a PWA by running a single command:</p><pre>vue add @vue/pwa</pre><p>This will make few changes to the project and add a few new assets necessary to run the app as a PWA. The most important change happens in src/main.js where we are now registering a <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers"><strong>service worker</strong></a><strong> </strong>that will allow Chatty to work offline.</p><p>Using the default settings, the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers"><strong>service worker</strong></a> is configured to pre-cache all the assets resulting from the build (js, css and public folder). Using this setup, the browser can access the cache to load the app while offline. See the diagram below:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5jxEUoFpn8iE-vPAD0-YbA.png" /><figcaption>Service worker serving assets from the cache while offline</figcaption></figure><blockquote>Learn more about service workers at <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers">using service workers</a>.</blockquote><p>Run the build command to see changes:</p><pre>yarn build</pre><p>In your dist folder you should find the following:</p><pre>└── dist<br>  ├── css<br>  │   └── app.&lt;version&gt;.css<br>  ├── img/icons<br>  │   ├── android-chrome-&lt;size&gt;.png<br>  │   └── ...<br>  ├── js<br>  │   ├── app.&lt;version&gt;.png<br>  │   └── ...<br>  ├── favicon.ico<br>  ├── index.html<br>  ├── manifest.json<br>  ├── precache-manifest.&lt;version&gt;.json<br>  ├── robots.txt<br>  └── service-worker.js</pre><p>The index.html has been modified to include the <a href="https://developer.mozilla.org/en-US/docs/Web/Manifest">Web app manifest</a> manifest.json along with some meta tags and entries to support different devices and platforms. You can further customise these settings. The most important ismanifest.json/display set to standalone. This setting will give the app a look and feel like a native application for Desktop and Mobile. Learn about all the options available in <a href="https://developer.mozilla.org/en-US/docs/Web/Manifest">Web app manifest</a>.</p><p>Another important file is service-worker.js. This contains the implementation for the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers"><strong>service worker</strong></a> which determines the behaviour of the app while offline. As part of it, precache-manifest.&lt;version&gt;.json includes all files to be installed and pre-cached as part of the app. This will make the app load almost instantly as it won’t use the network. These files were created by the <a href="https://cli.vuejs.org/core-plugins/pwa.html#vue-cli-plugin-pwa">PWA CLI plugin</a> and include all the assets from your build.</p><p>Test the app running the following commands on a new terminal window:</p><pre>cd dist<br>python -m SimpleHTTPServer 8887  // open localhost:8887</pre><blockquote>Remember that in order to test the app you need to install the service worker first. This requires at least loading the app once.</blockquote><p>To test the app while offline you can use the <strong>Developer Tools</strong> or switch off your <strong>internet connection</strong>. See below a screen capture after refreshing the page while offline:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2W85dgMo77Tvr4phioyTeA.png" /><figcaption>Chatty app while offline.</figcaption></figure><p>As you can see in the screenshot above using Chrome, in the <strong>Network tab</strong>, the files are served by the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers"><strong>service worker</strong></a> while offline (in green). Unfortunately the default setup won’t include any custom assets like our <strong>SVG logo</strong> in the header (in red) or external fonts.</p><h3>Adding a PWA custom configuration</h3><p>Let’s fix the issue with our logo by using a <strong>custom configuration</strong>. Create vue.config.js with the following content at the root of your project:</p><pre>// vue.config.js<br>const manifest = require(&#39;./public/manifest.json&#39;)</pre><pre>module.exports = {<br>  pwa: {<br>    name: manifest.short_name,<br>    themeColor: manifest.theme_color,<br>    msTileColor: manifest.background_color,<br>    appleMobileWebAppCapable: &#39;yes&#39;,<br>    appleMobileWebAppStatusBarStyle: &#39;black&#39;,<br>    workboxPluginMode: &#39;InjectManifest&#39;,<br>    workboxOptions: {<br>      swSrc: &#39;src/service-worker.js&#39;,<br>    }<br>  }<br>}</pre><p>This file controls the <a href="https://cli.vuejs.org/core-plugins/pwa.html#vue-cli-plugin-pwa">PWA CLI plugin</a> and deal with settings in the <a href="https://developer.mozilla.org/en-US/docs/Web/Manifest">Web app manifest</a> and UX for different devices.</p><p>The custom configuration uses <a href="https://developers.google.com/web/tools/workbox">workbox</a> in injectManifest mode and points to the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers">service worker</a> implementation we want to use. Find all configuration options at the <a href="https://cli.vuejs.org/core-plugins/pwa.html#configuration">official website</a>. Now create src/service-worker.js with the following code</p><pre>// src/service-worker.js<br>workbox.core.setCacheNameDetails({ prefix: &#39;amplify-datastore&#39; })</pre><pre>workbox.core.skipWaiting()<br>workbox.core.clientsClaim()</pre><pre>const cacheFiles = [{<br> &quot;revision&quot;: &quot;e653ab4d124bf16b5232&quot;,<br> &quot;url&quot;: &quot;<a href="https://aws-amplify.github.io/img/amplify.svg">https://aws-amplify.github.io/img/amplify.svg</a>&quot;<br>}]</pre><pre>self.__precacheManifest = cacheFiles.concat(self.__precacheManifest || [])<br>workbox.precaching.precacheAndRoute(self.__precacheManifest, {})</pre><p>For our <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers"><strong>service worker</strong></a>, we are setting a prefix for our cache to easily find our files while using the <strong>Developer Tools</strong>. We are also setting the behaviour for new service worker versions. These will be applied immediately replacing any existing ones with skipWaiting and clientsClaim as explained <a href="https://developers.google.com/web/tools/workbox/modules/workbox-core#skip_waiting_and_clients_claim">here</a>. To fix our <strong>SVG issue</strong>, we are adding the url to the SVG file, to the <strong>pre-cached files</strong> defined in the <a href="https://developer.mozilla.org/en-US/docs/Web/Manifest">Web app manifest</a>.</p><h3>Improving UX while offline</h3><p>We are almost done. Our app can survive offline reloads, can store messages while offline and can synchronise when back online thanks to Amplify DataStore.</p><p>The only remaining issue now is <strong>improving the user experience</strong> as the user doesn’t know when the app is operating online or offline. This is not a great UX, as sometimes <strong>the user might inadvertently go offline</strong> and be confused as for not receiving any feedback or explanation from the app. We can fix this by using the code below:</p><pre>// &lt;div v-if=&quot;offline&quot;&gt;You are offline.&lt;/div&gt;<br>// &lt;div v-bind:class=&quot;{ offline: offline }&quot;&gt;</pre><pre>// App.vue<br>import { Hub } from &#39;aws-amplify&#39;;</pre><pre>export default {<br>  data() {<br>    return { offline: undefined };<br>  },<br>  created() {<br>    this.listener = Hub.listen(&#39;datastore&#39;, {payload:{event}} =&gt; {<br>      if (event === &#39;networkStatus&#39;) {<br>        this.offline = !data.active;<br>      }<br>    })<br>  }<br>}</pre><p>We are using the <a href="https://docs.amplify.aws/lib/utilities/hub/q/platform/js"><strong>Amplify Hub</strong></a> to detect <strong>network changes</strong> and use it to set the offline flag. Once in place, we can use it to display messages or style the UI accordingly as shown at the beginning of the code above. We are now ready to publish <strong>Chatty</strong> to the cloud and test it using different devices.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/472/1*eIii-RnmoTL486dsT1dzNA.png" /><figcaption>Chatty PWA informing the user of changes in the network status.</figcaption></figure><h3>Publishing your app via the AWS Amplify Console</h3><p>The first thing you need to do is <strong>create a new repo</strong> for this project. Once you’ve created the repo, copy the <strong>URL</strong> for the project to the clipboard and initialise git in your local project:</p><pre>git init<br>git remote add origin <a href="/service/mailto:repo@repoofyourchoice.com">repo@repoofyourchoice.com</a>:username/project-name.git<br>git add .git commit -m &#39;initial commit&#39;git push origin master</pre><p>Next visit the <a href="https://aws.amazon.com/amplify/console/"><strong>AWS Amplify Console</strong></a> in your <strong>AWS account</strong>. Click <strong>Get Started </strong>to create a new deployment. Next, authorise your repository provider as the repository service. Next, choose the new repository and branch for the project you just created and click <strong>Next</strong>. In the next screen, create a new role and use this role to allow the <strong>AWS Amplify Console</strong> to deploy these resources and click <strong>Next</strong>. Finally, click <strong>Save</strong> and <strong>Deploy</strong> to deploy your application!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*DT15Us8PZ13wdHD2.png" /><figcaption>AWS Amplify Console deployment steps.</figcaption></figure><p>This will generate a public url that uses <strong>HTTPS</strong>, which is a requirement for <strong>PWAs.</strong> Congratulations! You can now test it in your browser, Desktop and Mobile.</p><h3>Installing the Chatty app in the Desktop and Mobile</h3><p>Due to the inclusion of the <a href="https://developer.mozilla.org/en-US/docs/Web/Manifest">Web app manifest</a> in our index.html page, you can now install the <strong>Chatty</strong> app in the Desktop and Mobile devices in Windows, Mac and Linux. The way it works, changes slightly depending the device and operating system you are using. Try it out following the steps in <a href="https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Add_to_home_screen">Add to Home screen</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/978/1*whmy0GeYOcL_31-R1-EEZg.png" /><figcaption>Use add to Home screen to install in Desktop and Mobile.</figcaption></figure><h3>Cleaning up cloud services</h3><p>If at any time, you would like to delete a service from your project and your <strong>AWS Account</strong>, you can do this by running:</p><pre>amplify delete</pre><h3>Conclusion</h3><p>Congratulations! You successfully built your first <strong>offline-first app </strong>using <strong>Vue</strong> and <strong>Amplify</strong>. You created a chatroom <strong>PWA</strong> that stores data on the device while offline and when online synchronises in real-time with other devices using <strong>Amplify DataStore, AWS AppSync</strong>, <strong>GraphQL</strong> and <strong>Amazon DynamoDB</strong>. Thanks for following this tutorial.</p><p>If you prefer, you can follow the instructions in this video to build the chatroom app.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2Fvideoseries%3Flist%3DPLQX6IPseabtTLo28GsWh0Db-o0uH4TfHo&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DCXeRQn62Ptw&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FCXeRQn62Ptw%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/23b1a303a95bff9ab82a2d445a6198ef/href">https://medium.com/media/23b1a303a95bff9ab82a2d445a6198ef/href</a></iframe><h3>Thanks for reading!</h3><p>Have you got any questions about this tutorial or <strong>AWS Amplify</strong>? Feel free to reach me anytime at <a href="https://twitter.com/intent/user?screen_name=gerardsans">@gerardsans</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/360/0*bwW0f85FxuW4esnl.jpeg" /></figure><blockquote><em>My Name is </em><a href="https://twitter.com/gerardsans"><em>Gerard Sans</em></a><em>. I am a Developer Advocate at </em><a href="https://aws.amazon.com/products/mobile"><em>AWS Mobile</em></a><em> working with </em><a href="https://aws-amplify.github.io/"><em>AWS Amplify</em></a><em> and </em><a href="https://aws.amazon.com/appsync/"><em>AWS AppSync</em></a><em> teams.</em></blockquote><blockquote><em>GraphQL is an open source data query and manipulation language for APIs, and a runtime for fulfilling queries with existing data.</em></blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HqG_GRsyMfjsyjuSLVfjgQ.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f9f7eec03c2d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Create a REST API integrated with Amazon DynamoDB using AWS Amplify and Vue]]></title>
            <link>https://gerard-sans.medium.com/create-a-rest-api-integrated-with-amazon-dynamodb-using-aws-amplify-and-vue-5be746e43c22?source=rss-9530b046d2ac------2</link>
            <guid isPermaLink="false">https://medium.com/p/5be746e43c22</guid>
            <category><![CDATA[dynamodb]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[api]]></category>
            <category><![CDATA[vuejs]]></category>
            <category><![CDATA[aws-amplify]]></category>
            <dc:creator><![CDATA[Gerard Sans]]></dc:creator>
            <pubDate>Fri, 25 Sep 2020 14:45:58 GMT</pubDate>
            <atom:updated>2020-09-25T15:47:45.032Z</atom:updated>
            <content:encoded><![CDATA[<p>Refresh your REST APIs skills using AWS Amplify and Vue</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jHdpWisXsTmkE2JY3BFAxQ.png" /></figure><p>In this article you will create a <strong>REST API</strong> integrated with <strong>Amazon DynamoDB </strong>using <strong>AWS Amplify</strong> including <strong>CRUD operations</strong> and publication. Access to the REST API will allow both registered users and guests. In order to test it you will create a client including an authentication flow using <strong>Vue</strong>.</p><ul><li><a href="#a757">Setting up a new project with the <strong>Vue CLI</strong></a></li><li><a href="#8cb1">Creating a <strong>REST API</strong> with <strong>Amplify CLI</strong></a></li><li><a href="#ebe2">Creating a new <strong>REST API</strong></a></li><li><a href="#ca29">Implementing <strong>CRUD operations using Amazon DynamoDB</strong></a></li><li><a href="#a18d">Pushing your <strong>REST API</strong> to the cloud</a></li><li><a href="#93c3">Publishing your app via the <strong>AWS Amplify Console</strong></a></li><li><a href="#35d4">Cleaning up <strong>cloud services</strong></a></li></ul><p>Please let me know if you have any questions or want to learn more at <a href="https://twitter.com/intent/user?screen_name=gerardsans">@gerardsans</a>.</p><p>&gt; Final solution in <a href="https://github.com/gsans/amplify-rest-todos-ui-vue">GitHub</a>.</p><h3>Setting up a new project with the Vue CLI</h3><p>Before moving to the next section, please complete the steps described in “<a href="https://medium.com/@gerard.sans/build-your-first-full-stack-serverless-app-with-vue-and-aws-amplify-9ed7ef9e9926">Build your first full-stack serverless app with Vue</a>”. Here you will set up the initial project, familiarise with <strong>Amplify CLI</strong> and add an authorisation flow so users can register themselves via an automated verification code sent to their email and login.</p><h3>Creating a REST API with Amplify CLI</h3><p>The <strong>Amplify CLI</strong> provides a guided workflow to easily add, develop, <a href="https://docs.amplify.aws/cli/restapi/testing">test</a> and manage REST APIs to access your AWS resources from your web and mobile applications.</p><p>A REST API or <strong>HTTP endpoint</strong> will be composed by one or more paths. Eg: /todos. Each path will use a <strong>Lambda function</strong> to handle <strong>HTTP requests</strong> and responses. Amplify CLI creates a single resource in <strong>Amazon API Gateway</strong> so you can handle all routes, <strong>HTTP Methods</strong> and <strong>paths</strong>, with a single Lambda function via a <a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html"><strong>Lambda Proxy integration</strong></a>. HTTP proxy integrations forward all requests and responses directly through to your <strong>HTTP endpoint</strong>. Eg: /todos.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LzW0P96lcw0ipzfprH_WEw.png" /><figcaption>Architecture diagram for the Todo App</figcaption></figure><h3>Creating a new REST API</h3><p>In this post, you are going to create a <strong>REST API</strong> to service a todo app with a single endpoint /todos using <strong>Amazon DynamoDB</strong> as a data source. To create it, use the following command:</p><pre>amplify add api</pre><p>Answer the following questions</p><ul><li>Please select from one of the below mentioned services: <strong>REST</strong></li><li>Provide a friendly name for your resource to be used as a label for this category in the project: <strong>todosApi</strong></li><li>Provide a path (e.g., /book/{isbn}): <strong>/todos</strong></li></ul><p>This will be the configuration for /todos path in <strong>Amazon API Gateway</strong>:</p><pre>/                        <br> |_ /todos        Main resource. Eg: /todos<br>    ANY           Methods: DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT<br>    OPTIONS       Allow pre-flight requests in CORS by browser<br>    |_ /{proxy+}  Eg: /todos/, /todos/id<br>       ANY        Methods: DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT<br>       OPTIONS    Allow pre-flight requests in CORS by browser</pre><p>By default, <strong>Amplify CLI</strong> creates a greedy path variable /todos/{proxy+} that catches all child resources for a path and forwards them to your Lambda. This will match all child routes including /todos/id.</p><ul><li>Choose a Lambda source <strong>Create a new Lambda function</strong></li><li>Provide a friendly name for your resource to be used as a label for this category in the project: <strong>todosLambda</strong></li><li>Provide the AWS Lambda function name: <strong>todosLambda</strong></li><li>Choose the runtime that you want to use: <strong>NodeJS</strong></li><li>Choose the function template that you want to use: <strong>CRUD function for Amazon DynamoDB</strong></li></ul><p>The Lambda function template, <strong>CRUD function for Amazon DynamoDB</strong> implements route handlers for GET, POST, PUT and DELETE Http Methods and paths for /todos and /todos/*. Some possible routes examples include:</p><pre>GET /todos         List all todos<br>GET /todos/1       Load a todo by id<br>POST /todos        Create a todo<br>PUT /todos         Update a todo<br>DELETE /todos/1    Delete a todo by id</pre><ul><li>Do you want to access other resources in this project from your Lambda function? <strong>No</strong></li><li>Do you want to invoke this function on a recurring schedule? <strong>No</strong></li><li>Do you want to configure Lambda layers for this function? <strong>No</strong></li><li>Do you want to edit the local lambda function now? <strong>Yes</strong></li></ul><blockquote><em>We are going to change this template later but it’s good that you have it open as you follow the next steps.</em></blockquote><ul><li>Press enter to continue</li><li>Restrict API access <strong>Yes</strong></li><li>Who should have access? <strong>Authenticated and Guest users</strong></li><li>What kind of access do you want for Authenticated users? <strong>create, read, update, delete</strong></li><li>What kind of access do you want for Guest users? <strong>read</strong></li></ul><blockquote>Amplify CLI restricts API access combining <strong>Amazon Cognito</strong> for authentication and <strong>AWS IAM</strong> (Identity and Access Management) for granting execution permissions on routes.</blockquote><ul><li>Do you want to add another path? <strong>No</strong></li></ul><p>That’s all! Before we publish to the cloud though, let’s see how to change the default template to implement <strong>create</strong>, <strong>read</strong>, <strong>update</strong> and <strong>delete</strong> operations for your todo app.</p><h3>Implementing CRUD operations with Amazon DynamoDB</h3><p>In order to manage your todo app you want to implement all <strong>CRUD operations</strong>, these are: create, read, update and delete. The template we picked in the last section uses <a href="https://github.com/awslabs/aws-serverless-express"><strong>AWS Serverless Express</strong></a>. <strong>Amazon API Gateway</strong> will proxy incoming requests to your <strong>todosLambda</strong>.</p><p>For the implementation, you need to add <strong>route handlers</strong> to match all HTTP methods and paths you want to support. The first to match with an incoming request will be then executed. This will be in the same order as you have define them. If there’s no match an error will be returned.</p><p>See below, how different <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods">HTTP methods</a> and operations match route definitions in <strong>AWS Serverless Express</strong> and <a href="https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/dynamodb-example-document-client.html"><strong>DynamoDB Document Client</strong></a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*uBlBjgAr0PlvXzSgQjzRIw.png" /><figcaption>REST API mapping between HTTP requests, AWS Serverless Express and Document Client calls.</figcaption></figure><p>Before we start, you need to install a library to generate the ids for new todos. To install this dependency run the following commands from the root of your project:</p><pre>cd /amplify/backend/function/todosLambda/src<br>npm i --save uuid</pre><p>Open /amplify/backend/function/todosLambda/src/app.js and replace its content for:</p><pre><strong>const AWS = require(&#39;aws-sdk&#39;)</strong></pre><pre>var awsServerlessExpressMiddleware = require(&#39;aws-serverless-express/middleware&#39;)<br>var bodyParser = require(&#39;body-parser&#39;)<br>var express = require(&#39;express&#39;)<br><strong>const { v4: uuidv4 } = require(&#39;uuid&#39;)</strong></pre><pre>AWS.config.update({ region: process.env.TABLE_REGION });<br><strong>const dynamodb = new AWS.DynamoDB.DocumentClient();</strong></pre><pre>let tableName = &quot;todosTable&quot;;<br>if (process.env.ENV &amp;&amp; process.env.ENV !== &quot;NONE&quot;) {<br>  tableName = tableName + &#39;-&#39; + process.env.ENV;<br>}</pre><pre>var app = express()<br>app.use(bodyParser.json())<br>app.use(awsServerlessExpressMiddleware.eventContext())</pre><pre>app.use(function (request, response, next) {<br>  response.header(&quot;Access-Control-Allow-Origin&quot;, &quot;*&quot;)<br>  response.header(&quot;Access-Control-Allow-Headers&quot;, &quot;Origin, X-Requested-With, Content-Type, Accept&quot;)<br>  next()<br>});</pre><p>This is the same code from the default template adding the <a href="https://github.com/uuidjs/uuid"><strong>uuid</strong></a> library. This takes care of initialising <strong>DynamoDB Document Client</strong> API to interact with DynamoDB, the DynamoDB table name taking into account the <a href="https://docs.amplify.aws/cli/teams/overview">current environment</a> and enabling <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS">CORS headers</a>.</p><p>Let’s handle the first route, we will use the <strong>HTTP Method</strong> and path by the title for reference as in the next section. For each operation, first we will include the code from the client; and then, followed by the code serving it in the <strong>todosLambda</strong>.</p><h4>Fetching todos (GET, /todos)</h4><p>In the client, we use the <strong>Amplify JavaScript library</strong> aws-amplify to consume the <strong>REST API</strong>. In order to fetch the todos useAPI.get with the todosApi followed by the path /todos and an empty payload. The result is an array with the todos as part of the body. Remember to use JSON.parse as the result.body needs to be in plain text due to <strong>HTTP transport</strong>. The result object also contains the statusCode and path as url.</p><pre>// client request: fetching todos<br>import { API } from &#39;aws-amplify&#39;;</pre><pre><strong>API.get</strong>(&#39;todosApi&#39;, &#39;<strong>/todos</strong>&#39;, {}).then(result =&gt; {<br> this.todos = JSON.parse(<strong>result.body</strong>);<br>}).catch(err =&gt; {<br> console.log(err);<br>})</pre><p>Let’s look at the code in todosLambda. To fetch todos, map a handler function to the <strong>GET Method</strong> and the /todos path. Then run a dynamodb.scan operation. This fetches all records in the table specified. Limit the results to 100 items. Find more details in the <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.03.html"><strong>Developer Guide</strong></a> from Amazon DynamoDB.</p><blockquote>Scan returns all the data in a table so you may consider to change it for a query if you expect more than just few records.</blockquote><pre>// todosLambda route handler: fetching todos</pre><pre>app.get(&quot;<strong>/todos</strong>&quot;, function (request, response) {<br>  let params = {<br>    TableName: tableName,<br>    <strong>limit: 100</strong><br>  }<br>  <strong>dynamodb.scan</strong>(params, (error, result) =&gt; {<br>    if (error) {<br>      response.json({ statusCode: 500, error: error.message });<br>    } else {<br>      response.json({ statusCode: 200, url: request.url, body: JSON.stringify(<strong>result.Items</strong>) })<br>    }<br>  });<br>});</pre><p>This returns the todos array as part of the body. Don’t forget to use JSON.stringifyas it needs to be in plain text due to <strong>HTTP transport</strong>.</p><p>Once the operation finishes, check for errors and create a <strong>JSON response</strong> accordingly. You will use the same approach in the rest of operations. Just note the highlighted parts on the code for important changes.</p><h4>Fetching a todo by id (GET, /todos/:id)</h4><p>Let’s quickly see the code necessary on the client below.</p><pre>// client request: fetching a todo by id</pre><pre>import { API } from &#39;aws-amplify&#39;;</pre><pre><strong>API.get</strong>(&#39;todosApi&#39;, `<strong>/todos/${id}</strong>`, {}).then((result) =&gt; {<br>  this.todo = JSON.parse(<strong>result.body</strong>);<br>}).catch(err =&gt; {<br>  console.log(err);<br>})</pre><p>Notice how to use API.get with a path using a template string generating the path. Eg: `/todos/${id}` becomes &quot;/todos/c71f0be2–607d-48bc-b721–4cb77c90a58f&quot;. The result receives the todo details.</p><p>Let’s see how to get the details from a single todo in <strong>todosLambda</strong>. In order to capture the todo id<strong> </strong>use <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/routes?#Route_parameters">route parameters</a>, a feature from <strong>AWS Serverless Express</strong>. Route parameters use a semicolon to capture values at specific position in the URL like in /users/<strong>:userId</strong>/books/<strong>:bookId</strong>. Values are then available in the request object as request.params.userId and request.params.bookId.</p><pre>// todosLambda route handler: fetching a todo by id</pre><pre>app.get(&quot;<strong>/todos/:id</strong>&quot;, function (request, response) {<br>  let params = {<br>    TableName: tableName,<br>    Key: {<br>      id: <strong>request.params.id</strong><br>    }<br>  }<br>  <strong>dynamodb.get</strong>(params, (error, result) =&gt; {<br>    if (error) {<br>      response.json({ statusCode: 500, error: error.message });<br>    } else {<br>      response.json({ statusCode: 200, url: request.url, body: JSON.stringify(<strong>result.Item</strong>) })<br>    }<br>  });<br>});</pre><p>As in the code above, use dynamodb.get to set your table and partition key Key.id from the request parameters.</p><blockquote>For todosApi we only have a partition key, if you have a composed key (partition key + sort key) include the sort key too as part of the Key.sk.</blockquote><h4>Creating a new todo (POST, /todos)</h4><p>In order to create a new todo, use API.post and set the payload to include the new todo description text within the request body.</p><pre>// client request: creating a new todo</pre><pre>import { API } from &#39;aws-amplify&#39;;</pre><pre><strong>API.post</strong>(&#39;todosApi&#39;, &#39;<strong>/todos</strong>&#39;, {<br><strong>  body: {<br>    text: &quot;todo-1&quot;<br>  }</strong><br>}).then(result =&gt; {<br>  this.todo = JSON.parse(<strong>result.body</strong>);<br>}).catch(err =&gt; {<br>  console.log(err);<br>})</pre><p>In <strong>todosLambda</strong>, creating a new todo is a bit more elaborated as we need to provide some new attributes and values. As we saw in the code above, the request.bodycontains the description for the new todo: text. Generate a new id, set complete to false, addcreatedAtand updatedAt timestamps and include the userId. To create the todo use dynamodb.put.</p><pre>// todosLambda route handler: creating a new todo</pre><pre>app.post(&quot;/todos&quot;, function (request, response) {<br>  <strong>const timestamp = new Date().toISOString();</strong><br>  let params = {<br>    TableName: tableName,<br>    Item: {<br>      ...request.body,<br>      <strong>id: uuidv4()</strong>,               // auto-generate id<br>      complete: false,            // default for new todos<br>      createdAt: timestamp,<br>      updatedAt: timestamp,<br>      <strong>userId: getUserId(request)</strong>  // userId from request<br>    }<br>  }</pre><pre><strong>  dynamodb.put</strong>(params, (error, result) =&gt; {<br>    if (error) {<br>      response.json({ statusCode: 500, error: error.message, url: request.url });<br>    } else {<br>      response.json({ statusCode: 200, url: request.url, body: JSON.stringify(<strong>params.Item</strong>) })<br>    }<br>  });<br>});</pre><p>The helper function getUserId below extracts the user id from <strong>Amazon Cognito</strong>.</p><pre>// todosLambda route handler: helper function</pre><pre>const <strong>getUserId</strong> = (request) =&gt; {<br>  try {<br>    const reqContext = request.apiGateway.event.requestContext;<br>    const authProvider = reqContext.identity.cognitoAuthenticationProvider;<br>    return authProvider ? <strong>authProvider.split(&quot;:CognitoSignIn:&quot;).pop()</strong> : <strong>&quot;UNAUTH&quot;;</strong><br>  } catch (error) {<br>    <strong>return &quot;UNAUTH&quot;;</strong><br>  }<br>}</pre><p>This code tries to capture the user id from the request identity context and if unsuccessful, returns an unauthorised token with UNAUTH as the value.</p><h4>Updating a todo (PUT, /todos)</h4><p>At this point you should know how to use the <strong>Amplify API</strong>. In order to update a todo use API.put and the /todos path. As you did creating a new todo provide the todo changes including its id as part of the body. As in the code below, change both the description and the complete values. The result contains any fields that were changed and their new values.</p><pre>// client request: updating a todo</pre><pre>import { API } from &#39;aws-amplify&#39;;</pre><pre><strong>API.put</strong>(&#39;todosApi&#39;, `<strong>/todos</strong>`, { <br><strong>  body: {<br>    id: id,<br>    text: &quot;todo-2&quot;,<br>    complete: true<br>  }</strong><br>}).then(result =&gt; {<br>  this.todo = JSON.parse(<strong>result.body</strong>);<br>}).catch(err =&gt; {<br>  console.log(err);<br>})</pre><p>The update in <strong>todosLambda</strong> uses most of the code you are already familiar but including a new <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.03.html">update expression</a>. This expression includes optional attributes so we need to create it dynamically. Eg: to service a request changing only the description text but not the other attributes. We used UPDATED_NEW to return only the updated attributes in <strong>DynamoDB</strong> but if you need all attributes use ALL_NEW.</p><pre>// todosLambda route handler: updating a todo</pre><pre>app.put(&quot;<strong>/todos</strong>&quot;, function (request, response) {<br>  <strong>const timestamp = new Date().toISOString();</strong><br>  const params = {<br>    TableName: tableName,<br>    Key: {<br>      <strong>id: request.body.id,</strong><br>    },<br>    ExpressionAttributeNames: { &#39;#text&#39;: &#39;text&#39; },<br>    ExpressionAttributeValues: {},<br>    <strong>ReturnValues: &#39;UPDATED_NEW&#39;,</strong><br>  };<br>  <strong>params.UpdateExpression = &#39;SET &#39;;</strong><br>  if (request.body.text) {<br>    params.ExpressionAttributeValues[&#39;:text&#39;] = request.body.text;<br>    params.UpdateExpression += &#39;#text = :text, &#39;;<br>  }<br>  if (request.body.complete) {<br>    params.ExpressionAttributeValues[&#39;:complete&#39;] = request.body.complete;<br>    params.UpdateExpression += &#39;complete = :complete, &#39;;<br>  }<br>  if (request.body.text || request.body.complete) {<br>    params.ExpressionAttributeValues[&#39;:updatedAt&#39;] = timestamp;<br>    params.UpdateExpression += &#39;updatedAt = :updatedAt&#39;;<br>  }<br>  <strong>dynamodb.update</strong>(params, (error, result) =&gt; {<br>    if (error) {<br>      response.json({ statusCode: 500, error: error.message, url: request.url });<br>    } else {<br>      response.json({ statusCode: 200, url: request.url, body: JSON.stringify(<strong>result.Attributes</strong>) })<br>    }<br>  });<br>});</pre><blockquote>To keep the semantics of HTTP PUT use the todo id from request.body.id instead of the request.params.id.</blockquote><h4>Deleting a todo by id (DELETE, /todos/:id)</h4><p>Let’s implement the request to delete a todo. On the client, use API.del with a path including the id as a <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/routes?#Route_parameters">route parameter</a>. If successful, the result body will be {} with statusCode:200.</p><pre>// client request: deleting a todo by id</pre><pre>import { API } from &#39;aws-amplify&#39;;</pre><pre><strong>API.del</strong>(&#39;todosApi&#39;, `<strong>/todos/${id}</strong>`, {}).then(result =&gt; {<br>  console.log(result);<br>}).catch(err =&gt; {<br>  console.log(err);<br>})</pre><p>In <strong>todosLambda</strong>, use the same techniques from the previous route handlers now using dynamodb.delete operation.</p><pre>// todosLambda route handler: deleting a todo by id</pre><pre>app.delete(&quot;<strong>/todos/:id</strong>&quot;, function (request, response) {<br>  let params = {<br>    TableName: tableName,<br>    Key: {<br>      <strong>id: request.params.id</strong><br>    }<br>  }<br>  <strong>dynamodb.delete</strong>(params, (error, result) =&gt; {<br>    if (error) {<br>      response.json({ statusCode: 500, error: error.message, url: request.url });<br>    } else {<br>      response.json({ statusCode: 200, url: request.url, body: JSON.stringify(<strong>result</strong>) })<br>    }<br>  });<br>});</pre><p>This completes all the CRUD operations. Before we can test it we need to publish it.</p><h3>Pushing your new REST API to the cloud</h3><p>Let’s deploy the new <strong>REST API</strong> in the cloud by running this command in the root of your project:</p><pre>amplify push</pre><p>At the end of this command you can take note of your new REST API url.</p><blockquote><em>REST APIs follow this pattern </em><a href="https://{restapi-id}.execute-api.{region}.amazonaws.com/%7Benvironment%7D/%7Bpath%7D."><em>https://</em></a><a href="https://{restapi-id}.execute-api.{region}.amazonaws.com/%7Benvironment%7D/%7Bpath%7D."><strong><em>{restapi-id}</em></strong></a><a href="https://{restapi-id}.execute-api.{region}.amazonaws.com/%7Benvironment%7D/%7Bpath%7D."><em>.execute-api.</em></a><a href="https://{restapi-id}.execute-api.{region}.amazonaws.com/%7Benvironment%7D/%7Bpath%7D."><strong><em>{region}</em></strong></a><a href="https://{restapi-id}.execute-api.{region}.amazonaws.com/%7Benvironment%7D/%7Bpath%7D."><em>.amazonaws.com/</em></a><a href="https://{restapi-id}.execute-api.{region}.amazonaws.com/%7Benvironment%7D/%7Bpath%7D."><strong><em>{environment}</em></strong></a><a href="https://{restapi-id}.execute-api.{region}.amazonaws.com/%7Benvironment%7D/%7Bpath%7D."><em>/</em></a><a href="https://{restapi-id}.execute-api.{region}.amazonaws.com/%7Benvironment%7D/%7Bpath%7D."><strong><em>{path}</em></strong><em>.</em></a></blockquote><p>Let’s see an overview of all the resources created by <strong>Amplify CLI</strong>.</p><pre>REST<br> |_ /todos (path)<br>    |_ todosApi (Amazon API Gateway) <br>       |_ todosLambda (AWS Lambda)<br>          |_ Logs (Amazon CloudWatch)</pre><p>We have covered all AWS Services but <strong>Amazon CloudWatch</strong>. This service will allow you to monitor usage and access to logs during development and testing.</p><h3>Publishing your app via the AWS Amplify Console</h3><p>The first thing you need to do is <strong>create a new repo</strong> for this project. Once you’ve created the repo, copy the URL for the project to the clipboard and initialise git in your local project:</p><pre>git init<br>git remote add origin <a href="/service/mailto:repo@repoofyourchoice.com">repo@repoofyourchoice.com</a>:username/project-name.git<br>git add .git commit -m &#39;initial commit&#39;git push origin master</pre><p>Next visit the <a href="https://aws.amazon.com/amplify/console/"><strong>AWS Amplify Console</strong></a> in your <strong>AWS account</strong>. Click <strong>Get Started </strong>to create a new deployment. Next, authorise your repository provider as the repository service. Next, choose the new repository and branch for the project you just created and click <strong>Next</strong>. In the next screen, create a new role and use this role to allow the <strong>AWS Amplify Console</strong> to deploy these resources and click <strong>Next</strong>. Finally, click <strong>Save</strong> and <strong>Deploy</strong> to deploy your application!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*0nNOE1I-LmwdwNQw.png" /><figcaption>AWS Amplify Console deployment steps.</figcaption></figure><h3>Cleaning up cloud services</h3><p>If at any time, you would like to delete the services from your project and your <strong>AWS Account</strong>, you can do this by running:</p><pre>amplify delete</pre><h3>Conclusion</h3><p>Congratulations! You successfully created a <strong>REST API </strong>using <strong>AWS Amplify</strong>, implemented all CRUD operations using <strong>Amazon DynamoDB </strong>and created a client to consume it <strong>restricting access to both registered users and guests</strong> using<strong> Vue</strong>. Thanks for following this tutorial.</p><p>If you prefer, you can also follow this video to achieve the same result.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2Fvideoseries%3Flist%3DPLQX6IPseabtTLo28GsWh0Db-o0uH4TfHo&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DhXL5z1TaqTk&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FhXL5z1TaqTk%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/729f2b6d5dfa3026b6759d2731bf11ff/href">https://medium.com/media/729f2b6d5dfa3026b6759d2731bf11ff/href</a></iframe><h3>Thanks for reading!</h3><p>Have you got any questions about this tutorial or <strong>AWS Amplify</strong>? Feel free to reach me anytime at <a href="https://twitter.com/intent/user?screen_name=gerardsans">@gerardsans</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*g3JXgwtV9b5B3lePTUG3ng.jpeg" /></figure><blockquote><em>My Name is </em><a href="https://twitter.com/gerardsans"><em>Gerard Sans</em></a><em>. I am a Developer Advocate at </em><a href="https://aws.amazon.com/products/mobile"><em>AWS Mobile</em></a><em> working with </em><a href="https://aws-amplify.github.io/"><em>AWS Amplify</em></a><em> and </em><a href="https://aws.amazon.com/appsync/"><em>AWS AppSync</em></a><em> teams.</em></blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HqG_GRsyMfjsyjuSLVfjgQ.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5be746e43c22" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Create a cloud-enabled GraphQL API with AWS Amplify and Vue]]></title>
            <link>https://gerard-sans.medium.com/create-a-cloud-enabled-graphql-api-with-aws-amplify-and-vue-99ec669d3bc5?source=rss-9530b046d2ac------2</link>
            <guid isPermaLink="false">https://medium.com/p/99ec669d3bc5</guid>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[graphql]]></category>
            <category><![CDATA[aws-amplify]]></category>
            <category><![CDATA[vuejs]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Gerard Sans]]></dc:creator>
            <pubDate>Tue, 22 Sep 2020 15:50:35 GMT</pubDate>
            <atom:updated>2020-09-25T15:45:03.116Z</atom:updated>
            <content:encoded><![CDATA[<p>Full-stack serverless made easy using AWS Amplify and Vue</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Z0LTXNIhY0CIzhEa-wDVsQ.png" /></figure><p>In this tutorial, we will learn how to build a GraphQL data-driven serverless app using <strong>Vue</strong>, <strong>AWS Amplify </strong>and<strong> AWS AppSync</strong>. We will create a new project with Vue, generate a serverless GraphQL API using <strong>AWS AppSync</strong> and build a client to consume it including real-time. We will cover:</p><ul><li><a href="#3ffe">Introduction to <strong>AWS AppSync</strong></a></li><li><a href="#abaa">Setting up a new project with the <strong>Vue CLI</strong></a></li><li><a href="#47da">Creating a new <strong>GraphQL API</strong></a> and <a href="#5b45">using your first <strong>GraphQL transform</strong></a></li><li><a href="#1e5b">Pushing your <strong>GraphQL API</strong> to the cloud</a></li><li>Building the <strong>client</strong>: adding <a href="#8759">queries</a>, <a href="#6c13">mutations</a> and <a href="#62d0">real-time</a></li><li><a href="#a118">Publishing your app via the <strong>AWS Amplify Console</strong></a></li><li><a href="#8d23">Cleaning up <strong>cloud services</strong></a></li></ul><blockquote><em>In order to follow this post you will need a basic knowledge of GraphQL. You can learn the basics following this tutorial at </em><a href="https://graphql.org/learn/"><em>graphql.org</em></a><em>.</em></blockquote><p>&gt; Final solution and step by step tutorial in <a href="https://github.com/gsans/fullstack-serverless-amplify-ui-vue">GitHub</a>.</p><p>Please let me know if you have any questions or want to learn more at <a href="https://twitter.com/intent/user?screen_name=gerardsans">@gerardsans</a>.</p><h3>Introduction to AWS AppSync</h3><p><strong>AWS AppSync </strong>allows you to create highly scalable serverless GraphQL data-driven mobile and web apps by providing an open source <strong>Amplify</strong> <strong>Framework </strong>(consisting of AWS AppSync Clients, GraphQL transforms and the CLI), integrations with multiple <strong>data sources</strong>, and the <strong>AWS AppSync console</strong>.</p><ul><li><strong>GraphQL client</strong>: client-side library to securely access data from your GraphQL API. Built-in support for real-time and offline/delta client synchronisation.</li><li><strong>Amplify CLI</strong>: set of commands, via theapi category, to automate the setup and provision of resources for AWS AppSync and Amazon API Gateway cloud services. Support for REST and GraphQL APIs.</li><li><strong>GraphQL Transforms</strong>: custom GraphQL schema directives that can be used in your GraphQL schema to enable custom workflows.</li><li><strong>Data sources</strong>: databases (Amazon DynamoDB for NoSQL, Amazon Aurora for RDBMS), searches (Amazon Elasticsearch Service), and AWS Lambda functions.</li></ul><p>By using AWS AppSync, teams can quickly create highly scalable serverless GraphQL data-driven apps for mobile and web while leaving the heavy lifting to the Amplify CLI.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*VZZC4W0cAnNKaMP3.png" /><figcaption>AWS AppSync data-driven apps architecture overview</figcaption></figure><h3>Setting up a new project with the Vue CLI</h3><p>Before moving to the next section, please complete the steps described in “<a href="https://medium.com/@gerard.sans/build-your-first-full-stack-serverless-app-with-vue-and-aws-amplify-9ed7ef9e9926">Build your first full-stack serverless app with Vue</a>”.</p><h3>Creating a new GraphQL API</h3><p>For this post we are going to create a GraphQL API to list our favourite restaurants. To create it, we will use the following command:</p><pre>amplify add api</pre><p>Answer the following questions</p><ul><li>Please select from one of the below mentioned services <strong>GraphQL</strong></li><li>Provide API name: <strong>RestaurantAPI</strong></li><li>Choose the default authorization type for the API <strong>API key</strong></li><li>Enter a description for the API key: <strong>(empty)</strong></li><li>After how many days from now the API key should expire (1–365): <strong>7</strong></li><li>Do you want to configure advanced settings for the GraphQL API <strong>No, I am done.</strong></li><li>Do you have an annotated GraphQL schema? <strong>No</strong></li><li>Choose a schema template: <strong>Single object with fields (e.g., “Todo” with ID, name, description)</strong></li><li>Do you want to edit the schema now? <strong>Yes</strong></li></ul><p>When prompted, replace the default schema with the following:</p><pre>type Restaurant <strong>@model</strong> {<br>  id: ID!<br>  name: String!<br>  description: String!<br>  city: String!<br>}</pre><p>You should be familiar with everything in the GraphQL schema above but for the @model directive. This is a GraphQL transform provided by AppSync.</p><h3>Using your first GraphQL transform</h3><p>GraphQL transforms allow AppSync to provide further customisation and support for common scenarios, so you don’t have to.</p><p>By adding@model to theRestauranttype we are telling the Amplify CLI runtime to create the resolvers to support queries, mutations and subscriptions in DynamoDB. Besides the regular CRUD operations, we are also getting some more advanced features like pagination and filtering that we are going to cover later.</p><p>Once we apply@model to a type we get access to these other transforms:</p><ul><li>@key to configure custom index structures in <strong>DynamoDB</strong></li><li>@searchable to enable searches using <strong>Amazon Elasticsearch </strong>Service</li><li>@connection to add relationships between types</li><li>@lambda to generate <strong>AWS Lambda</strong> resolvers</li><li>@auth to add fine grained multi-authorisation support</li><li>@versioned to add conflict resolution for offline scenarios</li></ul><p>Learn how to use each transform in detail from the <a href="https://docs.amplify.aws/cli/graphql-transformer/directives">official docs</a>.</p><blockquote><em>GraphQL Transforms are implemented using custom GraphQL schema directives as defined in the </em><a href="https://graphql.github.io/graphql-spec/draft/#sec-Language.Directives"><em>GraphQL specification</em></a><em>.</em></blockquote><h3>Pushing your GraphQL API to the cloud</h3><p>Let’s run the push command to create the GraphQL API and see the results of using the @model transform:</p><pre>amplify push</pre><ul><li>Are you sure you want to continue? <strong>Yes</strong></li><li>Do you want to generate code for your newly created GraphQL API <strong>Yes</strong></li><li>Choose the code generation language target <strong>javascript</strong></li><li>Enter the file name pattern of graphql queries, mutations and subscriptions <strong>src/graphql/**/*.js</strong></li><li>Do you want to generate/update all possible GraphQL operations — queries, mutations and subscriptions <strong>Yes</strong></li><li>Enter maximum statement depth [increase from default if your schema is deeply nested] <strong>2</strong></li></ul><p>Write down your <strong>GraphQL endpoint</strong> and <strong>API KEY</strong>.</p><p>Run the command below to access the <strong>AWS AppSync console</strong>.</p><pre>amplify console api</pre><ul><li>Please select from one of the below mentioned services <strong>GraphQL</strong></li></ul><h3>Testing your new GraphQL API</h3><p>Once in the AWS AppSync console, click on <strong>Queries</strong> on the left side. This will open an editor that we can use to edit and test GraphQL queries.</p><p>Execute the following mutation to create a new restaurant:</p><pre>mutation createRestaurant {<br>  createRestaurant(input: {<br>    name: &quot;Nobu&quot;<br>    description: &quot;Great Sushi&quot;<br>    city: &quot;New York&quot;<br>  }) {<br>    id name description city<br>  }<br>}</pre><p>Now, run this query to list the restaurant we just added:</p><pre>query listRestaurants {<br>  listRestaurants {<br>    items {<br>      id<br>      name<br>      description<br>      city<br>    }<br>  }<br>}</pre><p>Besides creating all common CRUD operations for your types, AWS AppSync also creates extra utility features like filters. Run this query to try using filters:</p><pre>query searchRestaurants {<br>  listRestaurants(filter: {<br>    city: {<br>      contains: &quot;New York&quot;<br>    }<br>  }) {<br>    items {<br>      id<br>      name<br>      description<br>      city<br>    }<br>  }<br>}</pre><p>AWS AppSync creates filters on GraphQL scalar types (ID, String, Int, Float, Boolean) for list operations like listRestaurants.</p><h3>Querying data with queries</h3><p>In the earlier sections, we made sure we had a working GraphQL API. On the client, we will start by displaying a list.</p><pre>&lt;template&gt;<br>  &lt;div v-for=&quot;restaurant of restaurants&quot; :key=&quot;restaurant.id&quot;&gt;<br>    {{restaurant.name}}<br>  &lt;/div&gt;<br>&lt;/template&gt;<br>&lt;script&gt;<br>import { API, graphqlOperation } from &#39;aws-amplify&#39;;<br>import { listRestaurants } from &#39;./graphql/queries&#39;;<br><br>export default {<br>  name: &#39;app&#39;,<br>  data() {<br>    return {<br>      restaurants: [],<br>    }<br>  },<br>  created() {<br>    this.getData();<br>  },<br>  methods: {<br>    async getData() {<br>      try {<br>        const response = await API.graphql(graphqlOperation(listRestaurants));<br>        this.restaurants = response.data.listRestaurants.items;<br>      }<br>      catch (error) {<br>        console.log(&#39;Error loading restaurants...&#39;, error);<br>      }<br>    },<br>  }<br>}<br>&lt;/script&gt;</pre><p>From the code above, we are using API.graphqlto run the listRestaurantsquery within getData. Queries were created by the Amplify CLI during the push command. This call returns a promise that we handle by using async/await and render the result using v-for.</p><p>You might be wondering why we used listRestaurants.items. This is because AWS AppSync created an intermediate type ModelRestaurantConnection. This is so we can handle pagination scenarios together withlimit and nextTokenparameters.</p><pre>listRestaurants(filter: ModelRestaurantFilterInput, limit: Int, nextToken: String): <strong>ModelRestaurantConnection</strong></pre><pre>type ModelRestaurantConnection {<br> items: [Restaurant]<br> nextToken: String<br>}</pre><h3>Creating data with mutations</h3><p>In order to add new restaurants, we are going to create a data entry using form to take the required user input and pass it forward to the <strong>createRestaurant</strong> mutation.</p><pre>&lt;template&gt;<br>  &lt;div&gt;<br>    &lt;form v-on:submit.prevent&gt;<br>      &lt;div&gt;<br>        &lt;label&gt;Name: &lt;/label&gt;<br>        &lt;input v-model=&#39;form.name&#39; class=&#39;input&#39; /&gt;<br>      &lt;/div&gt;<br>      ...<br>      &lt;button @click=&#39;createRestaurant&#39; class=&#39;button&#39;&gt;Create&lt;/button&gt;<br>    &lt;/form&gt;<br>  &lt;/div&gt;<br>&lt;/template&gt;<br>&lt;script&gt;<br>import { createRestaurant } from &#39;./graphql/mutations&#39;;<br><br>export default {<br>  name: &#39;app&#39;,<br>  data() {<br>    return {<br>      form: { },<br>    }<br>  },<br>  methods: {<br>    async createRestaurant() {<br>      const { name, description, city } = this.form<br>      if (!name || !description || !city) return;<br>    <br>      const restaurant = { name, description, city };<br>      try {<br>        const response = await API.graphql(graphqlOperation(createRestaurant, { input: restaurant }))<br>        console.log(&#39;Item created!&#39;)<br>        this.restaurants = [...this.restaurants, response.data.createRestaurant];<br>        this.form = { name: &#39;&#39;, description: &#39;&#39;, city: &#39;&#39; };<br>      } catch (error) {<br>        console.log(&#39;Error creating restaurant...&#39;, error)<br>      }<br>    },<br>  }<br>}<br>&lt;/script&gt;</pre><p>Note how AWS AppSync instead of passing each field as an argument created an input type CreateRestaurantInput which makes our client code simpler and convenient.</p><pre>type Mutation {<br> createRestaurant(input: <strong>CreateRestaurantInput</strong>!): Restaurant<br>}input <strong>CreateRestaurantInput</strong> {<br> id: ID<br> name: String!<br> description: String!<br> city: String!<br>}</pre><p>As we did before with queries, we are using async/await to run our mutation as we submit the form via onCreate. Once we get the result, we use the form data to update the list and clear the form inputs.</p><h3>Adding real-time with subscriptions</h3><p>To demonstrate real-time, we are going to use a subscription to update AppSync clients when new restaurants are added. AppSync clients will subscribe to listen for changes going through our GraphQL API. More specifically, restaurant creation mutations.</p><pre>import { onCreateRestaurant } from &#39;./graphql/subscriptions&#39;;<br><br>export default {<br>  name: &#39;app&#39;,<br>  created() {<br>    //Subscribe to changes<br>    API.graphql(graphqlOperation(onCreateRestaurant))<br>    .subscribe((sourceData) =&gt; {<br>      const newRestaurant = sourceData.value.data.onCreateRestaurant<br>      if (newRestaurant) {<br>        // skip our own mutations and duplicates<br>        if (this.restaurants.some(r =&gt; r.id == newRestaurant.id)) return;<br>        this.restaurants = [newRestaurant, ...this.restaurants];<br>      } <br>    });<br>  },<br>}</pre><p>We use createdto setup the subscription and immediately subscribe to start listening for notifications. Then for each notification, we will update our list of restaurants with changes.</p><h3>Publishing your app via the AWS Amplify Console</h3><p>The first thing you need to do is <strong>create a new repo</strong> for this project. Once you’ve created the repo, copy the URL for the project to the clipboard and initialise git in your local project:</p><pre>git init<br>git remote add origin <a href="/service/mailto:repo@repoofyourchoice.com">repo@repoofyourchoice.com</a>:username/project-name.git<br>git add .git commit -m &#39;initial commit&#39;git push origin master</pre><p>Next visit the <a href="https://aws.amazon.com/amplify/console/"><strong>AWS Amplify Console</strong></a> in your <strong>AWS account</strong>. Click <strong>Get Started </strong>to create a new deployment. Next, authorise your repository provider as the repository service. Next, choose the new repository and branch for the project you just created and click <strong>Next</strong>. In the next screen, create a new role and use this role to allow the <strong>AWS Amplify Console</strong> to deploy these resources and click <strong>Next</strong>. Finally, click <strong>Save</strong> and <strong>Deploy</strong> to deploy your application!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*fDb9ioULhBGsn-IW.png" /><figcaption>AWS Amplify Console deployment steps.</figcaption></figure><h3>Cleaning up cloud services</h3><p>If at any time, you would like to delete a service from your project and your <strong>AWS Account</strong>, you can do this by running:</p><pre>amplify delete</pre><h3>Conclusion</h3><p>Congratulations! You successfully built your first <strong>GraphQL API </strong>using <strong>Vue</strong> and <strong>AWS AppSync</strong>. Thanks for following this tutorial.</p><p>If you prefer, you can follow the instructions in this video to build the same app but deploying to <strong>Amazon Cloudfront</strong> and <strong>Amazon S3</strong>.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2Fvideoseries%3Flist%3DPLQX6IPseabtTLo28GsWh0Db-o0uH4TfHo&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DCAueVfEYn6s&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FCAueVfEYn6s%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/bcbb4bda9b42a357ecd616d7e74c06ea/href">https://medium.com/media/bcbb4bda9b42a357ecd616d7e74c06ea/href</a></iframe><h3>Thanks for reading!</h3><p>Have you got any questions about this tutorial or <strong>AWS Amplify</strong>? Feel free to reach me anytime at <a href="https://twitter.com/intent/user?screen_name=gerardsans">@gerardsans</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/360/1*lyJ6-Qcn58u3TrwTecEXsg.jpeg" /></figure><blockquote><em>My Name is </em><a href="https://twitter.com/gerardsans"><em>Gerard Sans</em></a><em>. I am a Developer Advocate at </em><a href="https://aws.amazon.com/products/mobile"><em>AWS Mobile</em></a><em> working with </em><a href="https://aws-amplify.github.io/"><em>AWS Amplify</em></a><em> and </em><a href="https://aws.amazon.com/appsync/"><em>AWS AppSync</em></a><em> teams.</em></blockquote><blockquote><em>GraphQL is an open source data query and manipulation language for APIs, and a runtime for fulfilling queries with existing data.</em></blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HqG_GRsyMfjsyjuSLVfjgQ.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=99ec669d3bc5" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Build your first full-stack serverless app with Vue and AWS Amplify]]></title>
            <link>https://gerard-sans.medium.com/build-your-first-full-stack-serverless-app-with-vue-and-aws-amplify-9ed7ef9e9926?source=rss-9530b046d2ac------2</link>
            <guid isPermaLink="false">https://medium.com/p/9ed7ef9e9926</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[aws-amplify]]></category>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[vuejs]]></category>
            <dc:creator><![CDATA[Gerard Sans]]></dc:creator>
            <pubDate>Mon, 14 Sep 2020 12:04:38 GMT</pubDate>
            <atom:updated>2020-09-14T12:08:20.757Z</atom:updated>
            <content:encoded><![CDATA[<p>Build flexible, scalable, and reliable apps with AWS Amplify</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*a2_qscA1yBWQdDpF81CN6g.png" /></figure><p>In this tutorial, you will learn how to build a full-stack serverless app using <strong>Vue</strong> and <strong>AWS Amplify</strong>. You will create a new project and add a full authorisation flow using the <strong>authenticator component</strong>. This includes:</p><ul><li><a href="https://medium.com/@gerard.sans/build-your-first-full-stack-serverless-app-with-angular-and-aws-amplify-d2e4716de9bd#2bda">Introduction to <strong>AWS Amplify</strong></a></li><li><a href="https://medium.com/@gerard.sans/build-your-first-full-stack-serverless-app-with-angular-and-aws-amplify-d2e4716de9bd#81ee">Setting up a new project with the <strong>Vue CLI</strong></a></li><li><a href="https://medium.com/@gerard.sans/build-your-first-full-stack-serverless-app-with-angular-and-aws-amplify-d2e4716de9bd#6268">Installing <strong>Amplify CLI</strong></a> and <a href="https://medium.com/@gerard.sans/build-your-first-full-stack-serverless-app-with-angular-and-aws-amplify-d2e4716de9bd#13cb">setting up your Amplify environment</a></li><li><a href="https://medium.com/@gerard.sans/build-your-first-full-stack-serverless-app-with-angular-and-aws-amplify-d2e4716de9bd#30fe">Adding <strong>authentication</strong></a><strong> </strong>and <a href="https://medium.com/@gerard.sans/build-your-first-full-stack-serverless-app-with-angular-and-aws-amplify-d2e4716de9bd#117f">pushing changes to the cloud</a></li><li><a href="https://medium.com/@gerard.sans/build-your-first-full-stack-serverless-app-with-angular-and-aws-amplify-d2e4716de9bd#66f0"><strong>Publishing</strong> your app</a></li><li><a href="https://medium.com/@gerard.sans/build-your-first-full-stack-serverless-app-with-angular-and-aws-amplify-d2e4716de9bd#bbbd">Cleaning up <strong>cloud services</strong></a></li></ul><p>Please let me know if you have any questions or want to learn more on the above at <a href="https://twitter.com/intent/user?screen_name=gerardsans">@gerardsans</a>.</p><h3>Introduction to AWS Amplify</h3><p><strong>Amplify</strong> makes developing, releasing and operating modern full-stack serverless apps easy and delightful. Mobile and frontend web developers are being supported throughout the app life cycle via an open source <strong>Amplify Framework</strong> (consisting of the Amplify libraries and Amplify CLI) and seamless integrations with <strong>AWS cloud services</strong>, and the <strong>AWS Amplify Console</strong>.</p><ul><li><strong>Amplify libraries</strong>: in this article we will be using aws-amplify and @aws-amplify/ui-vue.</li><li><strong>Amplify CLI</strong>: command line tool for configuring and integrating cloud services.</li><li><strong>UI components</strong>: authenticator, photo picker, photo album and chat bot.</li><li><strong>Cloud services</strong>: authentication, storage, analytics, notifications, AWS Lambda functions, REST and GraphQL APIs, predictions, chat bots and extended reality (AR/VR).</li><li><strong>Offline-first support</strong>: Amplify DataStore provides a programming model for leveraging shared and distributed data without writing additional code for data reconciliation between offline and online scenarios.</li></ul><p>By using AWS Amplify, teams can focus on development while the Amplify team enforces best patterns and practices throughout the AWS Amplify stack.</p><h3>Amplify CLI</h3><p>The <strong>Amplify CLI </strong>provides a set of commands to help with repetitive tasks and<strong> </strong>automating <strong>cloud service</strong> setup and provision.</p><p>Some commands will prompt questions and provide sensible defaults to assist you during its execution. These are some common tasks. Run:</p><ul><li>amplify init, to setup a new environment. Eg: dev, test, dist.</li><li>amplify push, to provision local resources to the cloud.</li><li>amplify status, to list local resources and their current status.</li></ul><blockquote><em>The </em><strong><em>Amplify CLI</em></strong><em> uses </em><strong><em>AWS CloudFormation</em></strong><em> to manage service configuration and resource provisioning via </em><strong><em>templates</em></strong><em>. This a declarative and atomic approach to configuration. Once a template is executed, it will either fail or succeed.</em></blockquote><h3>Setting up a new project with the Vue CLI</h3><p>To get started, create a new project using the <a href="https://cli.vuejs.org/">Vue CLI</a>. If you already have it, skip to the next step. If not, install it and create the app using:</p><pre>yarn global add @vue/cli<br>vue create amplify-app</pre><p>Navigate to the new directory and check everything checks out before continuing</p><pre>cd amplify-app<br>yarn serve</pre><h3>Prerequisites</h3><p>Before going forward make sure you have gone through the <a href="https://docs.amplify.aws/start/getting-started/installation/q/integration/vue">instructions in our docs</a> to sign up to your <strong>AWS Account </strong>and install and configure the<strong> Amplify CLI</strong>.</p><h3>Setting up your Amplify project</h3><p><strong>AWS Amplify</strong> allows you to create different environments to define your preferences and settings. For any new project you need to run the command below and answer as follows:</p><pre>amplify init</pre><ul><li>Enter a name for the project: <strong>amplify-app</strong></li><li>Enter a name for the environment: <strong>dev</strong></li><li>Choose your default editor: <strong>Visual Studio Code</strong></li><li>Please choose the type of app that you’re building <strong>javascript</strong></li><li>What javascript framework are you using <strong>vue</strong></li><li>Source Directory Path: <strong>src</strong></li><li>Distribution Directory Path: <strong>dist</strong></li><li>Build Command: <strong>npm run-script build</strong></li><li>Start Command: <strong>npm run-script serve</strong></li><li>Do you want to use an AWS profile? <strong>Yes</strong></li><li>Please choose the profile you want to use <strong>default</strong></li></ul><p>At this point, the <strong>Amplify CLI</strong> has initialised a new project and a new folder: <strong>amplify</strong>. The files in this folder hold your project configuration.</p><pre>&lt;amplify-app&gt;<br>    |_ amplify<br>      |_ .config<br>      |_ #current-cloud-backend<br>      |_ backend<br>      team-provider-info.json</pre><h3>Installing the AWS Amplify dependencies</h3><p>Install the required dependencies for <strong>AWS Amplify</strong> and <strong>Vue</strong> using:</p><pre>yarn add aws-amplify @aws-amplify/ui-vue</pre><h3>Adding authentication</h3><p><strong>AWS Amplify</strong> provides authentication via the auth category which gives us access to <strong>AWS Cognito</strong>. To add authentication use the following command:</p><pre>amplify add auth</pre><p>When prompted choose:</p><ul><li>Do you want to use default authentication and security configuration?: <strong>Default configuration</strong></li><li>How do you want users to be able to sign in when using your Cognito User Pool?: <strong>Username</strong></li><li>Do you want to configure advanced settings? <strong>No</strong></li></ul><h3>Pushing changes to the cloud</h3><p>By running the push command, the cloud resources will be provisioned and created in your <strong>AWS account</strong>.</p><pre>amplify push</pre><p>To quickly check your newly created <strong>Cognito User Pool</strong> you can run</p><pre>amplify status</pre><blockquote><em>To access the </em><strong><em>AWS Cognito Console</em></strong><em> at any time, go to the dashboard at </em><a href="https://console.aws.amazon.com/cognito/"><em>https://console.aws.amazon.com/cognito</em></a><em>. Also be sure that your region is set correctly.</em></blockquote><p>Your resources have been created and you can start using them!</p><h3>Configuring the Vue application</h3><p>Reference the auto-generated aws-exports.js file that is now in your src folder. To configure the app, open main.ts and add the following code below the last import:</p><pre>import Vue from &#39;vue&#39;<br>import App from &#39;./App.vue&#39;<br><br><strong>import Amplify from &#39;aws-amplify&#39;;<br>import &#39;@aws-amplify/ui-vue&#39;;<br>import aws_exports from &#39;./aws-exports&#39;;<br><br>Amplify.configure(aws_exports);</strong><br><br>Vue.config.productionTip = false<br><br>new Vue({<br>  render: h =&gt; h(App),<br>}).$mount(&#39;#app&#39;)</pre><h3>Using the Authenticator Component</h3><p><strong>AWS Amplify</strong> provides <strong>UI components</strong> that you can use in your app. Let’s add these components to the project</p><p>In order to use the <strong>authenticator component</strong> add it to src/App.vue:</p><pre>&lt;template&gt;<br>  &lt;div id=&quot;app&quot;&gt;<br>    <strong>&lt;amplify-authenticator&gt;<br>      </strong>&lt;div&gt;<br>        &lt;h1&gt;Hey, {{user.username}}!&lt;/h1&gt;<br>        &lt;amplify-sign-out&gt;&lt;/amplify-sign-out&gt;<br>      &lt;/div&gt;<strong><br>    &lt;/amplify-authenticator&gt;</strong><br>  &lt;/div&gt;<br>&lt;/template&gt;</pre><pre>&lt;script&gt;<br><strong>import { AuthState, onAuthUIStateChange } from &#39;@aws-amplify/ui-components&#39;</strong><br><br>export default {<br>  name: &#39;app&#39;,<br>  data() {<br>    return {<br>      <strong>user: { },</strong><br>    }<br>  },<br>  created() {<br>    // authentication state managament<br><strong>    onAuthUIStateChange((state, user) =&gt; {<br>    </strong>  // set current user and load data after login<br>      <strong>if (state === AuthState.SignedIn) {<br>        this.user = user;<br>      }<br>    })</strong><br>  }<br>}<br>&lt;/script&gt;</pre><p>You can run the app and see that an <strong>authentication flow</strong> has been added in front of your <strong>app</strong> <strong>component</strong>. This flow gives users the ability to sign up and sign in.</p><blockquote><em>To view any users that were created, go back to the </em><strong><em>Cognito Dashboard</em></strong><em> at </em><a href="https://console.aws.amazon.com/cognito/"><em>https://console.aws.amazon.com/cognito</em></a><em>. Also be sure that your region is set correctly.</em></blockquote><p>Alternatively you can also use:</p><pre>amplify console auth</pre><h3>Accessing User Data</h3><p>To access the user’s info using the Auth API. This will return a <strong>promise</strong>.</p><pre>import { Auth } from &#39;aws-amplify&#39;;</pre><pre>Auth.currentAuthenticatedUser().then(console.log)</pre><h3>Publishing your app</h3><p>To deploy and host your app on AWS, we can use the hosting category.</p><pre>amplify add hosting</pre><ul><li>Select the plugin module to execute: <strong>Amazon CloudFront and S3</strong></li><li>Select the environment setup: <strong>DEV</strong></li><li>hosting bucket name <strong>YOURBUCKETNAME</strong></li><li>index doc for the website <strong>index.html</strong></li><li>error doc for the website <strong>index.html</strong></li></ul><p>Now, everything is set up &amp; we can publish it:</p><pre>amplify publish</pre><h3>Cleaning up Services</h3><p>To wipe out all resources from your project and your <strong>AWS Account</strong>, you can do this by running:</p><pre>amplify delete</pre><h3>Conclusion</h3><p>Congratulations! You successfully built your first <strong>full-stack serverless app</strong> using <strong>Vue</strong> and <strong>AWS Amplify</strong>. Thanks for following this tutorial.</p><p>You have learnt how to provide an <strong>authentication flow</strong> using the <strong>authenticator component</strong> or via the <strong>service API</strong> and how to use <strong>Amplify CLI</strong> to execute common tasks including adding and removing services.</p><h3>Thanks for reading!</h3><p>Have you got any questions regarding this tutorial or <strong>AWS Amplify</strong>? Feel free to reach out to me anytime at <a href="https://twitter.com/intent/user?screen_name=gerardsans">@gerardsans</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/360/1*J9DNmPDsRts_0lMUliXwBw.jpeg" /></figure><blockquote>My Name is <a href="https://twitter.com/gerardsans">Gerard Sans</a>. I am a Developer Advocate at <a href="https://aws.amazon.com/products/mobile">AWS Mobile</a> working with <a href="https://aws-amplify.github.io/">AWS Amplify</a> and <a href="https://aws.amazon.com/appsync/">AWS AppSync</a> teams.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HqG_GRsyMfjsyjuSLVfjgQ.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9ed7ef9e9926" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>