<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Johnny Tordgeman</title>
    <description>The latest articles on Forem by Johnny Tordgeman (@pxjohnny).</description>
    <link>https://forem.com/pxjohnny</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F224740%2Feb309b79-356e-4c57-95e6-b9481926d586.jpeg</url>
      <title>Forem: Johnny Tordgeman</title>
      <link>https://forem.com/pxjohnny</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/pxjohnny"/>
    <language>en</language>
    <item>
      <title>Let’s Build a WebSockets Project With Rust and Yew 0.19</title>
      <dc:creator>Johnny Tordgeman</dc:creator>
      <pubDate>Mon, 14 Feb 2022 21:26:55 +0000</pubDate>
      <link>https://forem.com/pxjohnny/lets-build-a-websockets-project-with-rust-and-yew-019-11h6</link>
      <guid>https://forem.com/pxjohnny/lets-build-a-websockets-project-with-rust-and-yew-019-11h6</guid>
      <description>&lt;h4&gt;
  
  
  Cover Photo by &lt;a href="href="&gt;Mike Winkler&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/socket?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;Let me start by saying I’m a HUGE fan of Yew. Using the power and flexibility of Rust to build front-end components is something that I feel will only get bigger as the adaptation of WebAssembly grows. Recently, one of my side projects needed some WebSockets love. I figured this would be the perfect time to dive into Yew’s recently released 0.19 version, which introduced several significant changes to the framework (the removal of web-sys and its supported services (i.e. ConsoleService) and the introduction of &lt;em&gt;Functional Components,&lt;/em&gt; to name a few).&lt;/p&gt;

&lt;p&gt;As you might have guessed from the title already, we will build a chat app (such a cliche, I know, I’ll show myself out) using Yew, yew-router, yew-agent, and several other crates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F615%2F0%2AOZlexFCroqrP80FF.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F615%2F0%2AOZlexFCroqrP80FF.jpg" alt="YewChat"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;At least it’s got GIF support!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To give you a sense of what we are going to build, check out this lovely image:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F818%2F1%2ARbbAFl7MeYex63eTb9s0dQ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F818%2F1%2ARbbAFl7MeYex63eTb9s0dQ.gif" alt="YewChat"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🛑  Before moving forward make sure you have Rust and NodeJS installed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  🗿 The WebSocket Server
&lt;/h3&gt;

&lt;p&gt;To use WebSockets on the client-side you need a server capable of working with WebSockets (a shocker, I know). To keep this post a (somewhat) reasonable length, and for the sake of focusing on a single subject, we won’t be discussing the WebSockets server too much. In a nutshell: other than handling the incoming and outgoing connections, the server saves the incoming connections in an array called users. Every few seconds the server will compare the users array to the server’s current active connection list to verify that all the users in the list are in fact still connected.&lt;/p&gt;

&lt;p&gt;While you can go and build/use your own WebSockets server for our lovely chat app, the easier solution here will be to clone the NodeJS WebSocket server I used at &lt;a href="https://github.com/jtordgeman/SimpleWebsocketServer" rel="noopener noreferrer"&gt;https://github.com/jtordgeman/SimpleWebsocketServer&lt;/a&gt;. Once cloned, run npm i and then npm start and if all went well, you should now have a cute WebSockets server running locally on port 8080.&lt;/p&gt;
&lt;h3&gt;
  
  
  Time to Take Off 🚀
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Clone the starter project at &lt;a href="https://github.com/jtordgeman/YewChat" rel="noopener noreferrer"&gt;https://github.com/jtordgeman/YewChat&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Install the toolchain dependencies
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;The starter project is nothing but an empty project with wasm-pack and webpack already set up, so we can focus our attention to Yew&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;🛤 ️Routing&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Our app has three possible routes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;login— a simple page with a textbox and a button for a user to enter their nickname&lt;/li&gt;
&lt;li&gt;chat — The main page — has a list of users, the chat display, and a textbox to write stuff to the chat&lt;/li&gt;
&lt;li&gt;404 — If anyone tries to go to a page that doesn't exist — this catch-all page will show up in all its glory&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you are coming from React you probably know (and use) react-router-dom. Well, good news! yew-router is pretty much the exact same idea! yew-router handles the display of different pages (components) depending on the URL.&lt;/p&gt;

&lt;p&gt;So enough with the theory, let’s get busy:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new folder named &lt;strong&gt;components&lt;/strong&gt; under the &lt;strong&gt;src&lt;/strong&gt; folder. We will host all of our components here.&lt;/li&gt;
&lt;li&gt;Create three files under the newly created components folder: &lt;strong&gt;chat.rs&lt;/strong&gt; , &lt;strong&gt;login.rs&lt;/strong&gt; , &lt;strong&gt;mod.rs.&lt;/strong&gt; We will leave chat and login empty for now, in mod.rs add the following:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;At the top of &lt;strong&gt;lib.rs&lt;/strong&gt; , add the following use statements:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Note that &lt;strong&gt;Login&lt;/strong&gt; and &lt;strong&gt;Chat&lt;/strong&gt; will show as unresolved. We will fix that when we start dealing with components later on.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Thanks to yew-router we can use an enum to define our routes. We will add it to our &lt;strong&gt;lib.rs&lt;/strong&gt; as follows:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Pretty neat stuff! We annotate each entry with the URL it handles. Note that the 404 route uses an additional annotation: #[not_found] — this macro comes from the yew-router package and is basically what makes this route a catch-all route.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Next we need a way to translate the enum value of a route to an actual component. Add the following switch function just below the Route enum:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;To render our router (and in turn, the components it routes to) we will use &lt;strong&gt;a functional component.&lt;/strong&gt; But what is a functional component you may ask?
A functional component is a simplified version of the regular Yew component which can receive properties and determines the rendered content by returning HTML. In short — functional components are basically components that have been reduced to have only the view method.&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Last but not least, we need an entry point to our app — a function that the JavaScript can call in order to initiate our Yew app. Add the run_app function to lib.rs as follows:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;🔬So what do we have here?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Line 1&lt;/strong&gt; : Using the wasm_bindgen macro we expose the run_app function to JavaScript.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Line 3&lt;/strong&gt; : We initialize the wasm_logger crate. Using wasm_logger and the log crates we can write debug logs to the browser’s console.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Line 4&lt;/strong&gt; : We are passing our Main component (defined in the previous step) to the start_app method of yew, to — as you might have guessed — start the app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With the routing in place, let’s move on to creating our components.&lt;/p&gt;

&lt;h3&gt;
  
  
  🪅 &lt;strong&gt;️Components — Phase 1&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;For simplicity sake, our app will consist of two components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Login&lt;/strong&gt;  — a simple functional component to get the username and connect to the WebSockets server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chat&lt;/strong&gt;  — the main component of the app — shows the chat window, and a text area to write content to the chat.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When users browse to the &lt;strong&gt;Login&lt;/strong&gt; component they will type a username and click connect — that username then needs to pass down to the &lt;strong&gt;Chat&lt;/strong&gt; component and be used there to connect to the WebSocket server. To achieve that we will use a &lt;strong&gt;Context&lt;/strong&gt; (think of it as a global state of the app) that will hold the username for any component to use. The way we define a Context is as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Define a struct for the context and a type alias for it:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;In the main component, define a context using the use_state hook:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Lastly, let’s use the context by wrapping the main component HTML with a ContextProvider element which enables the child elements to actually use this context.&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;A ContextProvider element requires a context struct (User in our case) and a context object (ctx), that is set using the element’s context property.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;👁️&lt;/em&gt; Note: the child elements of a ContextProvider will re-render whenever the context changes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With the context in place, let’s build the &lt;strong&gt;Login&lt;/strong&gt; component!&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In &lt;strong&gt;components/login.rs&lt;/strong&gt; add the &lt;strong&gt;login&lt;/strong&gt; functional component:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Declare a use_state hook that will manage the state of the username the user typed in. When declaring a use_state hook we provide the default value (an empty String in our case), similarly to React’s use_state hook:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;To get a reference to the context (which as you might remember will hold the global state for the username), use the use_context hook:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;The Login component UI will contain an input element and a button. Whenever the input changes we need to update the local username variable. To connect between the UI element and username, we use a callback:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;🔬So what do we have here?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Line 7&lt;/strong&gt; : We clone the username state handler so we can later update it using its set method.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Line 9&lt;/strong&gt; : We create a Callback from the input element’s onchange event.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Line 10&lt;/strong&gt; : We get the target element (the element that fired the event) using the InputEvent’s target_unchecked_into method.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Line 11&lt;/strong&gt; : We update the username state with the new value that the input element currently holds using the element’s value method.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;🎉&lt;/em&gt; If you have ever done any JavaScript work with HTML elements then all of this should look pretty similar.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;The next callback we need to create is for the submit button. Once the username is typed, and the user clicks on the submit button — we need to save that username to the global context so that other components can use it if needed. Create the onclick callback as follows:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Lastly, let’s add the actual UI for this component using the html! macro:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;👀 A few callouts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The input element registers to the oninput callback. Every time the input changes — we call oninput and update the username state.&lt;/li&gt;
&lt;li&gt;We use the Link element from the yew_router crate to route the browser to the Chat route using the to property.&lt;/li&gt;
&lt;li&gt;The Link element contains a button element, which registers to the onclick callback which updates the global context with the value of username. In addition to that, the button also sets the disabled property to prevent the user from clicking it, unless username has a length of 2 characters or more.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that’s a wrap for the Login component 🎊. We now have a component that uses a Context in order to share its data (username in our case) with other components.&lt;/p&gt;

&lt;p&gt;Now we may be tempted to run ahead and create the chat component, but let’s stop for a minute and think about how the chat component even works…&lt;/p&gt;

&lt;h3&gt;
  
  
  👋 Hello WebSockets!
&lt;/h3&gt;

&lt;p&gt;At the heart of our chat application are WebSockets. WebSockets enable us to asynchronously send and receive messages between the server and the client without the need for constant polling from the client. This feature makes Websockets the perfect centerpiece for our chat app. Let’s go ahead and create a WebSocket service that will handle all the aspects of working with WebSockets in our app!&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new folder called &lt;strong&gt;services&lt;/strong&gt; under the &lt;strong&gt;src&lt;/strong&gt;  folder.&lt;/li&gt;
&lt;li&gt;Add a new file called &lt;strong&gt;mod.rs&lt;/strong&gt; inside &lt;strong&gt;services&lt;/strong&gt; with the following content:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Our Websocket service will handle the following:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Listen to incoming messages from the WebSocket server.&lt;/li&gt;
&lt;li&gt;Write messages to the WebSocket server.&lt;/li&gt;
&lt;li&gt;Communicate with other components using MPSC (Multi Producers Single Consumer) Channel (more on this soon 🤔)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add a new file called &lt;strong&gt;websocket.rs&lt;/strong&gt; inside the &lt;strong&gt;services&lt;/strong&gt; folder with the following content:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;😱 OMG there’s a lot going on here, let’s bite-size this whole thing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lines 6–8:&lt;/strong&gt; Creates the WebsocketService struct that holds a single property of type Sender. Sender allows us to asynchronously send messages on the channel that the receiver will later receive, in the order they are sent. Sender is cloneable, which means that every component that uses the service can clone it and use it to send messages back to the receiver, which as the name suggests — there can only be a single one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lines 11–46&lt;/strong&gt; : The new function initialize the service, similar to a constructor in other languages. The function does the following:
&lt;/li&gt;
&lt;li&gt;Connects to the WebSocket server (line 12)
&lt;/li&gt;
&lt;li&gt;Create the MPSC channel (line 16)
&lt;/li&gt;
&lt;li&gt;Spawns a new future (async task) on the current thread that will listen to the receiving end of the MPSC channel and write the received message to the WebSocket server. This is how components communicate with our service — by sending messages across the channel (lines 18–23).
&lt;/li&gt;
&lt;li&gt;Spawns another new future on the current thread to listen to the incoming messages from the WebSocket server and log them out(lines 25–43).
&lt;/li&gt;
&lt;li&gt;Finally, the function returns an instance of WebSocketService (Self) that holds the channel transmitter (in_tx).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s a handy diagram visualizing how everything connects:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F551%2F1%2ANrZlkCpS7Wj8Oiehxur4ig.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F551%2F1%2ANrZlkCpS7Wj8Oiehxur4ig.png" alt="Component/Service Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Awesome, with the WebSocket service behind us, let’s proceed with creating the actual chat component!&lt;/p&gt;

&lt;h3&gt;
  
  
  🪅 ️Components — Phase 2
&lt;/h3&gt;

&lt;p&gt;For our Chat component, we will use a regular (read not functional) component because we will make good use of its different lifecycle methods.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open up &lt;strong&gt;chat.rs&lt;/strong&gt; and add the following:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;👀 A few callouts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Msg enum holds the possible messages (read actions) our component can receive. Chat has two basic functionalities: either it handles a message received from the WebSocket server (HandleMsg), or it submits a message to the server (SubmitMessage) — for example when a user types something into the chat.&lt;/li&gt;
&lt;li&gt;MessageData represents a chat message, containing who is it from and what the actual message is.&lt;/li&gt;
&lt;li&gt;The MsgTypes enum holds the different types of messages the component can send or receive.&lt;/li&gt;
&lt;li&gt;Lastly, WebSocketMessage represents what a message to the WebSocket server looks like: it has a type (message_type) and then either an array of strings (such as in the case of the chat users list) or a single string (such as the case of sending a chat message to the server).&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Next, let’s add the Chat component itself:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The Chat components hold the user list (users), the input typed to the text box (chat_input), a reference to the Websocket service (wss), and finally, an array of all the messages typed to the chat (messages).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The first component lifecycle method we add is the create method. create initializes the component state and it’s ComponentLink:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;👀 Quite a few things are happening here so let’s break them down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We get the user object (of type Rc) we saved in the Context (lines 4–7) and then clone its username field (line 9), which is the actual user name the user used to log in.&lt;/li&gt;
&lt;li&gt;We create a new WebSocket message to register the current client with the WebSocket server (lines 11–15). Next, we send it to the WebSocket server using the WebSocketService’s channel transmitter (tx) (lines 17–23). If everything goes well we log a message to the console (line 22).&lt;/li&gt;
&lt;li&gt;We finish the method off by sending a fresh instance of Chat (lines 25–30).&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Next, we add the view method, which is responsible for rendering the component:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;That's one long method 😅 Most of the stuff here is just HTML and styling so we won't dive into that, but here are a few interesting pointers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On line 4 we create a callback of type MouseEvent to use when the submit button is clicked. The callback will send a message of type SubmitMessage whenever the button is clicked. This message will then get handled by the update lifecycle method.&lt;/li&gt;
&lt;li&gt;On line 10 we iterate over the users field by using map and collect to render a list of currently connected users (each user is rendered in its own div element).&lt;/li&gt;
&lt;li&gt;On line 33 we iterate over the messages field, similar to how we did it previously for users.&lt;/li&gt;
&lt;li&gt;We use the ref property on the input element (line 57) so we can later reference it (i.e. to read its value) outside of the view lifecycle method.&lt;/li&gt;
&lt;li&gt;We set the Submit button’s onclick property (line 58) to submit the callback defined on line 4.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;We are FINALLY ready to run the project for the first time and see what we achieved so far! Inside the project root folder run npm start. This will kick the process of compiling our app into WASM, optimizing it, building the HTML (with Webpack), and finally — running a dev server.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If all goes well you should be greeted with a login page where you can enter a username. Once done the main chat screen appears, let’s inspect the dev tools console:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AJoF7BoLa-6R4DMX1Mm6VJg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AJoF7BoLa-6R4DMX1Mm6VJg.png" alt="dev tools"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Three lines pop out almost immediately:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We successfully sent a WebSocket message from our chat component to the WebSocket server (first debug line)&lt;/li&gt;
&lt;li&gt;The WebSocket service sent the username to the WebSocket server&lt;/li&gt;
&lt;li&gt;The WebSocket server returned a message with a type of users containing an array with the names of the connected users.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that begs the question: if our WebSocket service received a message back with all the connected users — why don't we see that on our UI? Did our chat component even get that message at all?&lt;/p&gt;

&lt;p&gt;Eagled-eyed readers might notice that when we previously discussed our WebSocket service. We only discussed how components send messages to the service, but nowhere did we mention how the service sends back messages to the components. Let’s take another dive into the rabbit hole that is our WebSocket service…&lt;/p&gt;

&lt;h3&gt;
  
  
  🔌 WebSockets — Phase 2
&lt;/h3&gt;

&lt;p&gt;We are currently using an MPSC channel to communicate between components and the WebSocket service, but as the name implies — we cannot use the same approach for updating the components since we would need the opposite direction, i.e. multi consumers (components) single producer (service), which doesn't exist.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/media/644b0fe0703d066ae60bd7165831a174/href" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://medium.com/media/644b0fe0703d066ae60bd7165831a174/href" rel="noopener noreferrer"&gt;https://medium.com/media/644b0fe0703d066ae60bd7165831a174/href&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We use Yew Agents! Agents can be used to “route messages between components independently of where they sit in the component hierarchy” (taken from Yew’s official docs). That means we can use an agent’s dispatcher to send a message from the WebSocket service down to any listening component. Let’s create an event bus service which we will use to send these messages with.&lt;/p&gt;

&lt;p&gt;Create a new file called &lt;strong&gt;event_bus.rs&lt;/strong&gt; under services and paste the following content to it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/media/5d8876d1d684913d723182682dcef02e/href" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://medium.com/media/5d8876d1d684913d723182682dcef02e/href" rel="noopener noreferrer"&gt;https://medium.com/media/5d8876d1d684913d723182682dcef02e/href&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🔬So what do we have here?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lines 10–13&lt;/strong&gt; : we create the EventBus struct which holds a link and a list of subscribers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lines 15–47&lt;/strong&gt; : we implement the Agent trait for our EventBus. There are a bunch of methods we need to implement (connected, disconnected etc), but the one we care about the most is handle_input, which iterates over all of the subscribers and using link, sends them the content of the message.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let’s go back to our WebSocket service and use the new event bus:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open &lt;strong&gt;websocket.rs&lt;/strong&gt; under the services folder. Add the required use statements and the event_bus initializing. We are creating a dispatcher because we need a one-way communication channel between the service and the components:&lt;/p&gt;

&lt;a href="https://medium.com/media/8ed2ab338cd5d31bbdf04811ba1758bc/href" rel="noopener noreferrer"&gt;https://medium.com/media/8ed2ab338cd5d31bbdf04811ba1758bc/href&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To send a message on the channel, all we have to do is use send:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://medium.com/media/40bf2850055509e4dc735edd39e7aed5/href" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://medium.com/media/40bf2850055509e4dc735edd39e7aed5/href" rel="noopener noreferrer"&gt;https://medium.com/media/40bf2850055509e4dc735edd39e7aed5/href&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see we are making use of the EventBusMsg struct we defined in &lt;strong&gt;event_bus.rs&lt;/strong&gt; to send a String message down the channel (lines 9 and 15).&lt;/p&gt;

&lt;p&gt;Lastly, we need to add the event bus to the Chat component.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open &lt;strong&gt;chat.rs&lt;/strong&gt; under the &lt;strong&gt;components&lt;/strong&gt; folder, and add _producer to the Chat struct:&lt;/p&gt;

&lt;a href="https://medium.com/media/35f9ec005dceb966bf32355d07e3360a/href" rel="noopener noreferrer"&gt;https://medium.com/media/35f9ec005dceb966bf32355d07e3360a/href&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Head over to the create lifecycle method of Chat and add the default value for _producer to the returning Self statement:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://medium.com/media/04010ad3c68e103fd8c2ba33ba68b048/href" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://medium.com/media/04010ad3c68e103fd8c2ba33ba68b048/href" rel="noopener noreferrer"&gt;https://medium.com/media/04010ad3c68e103fd8c2ba33ba68b048/href&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you run the app again now you’ll notice nothing really changes. The reason for that is we never implemented the update lifecycle method, which is in charge of handling the different messages our component get (like HandleMsg or SubmitMessage). The method returns a boolean indicating whether the component should be re-rendered or not.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Under the create method, add the following implementation of update:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://medium.com/media/a758d26b80832373969f8b0a75d5a68d/href" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://medium.com/media/a758d26b80832373969f8b0a75d5a68d/href" rel="noopener noreferrer"&gt;https://medium.com/media/a758d26b80832373969f8b0a75d5a68d/href&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🔬So what do we have here?&lt;/p&gt;

&lt;p&gt;The method matches msg to one of the two possible messages the component can get: HandleMsg or SubmitMessage. If the message is of type HandleMsg we perform another match and check whether it is a message of type Users or of type Message. Messages of type Users get sent every time the connected user list changes (a user connect/disconnect) and upon receiving this message — we populate the users array with the name and avatar of each user that is connected. Messages of type Message get sent when a user posts a message to the chat, and pretty similar to how we handled users, we append the new message to the messages array. In both of these cases, we return true since we need the component to rerender itself with the new data.&lt;/p&gt;

&lt;p&gt;In the case the message is of type SubmitMessage we grab the message text from the input HTML element (remember that ref property we set earlier?) and using the WebSocket service channel transmitter (tx) we send the message to the WebSocket server. In the case of SubmitMessage we return false as we don't need the component to rerender itself.&lt;/p&gt;

&lt;p&gt;And with this change, our app is now ready for prime time!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AGTmruZMoiZUJw43JH9I4GA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AGTmruZMoiZUJw43JH9I4GA.png" alt="final product"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This post was definitely on the longer side, but I hope you got to experience how it is like working with Yew when building a web app. You can find the full source code at &lt;a href="https://github.com/jtordgeman/YewChat" rel="noopener noreferrer"&gt;https://github.com/jtordgeman/YewChat&lt;/a&gt;. Feel free to hit me up on &lt;a href="https://twitter.com/FullStackJ" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; or by leaving a comment here — I promise I'll answer nicely ;p&lt;/p&gt;

&lt;p&gt;Last but not least, huge thanks to &lt;a href="https://medium.com/u/9caa2c6ac2a4" rel="noopener noreferrer"&gt;Sara Lumelsky&lt;/a&gt; for proofreading and fixing my stupid spelling mistakes! :)&lt;/p&gt;

</description>
      <category>websocket</category>
      <category>yew</category>
      <category>rust</category>
    </item>
    <item>
      <title>Let’s Build a Salesforce Commerce Cloud Products Search Component with OCAPI, Rust, and Yew — Part…</title>
      <dc:creator>Johnny Tordgeman</dc:creator>
      <pubDate>Tue, 23 Nov 2021 17:54:59 +0000</pubDate>
      <link>https://forem.com/pxjohnny/lets-build-a-salesforce-commerce-cloud-products-search-component-with-ocapi-rust-and-yew-part-1ggd</link>
      <guid>https://forem.com/pxjohnny/lets-build-a-salesforce-commerce-cloud-products-search-component-with-ocapi-rust-and-yew-part-1ggd</guid>
      <description>&lt;h4&gt;
  
  
  Cover Photo by &lt;a href="href="&gt;Michael Fenton&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/love?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;
&lt;/h4&gt;

&lt;h3&gt;
  
  
  Salesforce Commerce Cloud + Rust = ❤️
&lt;/h3&gt;

&lt;p&gt;Anyone familiar with Salesforce Commerce Cloud (SFCC for short) knows that you usually develop a cartridge to extend and add new features to your SFCC instance. Since a cartridge is basically a module written in JavaScript, how do we go about adding Rust to the cartridge world? Are we really going to write a Rust-based cartridge in this post?&lt;/p&gt;

&lt;p&gt;Well, not really. While we can’t write Rust cartridges yet (😭), we can write a Rust-based WebAssembly component and load it in our SFCC instance (💡). You might be thinking: johnny, by definition a WebAssembly cannot directly access the DOM (&lt;a href="https://developer.mozilla.org/en-US/docs/WebAssembly/Concepts"&gt;https://developer.mozilla.org/en-US/docs/WebAssembly/Concept)&lt;/a&gt;. How are we going to render the component to the page? Is there some kind of magic involved?? well…&lt;/p&gt;

&lt;h3&gt;
  
  
  Yew 101
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/3ogwFGEHrVxusDbDjO/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/3ogwFGEHrVxusDbDjO/giphy.gif" width="480" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Meet Yew. By its own definition, Yew is "a modern &lt;a href="https://www.rust-lang.org/"&gt;Rust&lt;/a&gt; framework for creating multi-threaded front-end web apps using &lt;a href="https://webassembly.org/"&gt;WebAssembly&lt;/a&gt;." (&lt;a href="https://yew.rs/#what-is-yew"&gt;https://yew.rs/#what-is-yew&lt;/a&gt;). It features component-based development (React devs should feel right at home here), access to services (fetch for example) and great JavaScript interoperability.&lt;/p&gt;

&lt;p&gt;If I had to summarize Yew in one sentence I would say it's a framework that allows you to write back-to-front web applications in a component mindset, completely in Rust. Now that's some cool sh*t right there! 🤘&lt;/p&gt;

&lt;p&gt;Let’s begin our journey with a simple Yew application, just to, you know, get a feeling of how things work. Later on, we will add OCAPI into the mix and use it to search for a product from our SFCC instance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the Project
&lt;/h3&gt;

&lt;p&gt;Our simple application will bind an HTML input element to a read-only textarea element, copying everything the user writes in the input element to the textarea. I know it's not much (and in fact sounds pretty damn stupid) but think of it as the base for our product searcher, which will also use an input element to get the search term and display the results in a nicely styled div below it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🏗  Before we begin, make sure you have the following installed:&lt;br&gt;&lt;br&gt;
* Rust 1.50+- &lt;a href="https://www.rust-lang.org/learn/get-started"&gt;https://www.rust-lang.org/learn/get-started&lt;/a&gt;&lt;br&gt;&lt;br&gt;
* WASM-Pack — &lt;a href="https://github.com/rustwasm/wasm-pack"&gt;https://github.com/rustwasm/wasm-pack&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create a new Rust library project by running cargo new --lib yew-product-searcher, cd to the new yew-product-searcher folder, and open it in your favorite code editor.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Our project is going to be a dynamic library, so let’s update our &lt;strong&gt;Cargo.toml&lt;/strong&gt; to reflect that. Add the following snippet before the dependencies section:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next, let’s add the dependencies for our project. Update your &lt;strong&gt;Cargo.toml&lt;/strong&gt; dependencies section as follows:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;📦 So why do we need all of these dependencies?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;wasm-bindgen&lt;/strong&gt;  — A Rust library we will use to communicate between Rust and JavaScript. Also contains a set of macros that help when working with WASM and Rust.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;yew/yewtil&lt;/strong&gt;  — The Yew library and its utility library.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;serde/serde_json &lt;/strong&gt; — A serialization library we will use to serialize and deserialize JSON payloads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;web-sys&lt;/strong&gt;  — Yew uses web-sys under the hood to communicate between Rust and Web APIs. By default, none of the features are added. We specify the features we are going to use with it in our dependencies declaration.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ⛳ Round 1: The Entry Point
&lt;/h3&gt;

&lt;p&gt;Like most things in life, our Yew application needs an entry point. The grand entrance. In our case, that point is the &lt;strong&gt;src/lib.rs&lt;/strong&gt; file.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;We begin by adding the required use statements:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;🙋‍♂ Before you ask — yes I know we don't have an &lt;strong&gt;app.rs&lt;/strong&gt; yet - we will add it shortly.️&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now, let’s add the actual entry point function:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;🔬 So what do we have here?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Line 1&lt;/strong&gt;  — Using the wasm_bindgen(start) attribute, we annotate the app’s entry point. It is required by wasm-pack.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Line 2&lt;/strong&gt;  — Our main function. Returns an Option of either an empty tuple or a JsValue object.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lines 3–6&lt;/strong&gt;  — Using web_sys we stroll through the DOM tree, from the top window object (line 3) all the way to the body (line 5). Once we have the body element we can get the collection of its children elements by calling the much appropriately named method - children(line 6).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lines 7–9&lt;/strong&gt;  — Using the named_item method, we can get a reference to the div element which will host our app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Line 10 &lt;/strong&gt; — Creates a new yew app and mounts it to an element (in our case, the div with the id of &lt;strong&gt;yew-app&lt;/strong&gt;  ).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Line 11&lt;/strong&gt;  — Returns a unit type.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ⛳ Round 2: The App Component
&lt;/h3&gt;

&lt;p&gt;We now have an entry point pointing to nothing (remember app::App from line 10 above?). Now is the perfect time to add the App component - a.k.a our application’s main component - to the mix.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a new &lt;strong&gt;app.rs&lt;/strong&gt; file under the &lt;strong&gt;src&lt;/strong&gt; folder with the following content:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Our App is basically a struct containing a link property with ComponentLink as its type and a text property of type String.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;😐 Johnny — I know what a String type is, but wtf is aComponentLink?!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Glad you asked! A ComponentLink is basically a link (a.k.a a reference) to the component that enables us, at a later stage, to send messages (read: actions) to the component through callbacks. Imagine ComponentLink as your way of interacting with the components at runtime.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To send a message (a.k.a action) to the component we need to define an enum containing all the possible messages the calling party (the component host, a service, an agent, etc.) can send. Add the Msg enum to  &lt;strong&gt;app.rs&lt;/strong&gt; :&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We will call our component on every change in the input element (i.e. the oninput event), passing the message of. DuplicateText with an InputData object. The InputData object contains, among other properties, the new value of the element, which is something we will shortly use.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now it's time to implement Yew’s Component trait for our lovely app. As you’ll soon see — the Component trait basically enables us to control the component’s life cycle and how it will act at each event. We begin with the super basic stuff and set the Message and Properties types:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;🔬 So what do we have here?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Line 1&lt;/strong&gt;  — We tell Rust we want to implement the Component trait for our App.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Line 2&lt;/strong&gt;  — We set the Message type to the Msg enum we created previously to let the component know of the different actions it should expect.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Line 3&lt;/strong&gt;  — If you have some React background, you are probably pretty familiar with the concept of properties. In a nutshell, properties are immutable inputs we can add on an element to pass to the component. To visualize the properties concept, check out the following example, in which title is a property we pass to the component:
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Page&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Hi properties!"&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next, we implement the very first life-cycle method: create. The create method fires when the component is created and it is here that we initialize the component properties as well as the ComponentLink:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;When the component is created, it receives the properties (if any) from its host (a.k.a parent) as well as establish the link between itself and the host. The create method accepts these two arguments (line 4) that we then use to initialize our component (lines 5–8). Notice that we used _ as the properties variable name since in our simple component we don't them.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;As mentioned earlier, we communicate with the component through messages. The life-cycle method that handles these messages is the update method. This method contains the logic to handle the different messages, and ultimately decide if the component should re-render itself:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;When the update method is called it will perform a match on the msg object (line 4). We only have one possible message on our Msg enum for this component, so it will match DuplicateText (line 5). If the associated element's updated value matches DuplicateText we update the value of the text property with the value of the message. We end the method by returning true (line 7), indicating that the component needs to re-render.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📣 If we had more than one message, we had to handle cases where nothing matches, which usually results in returning false as the component doesn't need to re-render.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next up: the &lt;code&gt;change&lt;/code&gt; method. Just like the &lt;code&gt;update&lt;/code&gt; method, &lt;code&gt;change&lt;/code&gt; is also able to re-render the component, but unlike &lt;code&gt;update&lt;/code&gt; — &lt;code&gt;change&lt;/code&gt; deals with a change in the component properties. &lt;code&gt;change&lt;/code&gt; should return true (meaning re-render) only when the properties changed from the last call. In any other case (the component doesn't have properties at all, the properties didn't change etc.) we should return false:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;And finally, the crown jewel — &lt;code&gt;view&lt;/code&gt;. The &lt;code&gt;view&lt;/code&gt; method is where we define how to render our component to the DOM. To prevent things from getting messy here, Yew provides us with a super useful macro — &lt;code&gt;html!&lt;/code&gt; — for declaring HTML (and SVG) elements, their attributes, and their events. You can think of the &lt;code&gt;html!&lt;/code&gt; macro as the equivalent of JSX in React:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;🔬 So what do we have here?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Line 4&lt;/strong&gt;  — Using the &lt;code&gt;html!&lt;/code&gt; macro.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Line 6 / Line 9&lt;/strong&gt; — When we want to write some text directly to the DOM we wrap it in curly brackets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Line 10—&lt;/strong&gt; We set the &lt;code&gt;oninput&lt;/code&gt; callback using the link property, passing it the &lt;code&gt;InputData&lt;/code&gt; of the element.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Line 14&lt;/strong&gt;  — We bind the &lt;code&gt;textarea&lt;/code&gt;’s value attribute to the component text property, which will get updated whenever the data changes on the input element.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;🗣 Keep the class names used here in the back of your mind. We will meet up with them again soon.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  ⛳ Round 3: Packing Time
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GpVo0Wa3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/625/0%2Ax-wKCBN6AhbZ1un_.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GpVo0Wa3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/625/0%2Ax-wKCBN6AhbZ1un_.jpg" alt="" width="625" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our component is ready for prime time, but before we are able to load it, we have to pack it. We are going to use &lt;strong&gt;wasm-pack&lt;/strong&gt; as our weapon of choice, mainly for its simplicity, but it's important to know that there are other ways to pack a WebAssembly as well.&lt;/p&gt;

&lt;p&gt;Open your shell and cd to the project folder. Inside of it run the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wasm-pack build &lt;span class="nt"&gt;--target&lt;/span&gt; web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jopV66Jz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/510/1%2AB8wmSsJBMAAPzhTGD-XcJg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jopV66Jz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/510/1%2AB8wmSsJBMAAPzhTGD-XcJg.jpeg" alt="" width="510" height="499"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A wild folder appears!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you check the project folder now you will notice a new folder —  &lt;strong&gt;pkg&lt;/strong&gt;. This new folder contains the compiled WebAssembly (yay 🎉) along with its supporting JavaScript wrappers.&lt;/p&gt;

&lt;p&gt;Before we proceed to add OCAPI and SFCC to the mix, let’s quickly test that it's working as expected.&lt;/p&gt;
&lt;h3&gt;
  
  
  ⛳ Final Round: Testing
&lt;/h3&gt;

&lt;p&gt;To quickly test our WASM module, let’s write a short HTML file that will load the module and initiate it using the run_app command we defined way back in the &lt;strong&gt;lib.rs&lt;/strong&gt;  file.&lt;/p&gt;

&lt;p&gt;In the root folder of the project create an &lt;strong&gt;index.html&lt;/strong&gt; file with the following content:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;😱 What do we have here??&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Line 6 &lt;/strong&gt; — Remember all those class names we added to the view method? So they are all Tailwind CSS classes and in order to use them, we need to include the Tailwind CSS file&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;👀  It is not recommended to include the unoptimized CSS file from a CDN like we are doing here, but to keep things simple and avoid installing the Tailwind tooling, etc, we will just use that file.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Line 10 &lt;/strong&gt; — The div in which our app will render itself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Line 11&lt;/strong&gt;  — We declare a JavaScript module script section.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Line 12 &lt;/strong&gt; — We import the init and run_app methods from &lt;strong&gt;yew_product_searcher.js&lt;/strong&gt; , the JavaScript wasm wrapper wasm-pack created for us. It is with these functions that we are going to load our module in the browser.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lines 13–16&lt;/strong&gt;  — As we cannot have root-level async/await, we create an async function called run (line 13), await on the init function (line 14) and finally run the run_app function which starts our Yew app (line 15).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Line 17&lt;/strong&gt;  — Calling the async run method.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use your local webserver of choice (I personally use Caddy) and embrace the beauty that is Yewplicator:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gfT2Kuu5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/932/1%2AeMUpd1rtdq6OO4jXY5g3pg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gfT2Kuu5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/932/1%2AeMUpd1rtdq6OO4jXY5g3pg.gif" alt="" width="880" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🥂 Summary
&lt;/h3&gt;

&lt;p&gt;So far we:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Built a Yew project from scratch.&lt;/li&gt;
&lt;li&gt;Added a root component with a number of HTML elements that interact with one another without any JavaScript.&lt;/li&gt;
&lt;li&gt;Packed the WASM module with wasm-pack and&lt;/li&gt;
&lt;li&gt;Created a test HTML file that uses a JavaScript module script to load and initialize the WASM.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our next post, we will take our simple Yewplicator and throw SFCC into the mix by transforming it to an OCAPI based product searcher component.&lt;/p&gt;




</description>
      <category>yew</category>
      <category>sfcc</category>
      <category>rust</category>
    </item>
    <item>
      <title>Building a Simple Bot Protection With NGINX JavaScript Module (NJS) and TypeScript</title>
      <dc:creator>Johnny Tordgeman</dc:creator>
      <pubDate>Mon, 24 May 2021 19:57:34 +0000</pubDate>
      <link>https://forem.com/pxjohnny/building-a-simple-bot-protection-with-nginx-javascript-module-njs-and-typescript-1mpn</link>
      <guid>https://forem.com/pxjohnny/building-a-simple-bot-protection-with-nginx-javascript-module-njs-and-typescript-1mpn</guid>
      <description>&lt;h4&gt;
  
  
  Cover Photo by &lt;a href="href="&gt;Phillip Glickman&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/robots?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;I love Lua. I also love NGINX. The three of us get along just great. Like every relationship, we’ve had our highs and lows (yes, I’m looking at you Lua patterns), but overall life was perfect. Then, NGINX JavaScript Module (NJS for short) came along.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F750%2F1%2AUJZhiTDBGO2mOFx01iUL8Q.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F750%2F1%2AUJZhiTDBGO2mOFx01iUL8Q.jpeg"&gt;&lt;/a&gt;I ❤️ JS/TS&lt;/p&gt;

&lt;p&gt;NGINX JavaScript module was first introduced in 2015 but recently received a big boost in functionality with the 0.5.x update. Since I'm a sucker for anything JS, I decided to test it out by building a simple (read naive and &lt;strong&gt;not production ready&lt;/strong&gt; ) bot protection module 🤖.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring NGINX
&lt;/h3&gt;

&lt;p&gt;Before diving into bot fight, we have to set up NGINX to support the JavaScript module. The instructions below are for my setup (Ubuntu 20.4/Nginx 1.18), so YMMV, but the general idea should be the same for most setups.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Start by adding the NGINX PPA key by running:&lt;br&gt;&lt;br&gt;
curl -s &lt;a href="https://nginx.org/keys/nginx_signing.key" rel="noopener noreferrer"&gt;https://nginx.org/keys/nginx_signing.key&lt;/a&gt; | sudo apt-key add -&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Setup the repository key by running:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'echo "deb http://nginx.org/packages/ubuntu/ focal nginx" &amp;gt;&amp;gt; /etc/apt/sources.list.d/nginx.list'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Update the repository list by runningsudo apt update.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install NJS by running sudo apt install nginx-module-njs.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If all went well, at this point, you should get this lovely message on your terminal:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2ATR-aBRr-V8qILaSHvmVqeQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2ATR-aBRr-V8qILaSHvmVqeQ.png"&gt;&lt;/a&gt;Big success 🥂&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Enable NJS by adding the following to the top of your main &lt;strong&gt;nginx.conf&lt;/strong&gt; file:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;load_module modules/ngx_http_js_module.so;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Restart NGINX to load NJS into the running instance:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nginx &lt;span class="nt"&gt;-s&lt;/span&gt; reload
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now your NGINX is ready for some JS love, so let’s move on and create our first line of defense — IP filtering!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F888%2F1%2AG71NQ2tKLzd-3BmYLgNJ3A.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F888%2F1%2AG71NQ2tKLzd-3BmYLgNJ3A.jpeg"&gt;&lt;/a&gt;damn right you are!&lt;/p&gt;
&lt;h3&gt;
  
  
  Opening Act — Creating the Project
&lt;/h3&gt;

&lt;p&gt;Our bot protection project is going to be written in TypeScript. For that, we need to create a project that will transpile TypeScript to ES5 JavaScript, which NJS can understand. As you may have guessed, NodeJS is a must here, so make sure you are all set up before continuing.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create the new project folder and initialize it:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;njs-bot-protection &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;njs-bot-protection
npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Install the required packages:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-D&lt;/span&gt; @rollup/plugin-typescript @types/node njs-types rollup typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Add the &lt;strong&gt;build&lt;/strong&gt; script to the &lt;strong&gt;package.json&lt;/strong&gt; ’s &lt;strong&gt;scripts&lt;/strong&gt;  section:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rollup -c"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;To compile the project, you’ll need to tell the TypeScript compiler how to do that with the &lt;strong&gt;tsconfig.json&lt;/strong&gt; file. Create a new &lt;strong&gt;tsconfig.json&lt;/strong&gt; file in the root of the project, and add the following content to it:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Lastly, let’s add the rollup config, which will wrap everything up and produce the endgame js file that NJS will read.
Create a new &lt;strong&gt;rollup.config.js&lt;/strong&gt; file in the root of the project, and add the following content to it:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And with that, our boilerplate is all loaded and ready to go. That means it’s time to kick some bots!&lt;/p&gt;

&lt;h3&gt;
  
  
  Round 1 — IP Filtering
&lt;/h3&gt;

&lt;p&gt;Our first line of bot defense is IP blocking; we compare the IP of an incoming request with a list of known IPs with bad reputations, and if we find a match, we redirect the request to a “block” page.&lt;/p&gt;

&lt;p&gt;We’ll begin with creating the JavaScript module:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the project root folder, create a new folder called &lt;strong&gt;src,&lt;/strong&gt; and then inside of it create a new &lt;strong&gt;bot.ts&lt;/strong&gt;  file.&lt;/li&gt;
&lt;li&gt;Add the following code snippet to  &lt;strong&gt;bot.ts&lt;/strong&gt; :&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;💡 So what do we have here?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Line 1&lt;/strong&gt; : Imports the built-in module for the file system (i.e., fs). This module deals with the file system, allowing us to read and write files, among other activities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Line 2&lt;/strong&gt; : Calls the loadFile function, passing it the name of the file we wish to load.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lines 4–12&lt;/strong&gt; : The implementation of loadFile. First, we initialize the data variable to an empty string array (line 5), then we try to read and parse a text file containing a list of bad IP addresses into the data object (line 7), and finally we return the data object (line 11).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lines 14–21&lt;/strong&gt; : The implementation of verifyIP — the heart of our module (for now). This is the function we will expose to NGINX to verify the IP. We first check if the array of bad reputation IPs contains the current request client IP (line 15). If yes, redirect the request to the block page and end processing (lines 16 and 17). If not , redirect internally to the pages location (line 20).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Line 23&lt;/strong&gt; : Exports (read exposes) verifyIPexternally.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Build the module by running npm run build in your terminal. If all goes well, you should find the compiled &lt;strong&gt;bot.js&lt;/strong&gt; file in the &lt;strong&gt;dist&lt;/strong&gt; folder 🎉&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With the file in hand, let’s configure NGINX to be able to use it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In your NGINX folder ( &lt;strong&gt;/etc/nginx&lt;/strong&gt; in my case) create a folder named &lt;strong&gt;njs&lt;/strong&gt; and copy &lt;strong&gt;bot.js&lt;/strong&gt; from the previous section inside it.&lt;/li&gt;
&lt;li&gt;Create a new folder called &lt;strong&gt;njs&lt;/strong&gt; under &lt;strong&gt;/var/lib&lt;/strong&gt; , create a file called &lt;strong&gt;ips.txt&lt;/strong&gt; inside it, and populate it with a list of bad reputation IPs (one IP per line). You can either add your own list of IPs or use something like &lt;a href="https://github.com/stamparm/ipsum" rel="noopener noreferrer"&gt;https://github.com/stamparm/ipsum&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;In your &lt;strong&gt;nginx.conf&lt;/strong&gt; , under the http section, add the following:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;js_path &lt;span class="s2"&gt;"/etc/nginx/njs/"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
js_import bot.js&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;💡 So what do we have here?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;js_path&lt;/strong&gt;  — Sets the path for the NJS modules folder.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;js_import&lt;/strong&gt;  — Imports a module from the NJS modules folder. If not specified, the imported module namespace will be determined by the file name (in our case, bot)&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Under the server section (mine is on &lt;strong&gt;/etc/nginx/conf.d/default.conf&lt;/strong&gt; ) modify the / location as follows:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;location / &lt;span class="o"&gt;{&lt;/span&gt;
    js_content bot.verifyIP&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;By calling verifyIP using the js_content directive we set it as the content handler, which means verifyIP can control the content we send back to the caller (in our case, either show a block page or pass the request to the origin)&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Still under the server section, add the block.html location and the pages named location:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;location &lt;span class="o"&gt;[&lt;/span&gt;@pages]&lt;span class="o"&gt;(&lt;/span&gt;http://twitter.com/pages&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    root /usr/share/nginx/html&lt;span class="p"&gt;;&lt;/span&gt;
    proxy_pass &lt;span class="o"&gt;[&lt;/span&gt;http://localhost:8080]&lt;span class="o"&gt;(&lt;/span&gt;http://localhost:8080&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

location /block.html &lt;span class="o"&gt;{&lt;/span&gt;
    root /usr/share/nginx/html&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;(The namedpages location will be used by our NJS module to internally redirect the request if it shouldn't be blocked. You likely have your own logic for this redirection so change this to fit your needs)&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;At the bottom of the file, add the server block for port 8080:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;server &lt;span class="o"&gt;{&lt;/span&gt;
        listen 8080&lt;span class="p"&gt;;&lt;/span&gt;
        location / &lt;span class="o"&gt;{&lt;/span&gt;
        root /usr/share/nginx/html&lt;span class="p"&gt;;&lt;/span&gt;
        index index.html index.htm&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Under the &lt;strong&gt;/usr/share/nginx/html&lt;/strong&gt; folder, add the &lt;strong&gt;block.html&lt;/strong&gt; file as follows:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;And with that, our IP protection is ready! Add your own IP to the &lt;strong&gt;ips.txt&lt;/strong&gt; file and restart NGINX (sudo nginx -s reload). Browse to your instance and you should be greeted with the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2Aly0aRwgPudTC-TcdLZr7mg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2Aly0aRwgPudTC-TcdLZr7mg.png"&gt;&lt;/a&gt;Take that Mr. Evil Bot! 🤖 ⛔&lt;/p&gt;

&lt;h3&gt;
  
  
  Round 2 — JavaScript Detection
&lt;/h3&gt;

&lt;p&gt;Our second protection layer is JavaScript detection. We use this detection to determine if the visitor coming to our site is running JavaScript (which every normal browser should do) or not (a warning sign that this visitor might not be a legitimate user). We begin with injecting a JavaScript snippet to the pages that will bake a cookie on the root path:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add the following code snippets to  &lt;strong&gt;bot.ts&lt;/strong&gt; :&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;💡 So what do we have here?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Line 1&lt;/strong&gt; : Imports the built-in Crypto module. This module deals with cryptography, and we will soon use it for creating an HMAC.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lines 5–18&lt;/strong&gt; : The implementation of getCookiePayload. The function sets a date object to one hour ahead of the current time (lines 6–8), then uses the date object to HMAC (using the crypto module) the signature we passed to the function (the value object) with the date object (lines 10–14). Lastly, the function returns the cookie information in a string format (name, value, expiration, etc.). You may notice the cookie value contains not only the hashed signature but also the date object we used to HMAC the signature with. You’ll see why we do that soon.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lines 20–30&lt;/strong&gt; : The implementation of addSnippet. The function buffers the request data, and once it finishes (line 23) it:
&lt;/li&gt;
&lt;li&gt;Creates a signature based on the client IP and the User-Agent header (line 24).
&lt;/li&gt;
&lt;li&gt;Replaces the closing head tag with a script section that inserts a cookie (from the getCookiePayload function) on the browser side using JavaScript’s document.cookie property. (lines 25–28).
&lt;/li&gt;
&lt;li&gt;Sends the modified response back to the client (line 29).&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Export the new addSnippet function by updating the export statement at the bottom of the file:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;verifyIP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;addSnippet&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Under the @pages location block, modify the / location as follows:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;location &lt;span class="o"&gt;[&lt;/span&gt;@pages]&lt;span class="o"&gt;(&lt;/span&gt;http://twitter.com/pages&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    js_body_filter bot.addSnippet&lt;span class="p"&gt;;&lt;/span&gt;
    proxy_pass &lt;span class="o"&gt;[&lt;/span&gt;http://localhost:8080]&lt;span class="o"&gt;(&lt;/span&gt;http://localhost:8080&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Unlike verifyIP, we don't want addSnippet to manage the content of the response, we want it to inject content (a script tag in our case) to whatever response comes back from the origin. This is where js_body_filter comes into play. Using the js_body_filter directive we tell NJS that the function we provide will modify the original response from the origin and return it once finished.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Restart NGINX and browse to a page on your instance. You should see our new script added just before the closing head tag:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2ACB7hOzUOS7r5rsWU-HfwlQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2ACB7hOzUOS7r5rsWU-HfwlQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the client is running JavaScript, a new cookie called &lt;strong&gt;njs&lt;/strong&gt; will be baked. Next, let’s create the validation for this cookie/lack of cookie:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add the verifyCookie function (and its supportive functions/variables), to  &lt;strong&gt;bot.ts&lt;/strong&gt; :&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;💡 So what do we have here?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lines 5–11&lt;/strong&gt; : The implementation of the updateFile function, which uses the fs module to save an array of strings to a file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lines&lt;/strong&gt;  &lt;strong&gt;13–52&lt;/strong&gt; : The motherload implementation. When validating the &lt;strong&gt;njs&lt;/strong&gt; cookie, we have a flow of verification and consequences we have to follow:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;a. We begin with extracting the &lt;strong&gt;njs&lt;/strong&gt; cookie from the request’s &lt;strong&gt;Cookie&lt;/strong&gt; header (lines 14–20).&lt;/p&gt;

&lt;p&gt;b. If we don’t have a cookie (or we do and it’s malformed), we compare the client IP against our list of client IPs that have reached us without a cookie. If we find a match from within the last hour, we fail the request (returning false, lines 26–27). If we don’t, we delete the IP (if it's on the list but past one hour) and pass the request (lines 29–34).&lt;/p&gt;

&lt;p&gt;c. If we do have a cookie, we split it into a timestamp and a payload and use the timestamp to create our own HMAC hash based on the request’s User-Agent header and client IP. If our own HMAC matches the HMAC of the &lt;strong&gt;njs&lt;/strong&gt; cookie, we pass the request. Otherwise, we fail it (lines 38–45).&lt;/p&gt;

&lt;p&gt;d. If anything goes wrong during the validation, we fail open (meaning pass) the request (lines 48–51).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add the new verify function, which calls the new verifyCookie function, and act according to its result:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;🔥 At the point you might be thinking to yourself at this point that this verify function looks eerily similar to the verifyIP function from the earlier — you are absolutely right, and I will touch on that in a minute!&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;To test our new cookie validation functionality, open up your configuration file (mine is at &lt;strong&gt;/etc/nginx/conf.d/default.conf&lt;/strong&gt; ) and change the js_content directive from verifyIP to verify:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;location / &lt;span class="o"&gt;{&lt;/span&gt;
    js_content bot.verify&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Restart NGINX and try to visit the site twice without the njs cookie — ✋ 🎤- you are blocked!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2Aly0aRwgPudTC-TcdLZr7mg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2Aly0aRwgPudTC-TcdLZr7mg.png"&gt;&lt;/a&gt;Not today Mr. Evil Bot! 🤖 ⛔&lt;/p&gt;
&lt;h3&gt;
  
  
  Final Round — Bringing It All Together
&lt;/h3&gt;

&lt;p&gt;So now we have the cookie verification, but we took off our IP verification because we can only have one js_content directive, how do we go around fixing that?&lt;/p&gt;

&lt;p&gt;You may remember that a few minutes ago we created the verify function (which eagle-eyed readers may have noticed is VERY similar to the verifyIP function we used before). If we update our verifyIP function so that it returns a boolean response as verification, and add that verification to verify, we get the best of both worlds with one big function that verifies requests for both IPs and cookies!&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Refactor the verifyIP function as follows:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Update the verify function to call verifyIP as follows:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Update the export statement, as we no longer need to expose verifyIP:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;addSnippet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;verify&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Restart NGINX and enjoy your home-made bot protection using NJS and TypeScript 🎉&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F556%2F1%2AocJSogOMSWAcaTBdaLD4Rw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F556%2F1%2AocJSogOMSWAcaTBdaLD4Rw.jpeg"&gt;&lt;/a&gt;Ewwwww, so cute ❤️&lt;/p&gt;

&lt;p&gt;🍾 The module source code is available on &lt;a href="https://github.com/jtordgeman/njs-bot-protection" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>nginx</category>
      <category>njs</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Late Night Confessions — Building a Website Using Rust, Rocket, Diesel, and Askama — Part 3</title>
      <dc:creator>Johnny Tordgeman</dc:creator>
      <pubDate>Thu, 29 Apr 2021 18:52:30 +0000</pubDate>
      <link>https://forem.com/pxjohnny/late-night-confessions-building-a-website-using-rust-rocket-diesel-and-askama-part-3-46i9</link>
      <guid>https://forem.com/pxjohnny/late-night-confessions-building-a-website-using-rust-rocket-diesel-and-askama-part-3-46i9</guid>
      <description>&lt;h4&gt;
  
  
  Cover Photo by &lt;a href="https://unsplash.com/@agnis_leznins?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Agnis Leznins&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/night-city-streets-rain?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;With a working API layer under our belt, it's time to put in the final piece of the puzzle: the presentation layer. This layer consists of static resources (HTML, CSS, JavaScript) and API calls to display and add confessions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;✏️ As this tutorial is not frontend focused, I wanted to keep things simple and use vanilla JavaScript, HTML and CSS. I will also not go into too much detail with why or how these are implemented, as we are not really here for frontend stuff, are we? 😎&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Working With Templates&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When we serve &lt;strong&gt;index.html&lt;/strong&gt; back to the user, we want it to have a confession already so the user won’t load the page and then wait for the first API call to return the confession. That basically means that our application needs to parse the &lt;strong&gt;index.html&lt;/strong&gt; static file, find the right place to inject a confession, and then inject the content in the correct place after fetching a random confession from the database. Now that might work if you have one item to inject, but what if you have two or ten?&lt;/p&gt;

&lt;p&gt;That's where templates come into play. Templates allow us to have a static HTML that contains placeholders (aka variables) that the templating engine will replace with the content of our choice. In addition, templates allow us to use tags to control the template logic (if statements, for example). However, we will not be dealing with those in this tutorial.&lt;/p&gt;

&lt;p&gt;For Late Night Confessions, I chose Askama as the templating engine because of its easy integration and simple syntax. Let’s create a template for our &lt;strong&gt;index.html&lt;/strong&gt; file (trust me, it's easier than you think):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the project root folder, create a new folder called &lt;strong&gt;templates&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Inside the templates folder, create a new file called &lt;strong&gt;index.html&lt;/strong&gt; with the following content:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The vast majority of this file is plain old HTML syntax, take a glance at lines 32 and 47— These are Askama variables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;confession (line 32) — This variable will be replaced by an actual confession from the database.&lt;/li&gt;
&lt;li&gt;total_confessions (line 47) — This variable will be replaced by the total number of confessions in our database.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that's basically that for making our HTML an Askama template. Let’s quickly add the &lt;strong&gt;styles.css&lt;/strong&gt; and &lt;strong&gt;confessions.js&lt;/strong&gt; files to the &lt;strong&gt;site/static&lt;/strong&gt; folder and get back to Rust to integrate Askama:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;A few points of interest in our JavaScript:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The refreshCard function makes a call to our GET API to get a new random confession and update the UI.&lt;/li&gt;
&lt;li&gt;The event listener for click validates the text area (so it is not empty, somewhat naive, I know, but 🤷‍♂️), and then if all is well, makes a call to our POST API with the new confession. If everything checks out (line 43), we alert the user everything is fine and update the footer note with the updated saved confessions number.&lt;/li&gt;
&lt;li&gt;We listen to the animationend event to update the displayed confession once the timer runs off (lines 53–55).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Working With Askama&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Back in our Rust project, let’s add Askama to the &lt;strong&gt;Cargo.toml&lt;/strong&gt; file:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;As mentioned earlier, Askama works with templates, so the first thing we need to do is tell Askama where our template is and which variables it's going to have:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;🔬 So what do we have here?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Line 3&lt;/strong&gt; : We derive the Template trait, which is the main trait Askama uses. It includes template related methods such as render.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Line 4&lt;/strong&gt; : We use the template attribute to specify the path to our template. The path is relative to the templates folder in the project root folder. Other than path you can also specify a source (directly set the template, without a template file) or enable debug using the print sub-attribute. Read more about the different uses of the template attribute on the &lt;a href="https://docs.rs/askama/0.10.5/askama/#the-template-attribute" rel="noopener noreferrer"&gt;official docs&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lines 5–8&lt;/strong&gt; : We define the fields the struct will hold, which are identical to the variables we defined in the template itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;We now have two functions that need to get a random confession from the database: get_confession (the handler for the GET API) and root (the handler that renders &lt;strong&gt;index.html&lt;/strong&gt; ). To avoid code duplication, let’s extract get_confession’s confession fetching logic to a new function, get_random_confession:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Notice that our new function takes a conn variable of type &amp;amp;PgConnection as argument and return a Result of either a Confession (if successful) or diesel’s error type (if there was a database-related error).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;With the get_random_confession function in place, let’s update the get_confession handler to use the new function as its closure:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Lastly, let’s update the root handler to render the template using Askama and set it as the response:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;🔬 So what do we have here?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Line 2&lt;/strong&gt; : We changed the return type to Html for success and our CustomError in case of an error.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Line 3&lt;/strong&gt; : We get a random confession from the database using the new get_random_confession function, just like we are doing for the API call to &lt;strong&gt;/api/confession.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lines 4–6&lt;/strong&gt; : We query Postgres for the number of confessions we have saved on it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lines 8–11&lt;/strong&gt; : We initiate the HomepageTemplate struct (a.k.a our template definition) with the data from Postgres.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lines 13–14&lt;/strong&gt; : This is where the magic happens. Askama turns our template into an HTML string (line 13), which we return as the handler response (line 14).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that's basically it! Go ahead and run cargo run and browse to localhost:8000. You should get something similar to the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AqXZnbKZ9Q4V3XFD7lcmShA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AqXZnbKZ9Q4V3XFD7lcmShA.png"&gt;&lt;/a&gt;A deep and heartwarming confession indeed…&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;Our site creation journey has come to its end, but take a look back at everything you achieved! You now have a web app that is able to handle static files and API requests, uses a Postgres instance for persisting data and takes advantage of templates for quicker and easier HTML manipulation.&lt;/p&gt;

&lt;p&gt;I would love to read your comments on this mini-post series over on &lt;a href="https://twitter.com/FullStackJ" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, and please join me on my next Rust post series: “Let’s Build a Fitness Tracking Webapp With Rust and Yew”.&lt;/p&gt;

&lt;h3&gt;
  
  
  Credit Where Credit’s Due
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Thank you, &lt;a href="https://www.youtube.com/channel/UCnyWSONkScKMxut5g8iGi0A" rel="noopener noreferrer"&gt;Carla Notarobot&lt;/a&gt;, for the &lt;a href="https://www.youtube.com/watch?v=0t6Dmp70kTw" rel="noopener noreferrer"&gt;starry night CSS animation background&lt;/a&gt;!&lt;/li&gt;
&lt;li&gt;Thank you, &lt;a href="https://codepen.io/traf" rel="noopener noreferrer"&gt;Traf&lt;/a&gt;, for the &lt;a href="https://codepen.io/traf/pen/oKbaqQ" rel="noopener noreferrer"&gt;progress bar CSS animation&lt;/a&gt;!&lt;/li&gt;
&lt;/ul&gt;




</description>
      <category>softwareengineering</category>
      <category>tutorial</category>
      <category>rust</category>
    </item>
    <item>
      <title>Late Night Confessions — Building a Website Using Rust, Rocket, Diesel, and Askama — Part 2</title>
      <dc:creator>Johnny Tordgeman</dc:creator>
      <pubDate>Thu, 22 Apr 2021 17:56:41 +0000</pubDate>
      <link>https://forem.com/pxjohnny/late-night-confessions-building-a-website-using-rust-rocket-diesel-and-askama-part-2-31dh</link>
      <guid>https://forem.com/pxjohnny/late-night-confessions-building-a-website-using-rust-rocket-diesel-and-askama-part-2-31dh</guid>
      <description>&lt;h4&gt;
  
  
  Cover Photo by &lt;a href="https://unsplash.com/@david_watkis?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;David Watkis&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/night-motel?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;We previously left off with our server able to handle static content, but that is about all. In order to store and retrieve confessions, our app needs to interact with a database. That’s where Diesel comes to our aid!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠ In order for Diesel to interact with a database, a database instance needs to already exist. Make sure you have access to a Postgres instance (local or cloud based, both work) before moving forward.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Housekeeping&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We begin with installing diesel_cli - a tool that helps us manage the database. As we only use Diesel for Postgres, we use the features flag to specify that:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo install diesel_cli --no-default-features --features postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;In the root folder of the project, create a .env file. At the top of the file add the DATABASE_URL property that Diesel will use to get the connection details of your Postgres instance.&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;In the project root folder run diesel setup. Diesel will create a new database (&lt;em&gt;confessions&lt;/em&gt;), as well as a set of empty migrations.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2ABFM4iVKZ3-1bnfbNbtQ0_g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2ABFM4iVKZ3-1bnfbNbtQ0_g.png"&gt;&lt;/a&gt;A new database and migrations&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using Migrations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With the database setup, it’s time to create the confessions table. Diesel uses a concept called &lt;em&gt;migrations&lt;/em&gt; to track changes done to a database schema. You can think of migrations as a list of actions that you either apply to the database ( &lt;strong&gt;up.sql&lt;/strong&gt; ) or revert ( &lt;strong&gt;down.sql&lt;/strong&gt; ).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Generate a new migration set for the confessions table by running the following command at the root of the project:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;diesel migration generate confessions_table
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This creates a new folder inside of the &lt;strong&gt;migrations&lt;/strong&gt; folder that holds the new migration set (up/down.sql) for theconfessions table:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1010%2F1%2AE_lDgx-TNqb8L5TETvTHQg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1010%2F1%2AE_lDgx-TNqb8L5TETvTHQg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;To create the new table, cd to the new migration folder and add the following to the &lt;strong&gt;up.sql&lt;/strong&gt;  file:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;In &lt;strong&gt;down.sql&lt;/strong&gt; we specify how to revert the migration (i.e., dropping the confessions table):&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Apply the new migration by running the following command:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;diesel migration run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;💡To revert the last migration run diesel migration redo .&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;cd to the &lt;strong&gt;src&lt;/strong&gt; folder to find a new file called &lt;strong&gt;schema.rs&lt;/strong&gt;. This file contains the table definition created by Diesel that enables us to work with the database in a typesafe way.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With the housekeeping behind us, we proceed to establish a connection between our Rocket instance and Diesel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Getting Connected&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The first rule of working with a database is connecting to a database. A common method of connection between a database and an application is Connection Pool — a data structure that maintains active database connections (pool of connections) which the application can use at any point of time it needs.&lt;/p&gt;

&lt;p&gt;Rocket, with its &lt;strong&gt;rocket_contrib&lt;/strong&gt; crate (a crate that adds functionality commonly used by Rocket applications), allows us to easily set up a connection pool to our database using an &lt;a href="https://blog.bitsrc.io/what-is-an-orm-and-why-you-should-use-it-b2b6f75f5e2a" rel="noopener noreferrer"&gt;ORM&lt;/a&gt; of our choice. In our case, that’s going to be Diesel.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We begin with adding three dependencies to our &lt;em&gt;cargo.toml&lt;/em&gt; file: &lt;strong&gt;diesel,&lt;/strong&gt;  &lt;strong&gt;serde,&lt;/strong&gt; and &lt;strong&gt;rocket_contrib&lt;/strong&gt; :&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;🔭 As we only need certain features from the above crates, we specify these features using the &lt;em&gt;features&lt;/em&gt; property. In our case we only need Postgres support so we specify that in the features list for &lt;strong&gt;diesel&lt;/strong&gt; and &lt;strong&gt;rocket_contrib&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Add the following import statements to your &lt;strong&gt;main.rs&lt;/strong&gt;  file:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Next, we configure the connection settings for our database. Create a new file named &lt;strong&gt;Rocket.toml&lt;/strong&gt; in the root folder of the project with the following content:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;At this point you are probably thinking to yourself: “Johnny WTF? this is exactly the same connection string we configured earlier in the  &lt;strong&gt;.env&lt;/strong&gt; file. Can’t we just use that environmental variable and be done with it?”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F625%2F0%2ARLsPBJA830NGXQcI" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F625%2F0%2ARLsPBJA830NGXQcI"&gt;&lt;/a&gt;it really is!&lt;/p&gt;

&lt;p&gt;Of course you can! But I’ll touch on how to do that a little bit later. For now, let’s roll with &lt;strong&gt;Rocket.toml&lt;/strong&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open your &lt;strong&gt;main.rs&lt;/strong&gt; file and add a new unit-like struct called DBPool:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The database attribute is used to bind a previously configured database to a poolable type in our application.The database attribute accepts the name of the database to bind as a single string parameter. This must match a database key configured in &lt;strong&gt;Rocket.toml&lt;/strong&gt;. The macro will generate all the code needed on the decorated type to enable us to retrieve a connection from the database pool later on, or fail with an error.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Lastly we need to attach the database to our Rocket instance. We do that using the attach method of our Rocket instance. The attach method takes a fairing (think of that like a middleware) and attaches it to the request flow.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Append the attach method to the Rocket instance as follows:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;🍲 Before we proceed, I’d like to take a quick (completely optional) detour and talk about how to use the connection string from the  &lt;strong&gt;.env&lt;/strong&gt; file instead of duplicating it with &lt;strong&gt;Rocket.toml&lt;/strong&gt;. If you don’t feel like messing around with creating a database procedurally, feel free to skip over to the next section —  &lt;strong&gt;Working With Models.&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If created earlier, delete the &lt;strong&gt;Rocket.toml&lt;/strong&gt; file from the root folder of the project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;dotenv&lt;/strong&gt; is a crate that makes it super easy to work with environmental variables from a  &lt;strong&gt;.env&lt;/strong&gt; file. Add the &lt;strong&gt;dotenv&lt;/strong&gt; crate as a dependency in your &lt;strong&gt;Cargo.toml&lt;/strong&gt; file:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;In &lt;strong&gt;main.rs&lt;/strong&gt; , refactor your rocket function as follows:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;🔬So what do we have here?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Line 3&lt;/strong&gt; : We call the dotenv function (from the &lt;strong&gt;dotenv&lt;/strong&gt; crate) to load variables found in the root folder  &lt;strong&gt;.env&lt;/strong&gt; file into Rust’s environment variables.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Line 5&lt;/strong&gt; : Using Rust’s standard library we load up the value of the DATABASE_URL variable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lines 6–9&lt;/strong&gt; : We define a Map that holds two keys — url for the connection string and pool_size for the size of the connection pool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Line 10&lt;/strong&gt; : We create a Rocket config using Figment and add our database name (confessions_db) as a key to the databases collection. This closely resembles the &lt;strong&gt;Rocket.toml&lt;/strong&gt; file and for a good reason — its basically the same thing just done programmatically instead of a toml formatted file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Line 12:&lt;/strong&gt; Instead of initializing the Rocket instance using ignite, we use the custom method, passing on the Figment configuration object created on line 10.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before moving on to creating the Database models, let’s build the project to make sure everything compiles as expected.&lt;/p&gt;

&lt;p&gt;🏗️ When I tried to compile the project on my Macbook, I got a compilation error related to Diesel stating that I’m missing libpq. If you happen to get the same, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install libpq using homebrew: brew install libpq&lt;/li&gt;
&lt;li&gt;In the project root folder create a new folder named  &lt;strong&gt;.cargo&lt;/strong&gt; and inside of it create a new file called &lt;strong&gt;config&lt;/strong&gt; with the following content:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Run cargo build and enjoy.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Working With Models&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To represent our database table in a type-safe way, we need to create a model (struct) that represents it. Think of a model as the link connecting your database table with your Rust code.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In your &lt;strong&gt;src&lt;/strong&gt; folder create a new file called &lt;strong&gt;models.rs&lt;/strong&gt;. This file will be the home for the models we use in our project.&lt;/li&gt;
&lt;li&gt;We begin with the Confession model, which is used when querying the database. Add the Confession struct to &lt;strong&gt;models.rs&lt;/strong&gt; :&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Our struct looks identical to the Postgres table schema we created earlier (you can peek into &lt;strong&gt;schema.rs&lt;/strong&gt; for a reminder on how it looks). But what is this Queryable attribute on top of it? It is a Diesel attribute that basically marks this struct as a READABLE result from the database. Under the hood, it will generate the code needed to load a result from a SQL query.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;📢&lt;/em&gt; The order of the fields in the model matters! Make sure to define them in the same order as the table definition in &lt;strong&gt;&lt;em&gt;schema.rs&lt;/em&gt;&lt;/strong&gt;  .&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;To save a confession to the database, we don’t need to specify the id property since it's auto-incremented on the database side. For this reason, we will create an additional model in our &lt;strong&gt;models.rs&lt;/strong&gt; file called NewConfession:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We annotate this new model with the Insertable attribute so it can be used to INSERT data to our database. In addition, we also add the table_name attribute to specify which table this model is allowed to insert data to.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Lastly, we add the schema and models modules to  &lt;strong&gt;main.rs&lt;/strong&gt; :&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Handling API Requests&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It’s time to add a new route handler to our Rocket instance to handle POST requests containing new confessions.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In &lt;strong&gt;main.rs&lt;/strong&gt; , add a new struct named ConfessionJSON, which represents the JSON data sent to us from the browser:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Add a new struct named NewConfessionResponse which represents the JSON response we send back to the browser upon adding a new confession:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Add a new POST route that will handle requests to &lt;strong&gt;/confession&lt;/strong&gt; :&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;🔬 So what do we have here?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Line 6&lt;/strong&gt; : We define the route using three attributes:
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;post&lt;/strong&gt;  — The HTTP verb this route is bound to.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;format&lt;/strong&gt;  — The required content type of the request. In our case we are going to use application/json. Any POST request to &lt;strong&gt;/confession&lt;/strong&gt; which does not have a content type of application/json will NOT be routed to the post_confession handler.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;data&lt;/strong&gt;  — The name of the variable the body will be bound to. In this example, I named the variableconfession(surrounded by &amp;lt; and &amp;gt;, which is a must), but you can name it anything you like, as long as you name it the same in the handler (line 2).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lines 7–10&lt;/strong&gt; : Here we define the handler for the &lt;strong&gt;/confession&lt;/strong&gt; route. We pass confession as an argument (same variable from step 1’s data attribute) and set its type as ConfessionJSON wrapped by serde’s Json attribute. Serde will deserialize the request body’s JSON payload as a Rust struct (ConfessionJSON) giving us a typesafe way to access it. In addition to confession we get access to the database connection pool we created earlier, thanks to the attachment of it to our Rocket instance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Line 10&lt;/strong&gt; : The handler will return a Result containing either a JSON with an HTTP status of 201 (created) or an error (using a custom error that we will write next).&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Add the implementation for the post_confession handler:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now this handler might seem scary (👻) in its current form, so let’s break it into smaller chunks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lines 6–14&lt;/strong&gt; : We create a new confession by calling the run method on our connection pool using Diesel’s insert_into method. The method takes the table name as the first argument and then using the values method we pass a struct (of type NewConfession as that is our Insertable struct) with the data that needs to be saved. Finally, we call await on the run method as it is an asynchronous function.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lines 16–18&lt;/strong&gt; : We create a new NewConfessionResponse with the result of the insert item query (the new_confession variable).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Line 20&lt;/strong&gt; : We return a Result with the newly created confession, wrapped with Created to return a status code of 201.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;If post_confession fails for whatever reason, it returns a CustomError error, that we need to create next. Inside the &lt;strong&gt;src&lt;/strong&gt; folder, create a new file called &lt;strong&gt;error.rs&lt;/strong&gt; and add the following content:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;I won’t go into much detail on what’s happening here, but the main takeaways from this file are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We create an enum to hold different error types and decorate it using Failure’s Fail attribute (lines 7–11).&lt;/li&gt;
&lt;li&gt;We implement the From trait so we can support the diesel error type (lines 13–17).&lt;/li&gt;
&lt;li&gt;Rocket requires the response of a handler (be it an error or a valid response) to implement the Responder trait. We implement this trait on our CustomError to display an error (of diesel::result::Error) to the caller (lines 19–28).&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Our post_confession handler is now completed 🎉. Let’s mount it to our Rocket instance’s routes with a new base of  &lt;strong&gt;/api&lt;/strong&gt; :&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AFtnTpZOZTi6XI8cTM-DYow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AFtnTpZOZTi6XI8cTM-DYow.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We are finally ready to test our new API! Run the app with cargo run and on a different terminal run the following curl:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;If all went well you should get back a JSON response with the confession and its new ID.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AWR7sk_VmTsILYjbiKkbyxA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AWR7sk_VmTsILYjbiKkbyxA.png"&gt;&lt;/a&gt;big success 🏆&lt;/p&gt;

&lt;p&gt;That was quite a ride, wasn’t it? You’d be happy to know (or not) that adding the GET route — for getting a random confession out of Postgres — is a much simpler task:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add the new get_confession handler to  &lt;strong&gt;main.rs&lt;/strong&gt; :&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Nothing really exciting happening here. We get a connection from the pool (line 5), use the confessions table (line 7) to query for a single random confession (line 1 defines the SQL’s RANDOM function, lines 8–10 build the query) and eventually returning a JSON of the confession (line 14).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Mount the new get_confession handler to our Rocket instance’s routes:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Launch 🚀 with cargo run and in another terminal window run this lovely curl:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now, what is it that we got back? A random confession from Postgres that’s what!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AHzC3ckwW98uKXWiw-EQ6fQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AHzC3ckwW98uKXWiw-EQ6fQ.png"&gt;&lt;/a&gt;✋🎤&lt;/p&gt;

&lt;p&gt;And with that our API is completed. We have a Rocket web server running with two API endpoints (post and get confessions) and an additional route to handle static content. Let’s move on to the final task for our website — adding the presentation layer.&lt;/p&gt;




</description>
      <category>rust</category>
      <category>softwareengineering</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Late Night Confessions — Building a Website Using Rust, Rocket, Diesel, and Askama — Part 1</title>
      <dc:creator>Johnny Tordgeman</dc:creator>
      <pubDate>Thu, 15 Apr 2021 16:07:37 +0000</pubDate>
      <link>https://forem.com/pxjohnny/late-night-confessions-building-a-website-using-rust-rocket-diesel-and-askama-part-1-127j</link>
      <guid>https://forem.com/pxjohnny/late-night-confessions-building-a-website-using-rust-rocket-diesel-and-askama-part-1-127j</guid>
      <description>&lt;h5&gt;
  
  
  Cover Photo by &lt;a href="https://unsplash.com/@thebyul?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Hanbyul Jeong&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/late-night?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;
&lt;/h5&gt;

&lt;p&gt;It’s 1:00 AM (🎵 soft jazz music). You’re lying in bed trying to get some sleep. The city lights shine into your bedroom, softly illuminating the wall in front of you. You can hear the rain outside and the sound of people going about their late-night business. You can’t fall asleep. Something is bothering you, and you feel like you have to get it off your chest. You have to tell someone, but you don’t want to do it on social media. You want to spill your guts but remain completely anonymous. If only there was a place you could do this…&lt;/p&gt;

&lt;p&gt;This is the setting we are going to use for the project of this post —  &lt;strong&gt;Late Night Confessions&lt;/strong&gt; : A 🦀 Rust-based website built using &lt;a href="https://rocket.rs/" rel="noopener noreferrer"&gt;Rocket&lt;/a&gt; (web framework), &lt;a href="http://diesel.rs/" rel="noopener noreferrer"&gt;Diesel&lt;/a&gt; (ORM), and &lt;a href="https://github.com/djc/askama" rel="noopener noreferrer"&gt;Askama&lt;/a&gt; (template rendering engine).&lt;/p&gt;

&lt;h3&gt;
  
  
  Overview
&lt;/h3&gt;

&lt;p&gt;The site functionality is pretty simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Show the user a random confession.&lt;/li&gt;
&lt;li&gt;Allow the user to add a new confession.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Since we want to keep our confessions anonymous, we will not create a signup or login form.&lt;/p&gt;

&lt;p&gt;Our site has three types of requests to handle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Static content requests — to get static files (i.e., &lt;em&gt;index.html&lt;/em&gt;, &lt;em&gt;styles.css&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;API request to get a confession.&lt;/li&gt;
&lt;li&gt;API request to post a confession.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All confessions will be saved in a Postgres database instance. We will use Diesel to manage the database activities.&lt;/p&gt;

&lt;p&gt;Our finished project will look something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AtlJAI985s9Racs0c_kiTYw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AtlJAI985s9Racs0c_kiTYw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The full source code can be found on &lt;a href="https://github.com/jtordgeman/late-night-confessions" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Launching a 🚀
&lt;/h3&gt;

&lt;p&gt;We begin by creating a new crate for our project called &lt;em&gt;late-night-rocket:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo new late-night-rocket
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Next, let’s add &lt;em&gt;Rocket&lt;/em&gt; and &lt;em&gt;Failure&lt;/em&gt; as dependencies to our &lt;em&gt;Cargo.toml&lt;/em&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;🔭 Why do we need to specifically specify the_ &lt;code&gt;0.5.0-dev&lt;/code&gt; version? Since we want our app to run on a stable Rust release, &lt;code&gt;0.5.0-dev&lt;/code&gt; is (&lt;em&gt;as of writing this post&lt;/em&gt;) the only version that supports stable Rust.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Rocket makes heavy use of macros. This means our first order of business is to import all of them to our crate. We do this by adding the &lt;code&gt;macro_use&lt;/code&gt; attribute to the top of our &lt;em&gt;main.rs&lt;/em&gt; file, pointing to the Rocket crate:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Next, let’s add some &lt;code&gt;use&lt;/code&gt; statements to import modules we would need:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Finally, it’s time to create some routes!&lt;/p&gt;

&lt;p&gt;1. We begin with the &lt;code&gt;root&lt;/code&gt; route responsible for rendering the content of &lt;em&gt;index.html&lt;/em&gt; when the &lt;code&gt;/&lt;/code&gt; path is called:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;🔬 So what do we have here?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Line 1&lt;/strong&gt;: Say hello to our first Rocket attribute — &lt;code&gt;route&lt;/code&gt;. Using this attribute, we define an HTTP method for our route (i.e &lt;code&gt;get&lt;/code&gt;, &lt;code&gt;post&lt;/code&gt;), a path (either static or dynamic), and an optional data parameter (not needed here since we are defining a &lt;code&gt;GET&lt;/code&gt; route).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lines 3–5&lt;/strong&gt;: We use the &lt;code&gt;NamedFile&lt;/code&gt; struct to try and open the &lt;strong&gt;index.html&lt;/strong&gt; file (we will create it next), and if we are successful, return the content of the file (the file extension determines the content type automatically). If we fail, we map the errors to a &lt;code&gt;NotFound&lt;/code&gt; error type and return it. Notice the use of &lt;code&gt;await&lt;/code&gt; on line 4. We are asynchronously loading the file so that other operations won't have to wait for the file to load to continue processing.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2. Next, &lt;code&gt;static_files&lt;/code&gt;, as the name suggests, will handle requests for static files, such as images:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The route looks very similar to the &lt;code&gt;root&lt;/code&gt; route, with one noticeable difference; unlike the static &lt;code&gt;root&lt;/code&gt; route, this route is dynamic, meaning it matches anything after the &lt;code&gt;/&lt;/code&gt; as the &lt;code&gt;path&lt;/code&gt; variable. We then use this &lt;code&gt;path&lt;/code&gt; variable and append it to the &lt;em&gt;site&lt;/em&gt; folder (line 3) before trying to get the file (using &lt;code&gt;NamedFile&lt;/code&gt;, just like in the previous route).&lt;/p&gt;

&lt;p&gt;3. Next, we mount the new routes to a &lt;code&gt;Rocket&lt;/code&gt; instance using the &lt;code&gt;mount&lt;/code&gt; method:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;🔬So what do we have here?&lt;/p&gt;

&lt;p&gt;We &lt;code&gt;build&lt;/code&gt; a new &lt;code&gt;Rocket&lt;/code&gt; instance, then we mount the routes using the &lt;code&gt;mount&lt;/code&gt; method, which takes two parameters as input:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A base path to use on all the associated routes (&lt;code&gt;/&lt;/code&gt; in our case)&lt;/li&gt;
&lt;li&gt;A list of routes via the &lt;code&gt;routes!&lt;/code&gt; macro.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;4. Finally, we need to launch our rocket for it to serve requests. There are two mechanisms to launch a &lt;code&gt;Rocket&lt;/code&gt; instance, but we will focus on the preferred approach for this tutorial's purposes: the &lt;code&gt;launch&lt;/code&gt; attribute. Add it above the &lt;code&gt;rocket&lt;/code&gt; function defined in the previous step:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;5. At the root of our project, create a new folder named &lt;strong&gt;site&lt;/strong&gt; and inside of it, create a folder named &lt;strong&gt;static&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;6. Inside the &lt;strong&gt;static&lt;/strong&gt; folder, create an &lt;strong&gt;index.html&lt;/strong&gt; file with the following content:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Create an empty &lt;strong&gt;styles.css&lt;/strong&gt; file in the same folder. We will populate it later on.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Go ahead and &lt;code&gt;cargo run&lt;/code&gt; the project and then browse to localhost:8000. Congratulations, you have a working Rocket server!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AqDR4dgv6G9IUcrm9JdiAWA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AqDR4dgv6G9IUcrm9JdiAWA.jpeg"&gt;&lt;/a&gt;Look ma! I can serve a page! 👶&lt;/p&gt;

&lt;p&gt;With our server up and running, we are ready to take on the next task and pour some Diesel (pun intended) into our Rocket to gain database support!&lt;/p&gt;




</description>
      <category>tutorial</category>
      <category>rust</category>
      <category>rocket</category>
      <category>diesel</category>
    </item>
    <item>
      <title>11 Days of Salesforce Storefront Reference Architecture (SFRA) — Day 11: Playing With Templates</title>
      <dc:creator>Johnny Tordgeman</dc:creator>
      <pubDate>Mon, 18 May 2020 19:01:36 +0000</pubDate>
      <link>https://forem.com/pxjohnny/11-days-of-salesforce-storefront-reference-architecture-sfra-day-11-playing-with-templates-56jg</link>
      <guid>https://forem.com/pxjohnny/11-days-of-salesforce-storefront-reference-architecture-sfra-day-11-playing-with-templates-56jg</guid>
      <description>&lt;h3&gt;
  
  
  11 Days of Salesforce Storefront Reference Architecture (SFRA) — Day 11: Playing With Templates
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2CvR_08I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AmY4tYAWObMEtg08OE_ddCQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2CvR_08I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AmY4tYAWObMEtg08OE_ddCQ.jpeg" alt=""&gt;&lt;/a&gt;Photo by &lt;a href="https://unsplash.com/@picoftasty?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Mae Mu&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/manipulation?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Time flies when you’re having fun. Today is our last stop on the SFRA development train, and its an exciting one for sure! In today’s post, we will play around with ISML templates, or in other words, the visual representation layer of our storefront.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let’s Talk About Cache, Baby
&lt;/h3&gt;

&lt;p&gt;Templates are used a lot, but by default, they are &lt;strong&gt;not&lt;/strong&gt; cached. That being said, there may be times where we want to cache the template for better performance. For cases like these, ISML comes to our aid with the &lt;code&gt;iscache&lt;/code&gt; element. The &lt;code&gt;iscache&lt;/code&gt; element should be placed at the top of the page and enables us to set cache on a template and configure it, using a number of properties, to suit our needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Status&lt;/strong&gt; : A boolean flag that enables/disables page caching. Since caching is disabled by default, just the presence of the &lt;code&gt;iscache&lt;/code&gt; tag implicitly enables page caching.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type&lt;/strong&gt; : A required property that sets the type of cache being used. The values for type can be either &lt;code&gt;relative&lt;/code&gt; or &lt;code&gt;daily&lt;/code&gt;, the former allows us to specify a period of time (in hours and minutes) for the page to be deleted from the cache, and the later allows us to specify a specific time in the day when the page will be deleted from the cache (eg. 3 am).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hour&lt;/strong&gt; : When the cache type is set to &lt;code&gt;relative&lt;/code&gt;, the &lt;code&gt;hour&lt;/code&gt; property represents the duration in hours before the page is cleared from the cache. When the cache type is set to &lt;code&gt;daily&lt;/code&gt;, the property represents the hour of the day (in 24h format) when the cache will expire.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minute&lt;/strong&gt; : When the cache type is set to &lt;code&gt;relative&lt;/code&gt;, the &lt;code&gt;minute&lt;/code&gt; property represents the duration in minutes before the page is cleared from the cache. When the cache type is set to &lt;code&gt;daily&lt;/code&gt;, the property represents the minute of the hour in the day when the cache will expire.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;🐘 The &lt;code&gt;iscache&lt;/code&gt; element has two additional properties which are beyond the scope of this post: &lt;code&gt;varyby&lt;/code&gt; and &lt;code&gt;if&lt;/code&gt;. If you like to learn more about them, head over to the official &lt;a href="https://documentation.b2c.commercecloud.salesforce.com/DOC1/topic/com.demandware.dochelp/ISML/ISML.html?resultof=%22%69%73%6d%6c%22%20"&gt;SFCC documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Go Wild 🌈&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Consider the following tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;iscache status="on" type="relative" minute="15"/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This will cache the page for a period of 15 minutes (notice the use of &lt;code&gt;relative&lt;/code&gt; and &lt;code&gt;minute&lt;/code&gt; here).&lt;/p&gt;

&lt;p&gt;Another example would be:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;iscache status="on" type="daily" hour="21" minute="30"/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This tag uses the &lt;code&gt;daily&lt;/code&gt; type, which means that the hour and minute properties represent an hour in the day (9:30pm in this case).&lt;/p&gt;
&lt;h3&gt;
  
  
  A JSON Response
&lt;/h3&gt;

&lt;p&gt;Not all templates have to be visual. There may come a time when you would like to return a JSON object as your response (for example, an API route). Up until now we only used &lt;code&gt;res.render&lt;/code&gt; to render our responses to the client, however &lt;code&gt;res&lt;/code&gt; has another card up its sleeve: &lt;code&gt;res.json&lt;/code&gt;. Using &lt;code&gt;res.json&lt;/code&gt; allows us to render a JSON object directly, without the need to add any ISML templates or set the content type of the response.&lt;/p&gt;

&lt;p&gt;On the Magic controller (located in our Magic cartridge controllers folder) add the following route:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;The code looks similar to our Show method, but instead of rendering it on the page, we render the response from the &lt;a href="https://icanhazdadjoke.com/"&gt;icanhazdadjoke&lt;/a&gt; service directly on the page using &lt;code&gt;res.json&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Go Wild 🌈&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you navigate to the &lt;strong&gt;/Magic-Json&lt;/strong&gt; route (don't remember the full URL? head back to Day 4 to refresh your memory) and you should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TNGi2VVX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AQN_Xn7Vp_V6ExmyK9YYS-A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TNGi2VVX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AQN_Xn7Vp_V6ExmyK9YYS-A.png" alt=""&gt;&lt;/a&gt;Our joke JSON in all its glory! 🎉&lt;/p&gt;

&lt;h3&gt;
  
  
  Overcoming the Language Barrier
&lt;/h3&gt;

&lt;p&gt;Internationalization is another important concept for our storefront, as it allows us to provide content to visitors in more than one language. ISML templates support this concept using a feature called &lt;code&gt;properties files&lt;/code&gt;. So what are these magical files? Well, nothing more than a dictionary of key/value of text really. Let’s create a new template on our Magic cartridge called &lt;strong&gt;hello.isml&lt;/strong&gt; that initially have the following content:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As you can see, it’s a pretty basic (and ugly) template that shows a header and some text. Now, this text only caters to an English speaking audience, but what if we want to show a visitor whose browser language is Spanish the same text in his native language?&lt;/p&gt;

&lt;p&gt;If you look closely at the &lt;strong&gt;templates&lt;/strong&gt; folder of our cartridge, you’ll notice a folder called &lt;strong&gt;resources&lt;/strong&gt;. As the name suggests, this folder holds the resources (or language) files for our template. Let’s create a default language (a.k.a properties) file in the folder that will hold the English text. Create a new file called &lt;strong&gt;hello.properties&lt;/strong&gt; inside the &lt;strong&gt;resources&lt;/strong&gt; folder with the following content:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This is the same text as we had hardcoded on the &lt;strong&gt;hello.isml&lt;/strong&gt; template just a moment ago. Let’s update our template to actually use the properties file:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;So what do we have here?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 9&lt;/strong&gt; : We replaced the hardcoded text with the &lt;code&gt;msg&lt;/code&gt; method of the &lt;code&gt;Resources&lt;/code&gt; object in order to display the text from a resource file. The method takes three arguments:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The key to the text we wish to display.&lt;/li&gt;
&lt;li&gt;The name of the properties file to use.&lt;/li&gt;
&lt;li&gt;The default value to display. In this example, I left it as &lt;code&gt;null&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Go Wild 🌈&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you browse to a route that uses this template you will see it just like before:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zlSni3kr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AKAigK0v7e_175uyXFTIzEA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zlSni3kr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AKAigK0v7e_175uyXFTIzEA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let’s add another file named &lt;strong&gt;hello_es.properties&lt;/strong&gt; in the resources folder:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And that's it! if a Spanish speaking visitor comes to our site, he will see the translated text:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--viUIk8VI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AJl1Q8-5mf97k9Om5pQPDtQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--viUIk8VI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AJl1Q8-5mf97k9Om5pQPDtQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can have as many properties files as you wish to support different languages. There is virtually no limit to the internalization you can have on your storefront.&lt;/p&gt;

&lt;h3&gt;
  
  
  Epilogue
&lt;/h3&gt;

&lt;p&gt;This brings our journey with SFRA to its final destination. I hope I managed to show you at least one cool aspect of the SFCC platform you didn't know before, and as always please contact me with any comments or suggestions either here or on &lt;a href="https://twitter.com/fullstackj"&gt;Twitter&lt;/a&gt;. I look forward to hearing which day was your favorite 😎&lt;/p&gt;




</description>
      <category>salesforce</category>
      <category>sfra</category>
      <category>sfcc</category>
    </item>
    <item>
      <title>11 Days of Salesforce Storefront Reference Architecture (SFRA) — Day 10: Advanced Jobs</title>
      <dc:creator>Johnny Tordgeman</dc:creator>
      <pubDate>Fri, 15 May 2020 16:01:22 +0000</pubDate>
      <link>https://forem.com/pxjohnny/11-days-of-salesforce-storefront-reference-architecture-sfra-day-10-advanced-jobs-444l</link>
      <guid>https://forem.com/pxjohnny/11-days-of-salesforce-storefront-reference-architecture-sfra-day-10-advanced-jobs-444l</guid>
      <description>&lt;h3&gt;
  
  
  11 Days of Salesforce Storefront Reference Architecture (SFRA) — Day 10: Advanced Jobs
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ngSK5S9Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AkGnPsjqUFwfZ3FqP0XBnXQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ngSK5S9Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AkGnPsjqUFwfZ3FqP0XBnXQ.jpeg" alt=""&gt;&lt;/a&gt;Photo by &lt;a href="https://unsplash.com/@jcrod?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Joshua Rodriguez&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/job?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/pxjohnny/11-days-of-salesforce-storefront-reference-architecture-sfra-day-9-jobs-2d51-temp-slug-6190953"&gt;Yesterday&lt;/a&gt; we created a job that keeps our storefront sitemap updated and fresh, and we did that using the out-of-the-box &lt;strong&gt;createSiteMap&lt;/strong&gt; step. Whenever you can use a premade step like that, that’s awesome! But, there are times that you may want to create a step customized to your own needs. Meet the &lt;strong&gt;ExecuteScriptModule&lt;/strong&gt; step — the ⭐️of today’s post!&lt;/p&gt;

&lt;h3&gt;
  
  
  The One With the Static Assets
&lt;/h3&gt;

&lt;p&gt;Let’s consider the following situation: you are using a JavaScript library in your storefront, which you download from a third-party CDN, for example: React: &lt;code&gt;&amp;lt;script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If a visitor with an Ad Blocker configured to block third-party scripts comes to our site, his experience on our site may be ruined because he might not be able to load the React JS library. One possible solution could be to host the React library in the assets folder of our storefront. This approach is awesome, and it will solve the third party issue, however, it will also create a new problem - what happens when the React library gets updated? What will keep our local asset up to date with React’s CDN? 🤔&lt;/p&gt;

&lt;p&gt;If at this point you are hearing bells in your head and thinking “this is a repeated task I should automate using SFCC Jobs” then you are absolutely right! Let’s create a job that periodically checks and downloads the React library from its CDN to our local assets folder.&lt;/p&gt;

&lt;h3&gt;
  
  
  Look Ma, I Can Run My Own Code
&lt;/h3&gt;

&lt;p&gt;If you look at the pre-defined steps an SFCC Job can have — you won’t find anything for saving a file as a local asset. However, you would see a step called &lt;strong&gt;ExecuteScriptModule.&lt;/strong&gt; This step, as its name suggests, allows you to run JavaScript code as a step in your Job. Let’s use this step to point to a new file on our cartridge called a_ssetUpdater.js_, which in turn handles downloading and storing the React library as a local asset of our storefront.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating the Job&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Follow the instructions from yesterday’s post to create a new job. Give the new job the ID &lt;strong&gt;AssetUpdaterJob.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Under the &lt;em&gt;Job Steps&lt;/em&gt; tab, click on &lt;strong&gt;Configure a step.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Select the &lt;strong&gt;ExecuteScriptModule&lt;/strong&gt; step and provide the following details:
* &lt;strong&gt;ID&lt;/strong&gt; : LocalAssetUpdaterStep.
* &lt;strong&gt;ExecuteScriptModule.Module&lt;/strong&gt; : magicCartridge/cartridge/scripts/assetUpdater.js
* &lt;strong&gt;ExecuteScriptModule.FunctionName&lt;/strong&gt; : execute.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Assign&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Adding the Service&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As we learned on day 6, the Services Framework is our way of communicating with the outside world. The &lt;strong&gt;assetUpdater.js&lt;/strong&gt; needs to get the &lt;code&gt;react.production.min.js&lt;/code&gt; file from &lt;a href="https://unpkg.com/react@16/umd/react.production.min.js"&gt;&lt;code&gt;https://unpkg.com/react@16/umd/react.production.min.js&lt;/code&gt;&lt;/a&gt; and for that, we need to create a service and credentials that the script will use:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open your Business Manager and navigate to &lt;strong&gt;Administration&lt;/strong&gt; &amp;gt; &lt;strong&gt;Operations&lt;/strong&gt; &amp;gt; &lt;strong&gt;Services&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click on the &lt;strong&gt;credentials&lt;/strong&gt; tab, and create a new service credential that will point to &lt;a href="https://unpkg.com/react@16/umd/react.production.min.js"&gt;&lt;code&gt;https://unpkg.com/react@16/umd/react.production.min.js&lt;/code&gt;&lt;/a&gt; (I named mine &lt;code&gt;MagicCartridge.Job.Credentials&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Click on the &lt;strong&gt;Services&lt;/strong&gt; tab, and create a new service that will use the newly created &lt;code&gt;MagicCartridge.Job.Credentails&lt;/code&gt; (I named mine &lt;code&gt;MagicCartridge.Job.Service&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;cd to the &lt;code&gt;services&lt;/code&gt; folder of MagicCartridge (&lt;code&gt;cd cartridges/magicCartridge/cartridge/services&lt;/code&gt;), and create a new service initialization file called &lt;code&gt;reactservice.js&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add the following content to the newly created &lt;code&gt;reactservice.js&lt;/code&gt;:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;🐘 If you need a refresher on how to use the Services Framework just head back to Day 6 and Day 7.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Adding assetUpdater.js&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With the job in place, its time to add the script that it will call, &lt;code&gt;assetUpdater.js&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;cd to the root folder of MagicCartridge (&lt;code&gt;cd cartridges/magicCartridge/cartridge&lt;/code&gt;), create a new folder called &lt;code&gt;scripts&lt;/code&gt; and inside of it, create a new file called &lt;code&gt;assetUpdater.js&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add the following content to the newly created &lt;code&gt;assetUpdater.js&lt;/code&gt;:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Let’s break down what's happening here:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lines 1–4&lt;/strong&gt; : Imports the needed classes to get the content of the script (line 4) and to write the file back to the shared library (lines 1–2).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 9&lt;/strong&gt; : Sets the name of the shared library we are going to save the file to. In my case, my site name is Mobile First and my shared library name is &lt;strong&gt;MobileFirstSharedLibrary&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🐘 You can find the names of all the shared libraries on your pod under Administration -&amp;gt; Sites -&amp;gt; Content Libraries.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Lines 10–12&lt;/strong&gt; : Sets the destination path for the asset file. Notice the use of File.LIBRARIES constant — this constant represents the storefront libraries root directory. From here we add the name of our shared library and append the &lt;code&gt;default&lt;/code&gt; folder to it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 13&lt;/strong&gt; : Creates a new &lt;code&gt;fileWriter&lt;/code&gt; instance based on the destination file we defined earlier. We will use this instance’s &lt;code&gt;writeLine&lt;/code&gt; method later in the code to actually write the content to the destination file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lines 16–19&lt;/strong&gt; : These lines deal with fetching the content of the script using the Services Framework, and then, if successful save the content to the file using the &lt;code&gt;fileWriter&lt;/code&gt; instance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lines 23–24&lt;/strong&gt; : These lines call the &lt;code&gt;flush()&lt;/code&gt; method of &lt;code&gt;fileWriter&lt;/code&gt; to flush the buffer used for writing the content, and then the &lt;code&gt;close()&lt;/code&gt; method to close the writer instance. You must call these methods when working with the &lt;code&gt;fileWriter&lt;/code&gt; class in order to properly close the file you are writing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 27&lt;/strong&gt; : Tells the Job framework that our module is done and it should move on to the next Pipelet in the chain.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🤖 It is highly recommended that you go over this script more than once as it introduces a number of new concepts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Deploy &lt;strong&gt;MagicCartridge&lt;/strong&gt; to your instance and let’s take it for a spin!&lt;/p&gt;

&lt;h3&gt;
  
  
  Go Wild 🌈
&lt;/h3&gt;

&lt;p&gt;With the service, the job script, and the cartridge in place, let’s test our newly developed job. Navigate back to the &lt;strong&gt;Jobs&lt;/strong&gt; section in Business Manager, and click on our newly created &lt;strong&gt;AssetUpdaterJob&lt;/strong&gt;. In the top right corner, click on &lt;strong&gt;Run Now,&lt;/strong&gt; and then head over to the &lt;strong&gt;Schedule and History&lt;/strong&gt; tab. If all went well, you should see the beloved OK badge next to your run!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Mrckw7NZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A_JePf4iAYuaocpWHNcaxxw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Mrckw7NZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A_JePf4iAYuaocpWHNcaxxw.png" alt=""&gt;&lt;/a&gt;Successful run — happy life&lt;/p&gt;

&lt;p&gt;But this is not all, you may be asking yourself “this is great, but how do I see the actual file?” By using &lt;code&gt;URLUtils&lt;/code&gt; of course! On your storefront ‘s &lt;code&gt;scripts.isml&lt;/code&gt; file, add the following script element:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script src=_"${URLUtils.staticURL(URLUtils.CONTEXT\_LIBRARY,'','/react.min.js')}"_ type=_"text/javascript"_ async&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;URLUtils.CONTEXT_LIBRARY&lt;/code&gt; will point to the site’s shared library so appending the &lt;code&gt;react.min.js&lt;/code&gt; file name will actually call the file we just got using our job:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--y24AmMND--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AajzgtQGShUV8zHSCKgMFTw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--y24AmMND--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AajzgtQGShUV8zHSCKgMFTw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This wraps up today’s post, and I hope that I managed to show you the amazing value a job can add to your site. Another plus of using such an approach of loading static content on your site is that these assets are also browser cached — meaning users will not hit your backend every time they visit your site but will be able to use a cached version of the library.&lt;/p&gt;

&lt;p&gt;Tomorrow we will wrap up this post series with a really cool and useful subject — templates.&lt;/p&gt;

&lt;p&gt;As always, looking forward to your comments either here or on &lt;a href="https://twitter.com/fullstackj"&gt;Twitter&lt;/a&gt; 😎&lt;/p&gt;




</description>
      <category>salesforce</category>
      <category>sfra</category>
      <category>sfcc</category>
    </item>
    <item>
      <title>11 Days of Salesforce Storefront Reference Architecture (SFRA) — Day 9: Jobs</title>
      <dc:creator>Johnny Tordgeman</dc:creator>
      <pubDate>Thu, 14 May 2020 17:03:57 +0000</pubDate>
      <link>https://forem.com/pxjohnny/11-days-of-salesforce-storefront-reference-architecture-sfra-day-9-jobs-e09</link>
      <guid>https://forem.com/pxjohnny/11-days-of-salesforce-storefront-reference-architecture-sfra-day-9-jobs-e09</guid>
      <description>&lt;h3&gt;
  
  
  11 Days of Salesforce Storefront Reference Architecture (SFRA) — Day 9: Jobs
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7DQdJj6a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A5DM6isuhLHyZ-Vqjq78Q9A.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7DQdJj6a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A5DM6isuhLHyZ-Vqjq78Q9A.jpeg" alt=""&gt;&lt;/a&gt;Photo by &lt;a href="https://unsplash.com/@polarmermaid?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Anne Nygård&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/job?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There may come a time where we want to run code automatically and repeatedly on our storefront (think Linux cron job). Such a job could be to update a local database with values, import or export product catalogs or even update a local resource on our site. SFCC provides us with a wonderful and accurately named framework — the Jobs framework — that enables us to handle these tasks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Automate All the Things!
&lt;/h3&gt;

&lt;p&gt;So what actually is an SFCC job? Well my young Padawan, an SFCC job is really a set of steps (actions) that are executed in order (flow) on a fixed time interval. Executing behind the scenes, jobs do not affect our storefront performance when running and are invisible to the user. Think of a job as a house-elf that does work for you while you sleep.&lt;/p&gt;

&lt;p&gt;Jobs are managed in Business Manager under Administration -&amp;gt; Jobs. This is the central point for anything related to Jobs and also the prime focus of today’s post 🎉&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a Job
&lt;/h3&gt;

&lt;p&gt;A common (and repeated) task for every website is maintaining a site map that provides information about the site structure so search engines will know what to index. Such a task is probably not something you want to deal with manually on a regular basis, which makes it the perfect candidate for our first job:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open your Business Manager and navigate to &lt;strong&gt;Administration&lt;/strong&gt; &amp;gt; &lt;strong&gt;Operations&lt;/strong&gt; &amp;gt;  &lt;strong&gt;Jobs&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;New Job&lt;/strong&gt; (located at the top right corner).&lt;/li&gt;
&lt;li&gt;Fill in the following details and click  &lt;strong&gt;Create&lt;/strong&gt; :&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ID&lt;/strong&gt; : SiteMapJob&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Description&lt;/strong&gt; : A job to update the site map file.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;As soon as the job is created you’ll be greeted with the job configuration page. This is where you can configure (among other things) the two most important properties of a job: when it runs ( &lt;strong&gt;Schedule and History&lt;/strong&gt; ) and what it does ( &lt;strong&gt;Job Steps&lt;/strong&gt; ):&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Y63G-vrt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2Ajg0RoH6WwB_d88Mud5Vssw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Y63G-vrt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2Ajg0RoH6WwB_d88Mud5Vssw.png" alt=""&gt;&lt;/a&gt;Yay, Job configuration page 🎉&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;&lt;em&gt;Creating the Job Steps&lt;/em&gt;&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Steps are the heart of the Job creation process. It’s here that we tell the job what to do, in which order to run its steps and what is the step context (global, specific site, etc.). Let’s add the site map creation step:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click on the &lt;strong&gt;Job Steps&lt;/strong&gt;  tab.&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Configure a step&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;CreateSiteMap,&lt;/strong&gt; enter the following details, and click  &lt;strong&gt;Assign&lt;/strong&gt; :&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ID&lt;/strong&gt; : SiteMapCreationStep&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Description&lt;/strong&gt; : A job step to create the site map.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this point, you might notice that while our new step is created, it is highlighted in red 😱. Do not fear, this is normal! A site map is, as its name suggests, scoped to a site. Our step, however, is currently scoped as &lt;strong&gt;organization&lt;/strong&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click on the blue &lt;strong&gt;Organization&lt;/strong&gt; button on the top left corner of our step and change the &lt;em&gt;scope&lt;/em&gt; dropdown to &lt;strong&gt;Specific Sites&lt;/strong&gt;. Check the site(s) you wish the job to run on and click  &lt;strong&gt;Assign.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XWq5PHUG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AP0kJ6aUAKTI6lNVDLRsw4g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XWq5PHUG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AP0kJ6aUAKTI6lNVDLRsw4g.png" alt=""&gt;&lt;/a&gt;MobileFirst will be the only site my job runs on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scheduling The Job&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now that we configured the “what” let's define the “when”:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click on the &lt;strong&gt;Schedule and History&lt;/strong&gt;  tab.&lt;/li&gt;
&lt;li&gt;Check the &lt;strong&gt;Enabled&lt;/strong&gt; checkbox. This defines our job as a scheduled one.&lt;/li&gt;
&lt;li&gt;Change the &lt;strong&gt;Trigger&lt;/strong&gt; drop-down from &lt;em&gt;Once&lt;/em&gt; to &lt;strong&gt;Recurring Interval&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Every&lt;/strong&gt; set &lt;strong&gt;Amount&lt;/strong&gt; to &lt;em&gt;1&lt;/em&gt; and &lt;strong&gt;Interval&lt;/strong&gt; to &lt;em&gt;Days&lt;/em&gt;. This triggers our new job once a day.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;🐘 There are many other scheduling options you can set in this tab. You can have the job run only on specific days, you can have the interval to be minutes, hours years etc. and you can even set a start and end date for your job if you want to have it run in a specific time frame.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Go Wild 🌈
&lt;/h3&gt;

&lt;p&gt;With everything in place, let’s run our job and see its status!&lt;/p&gt;

&lt;p&gt;On the top right corner, you should see a blue &lt;strong&gt;Run Now&lt;/strong&gt; button. Click it and wait a few seconds. On the bottom of the page, under the &lt;strong&gt;Job History&lt;/strong&gt; section you should see the result of running our job:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AXfhdiQy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AADCaC760DsMkFV6B5xc_ug.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AXfhdiQy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AADCaC760DsMkFV6B5xc_ug.png" alt=""&gt;&lt;/a&gt;The sweet taste of success 🍾&lt;/p&gt;

&lt;p&gt;And there you have it! An automated job that will keep your sitemap fresh and updated, while letting you deal with much more important stuff.&lt;/p&gt;

&lt;p&gt;If you liked this out-of-the-box job we created here, then you are in for a treat tomorrow as we are going to deep dive into the world of custom code job steps.&lt;/p&gt;

&lt;p&gt;As always, looking forward to your comments either here or on &lt;a href="https://twitter.com/fullstackj"&gt;Twitter&lt;/a&gt; 😎&lt;/p&gt;




</description>
      <category>salesforce</category>
      <category>sfcc</category>
      <category>sfra</category>
    </item>
    <item>
      <title>11 Days of Salesforce Storefront Reference Architecture (SFRA) — Day 8: A Tale of Two Events</title>
      <dc:creator>Johnny Tordgeman</dc:creator>
      <pubDate>Wed, 13 May 2020 16:13:51 +0000</pubDate>
      <link>https://forem.com/pxjohnny/11-days-of-salesforce-storefront-reference-architecture-sfra-day-8-a-tale-of-two-events-ae7</link>
      <guid>https://forem.com/pxjohnny/11-days-of-salesforce-storefront-reference-architecture-sfra-day-8-a-tale-of-two-events-ae7</guid>
      <description>&lt;h3&gt;
  
  
  11 Days of Salesforce Storefront Reference Architecture (SFRA) — Day 8: A Tale of Two Events
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PL9GoGVo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AadsRSb1JboA65iyEtws7Iw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PL9GoGVo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AadsRSb1JboA65iyEtws7Iw.jpeg" alt=""&gt;&lt;/a&gt;Photo by &lt;a href="https://unsplash.com/@solomac?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Adam Solomon&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/event?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🎼 Now this is a story all about how&lt;br&gt;
My code got triggered only once&lt;br&gt;
And I’d like to take a minute - just sit right there&lt;br&gt;
I’ll tell you how I spent my day registering to events 🎼&lt;/p&gt;

&lt;p&gt;So far in our SFCC journey, we saw how to write code that gets triggered by an action (for example, browsing to a route); but what if we want to run code that corresponds to an event? SFRA allows us to hook to all kind of events, such as payment events or analytics events, but on this post, we are going to focus on two very special events: &lt;code&gt;onSession&lt;/code&gt; and &lt;code&gt;onRequest&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/bTzFnjHPuVvva/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/bTzFnjHPuVvva/giphy.gif"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Two Events Walk Into a Bar…
&lt;/h3&gt;

&lt;p&gt;SFRA allows us to hook into all kinds of events, for example, &lt;code&gt;app.communication.order.confirmation&lt;/code&gt; that notifies on an order confirmation or &lt;code&gt;app.template.htmlHead&lt;/code&gt;, which, in turn, allows you to add content to the HTML &lt;code&gt;head&lt;/code&gt; element — each handles a specific event in the flow of the storefront life.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;onSession&lt;/code&gt; and &lt;code&gt;onRequest&lt;/code&gt; represents different type of events as they enable us to hook into the life cycle of a storefront request and receive notifications on two different states:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;onSession&lt;/code&gt; is called at the beginning of a new storefront session.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;onRequest&lt;/code&gt; is called every single time a storefront request is received from the client.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Hook Me Up!
&lt;/h3&gt;

&lt;p&gt;Hooking to events is done via a special file called &lt;code&gt;hooks.json&lt;/code&gt;. This file contains hook entries for any number of events we wish to hook to and has to be declared inside of the cartridge’s &lt;code&gt;package.json&lt;/code&gt; file. Each hook entry must contain the following two properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name:&lt;/strong&gt; The extension point (hook name)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Script:&lt;/strong&gt; The script file to call when the event is fired.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;🐘 Make sure that the script file you set for the hook entry contains a function which will run once the event is fired&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For today’s project, we are going to hook to the &lt;code&gt;onRequest&lt;/code&gt; event, check every storefront request for a query param called &lt;code&gt;magic&lt;/code&gt;, and if found, and its value is &lt;code&gt;true&lt;/code&gt;, redirect the user to our &lt;code&gt;Magic-Show&lt;/code&gt; route.&lt;/p&gt;

&lt;p&gt;We begin by declaring a hook entry for &lt;code&gt;onRequest&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;cd to the &lt;code&gt;services&lt;/code&gt; folder of MagicCartridge (&lt;code&gt;cd cartridges/magicCartridge/cartridge/services&lt;/code&gt;), and create a new file named &lt;code&gt;hooks.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add the following content to the newly created &lt;code&gt;hooks.json&lt;/code&gt;:
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s break this JSON down:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 2&lt;/strong&gt; : Declares a key called &lt;code&gt;hooks&lt;/code&gt; and its value as an array of &lt;code&gt;hook&lt;/code&gt; entries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lines 3–6:&lt;/strong&gt; A &lt;code&gt;hook&lt;/code&gt; entry.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 4:&lt;/strong&gt; Sets the name of the event we wish to hook to. In our case we wish to validate every request to our storefront, so we will hook to the &lt;code&gt;onRequest&lt;/code&gt; event.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 5:&lt;/strong&gt; Sets the path and name of the script that will be called once the event fires. We will create the &lt;code&gt;MagicValidator.js&lt;/code&gt; file in the same folder as &lt;code&gt;hooks.json&lt;/code&gt; hence the use of &lt;code&gt;./&lt;/code&gt; to specify the file path.&lt;/p&gt;

&lt;p&gt;With the new &lt;code&gt;hooks.js&lt;/code&gt; file in place, it’s time to register it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;cd to the root folder of &lt;code&gt;MagicCartridge&lt;/code&gt; (&lt;code&gt;cd cartridges/magicCartridge&lt;/code&gt;), and create a new file named &lt;code&gt;package.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add the following content to the newly created file:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Answer the Call!
&lt;/h3&gt;

&lt;p&gt;With &lt;code&gt;hooks.json&lt;/code&gt; registered, SFCC will fire an event for every incoming storefront request and call &lt;code&gt;MagicValidator.js&lt;/code&gt; each time to handle the event. In turn, &lt;code&gt;MagicValidator.js&lt;/code&gt; needs to export a method called &lt;code&gt;onRequest&lt;/code&gt; to handle the event.&lt;/p&gt;

&lt;p&gt;Let’s add &lt;code&gt;MagicValidator.js&lt;/code&gt; to our cartridge and handle the event:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;cd to the services folder of &lt;code&gt;MagicCartridge&lt;/code&gt; (&lt;code&gt;cd cartridges/magicCartridge/cartridge/services&lt;/code&gt;), and create a new file named &lt;code&gt;MagicValidator.js&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add the following content to the newly created &lt;code&gt;MagicValidator.js&lt;/code&gt; file:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;So let’s see what we have here:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 5&lt;/strong&gt; : Verifies the request we are processing is both an HTTP request and a top-level one (we don't want to start validating requests from remote sources on the page).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 6&lt;/strong&gt; : Checks the request’s query params string for a parameter named &lt;code&gt;magic&lt;/code&gt; with the value of &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🐘 This query param check is rather naive and is only used in this case to demonstate the onRequest handler. If you are working with query params in your code — please use something better.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Line 7&lt;/strong&gt; : Redirects the response to the &lt;code&gt;Magic-Show&lt;/code&gt; route using the &lt;code&gt;URLUtils&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 11&lt;/strong&gt; : If the request does not meet all of the above conditions, then pass the request back to SFCC’s request flow by setting its status to OK.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lines 14–16&lt;/strong&gt; : Exports the &lt;code&gt;onRequest&lt;/code&gt; method.&lt;/p&gt;

&lt;h3&gt;
  
  
  Go Wild 🌈
&lt;/h3&gt;

&lt;p&gt;Armed with the new event handler let’s test our new feature! Browse to any RL in your site front (for example &lt;code&gt;/home&lt;/code&gt;). You should notice nothing changes and you are right on the home page as you should be. Now try to add the &lt;code&gt;magic&lt;/code&gt; query params (&lt;code&gt;/home?magic=true&lt;/code&gt;) and watch what happens:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gWu8jntx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ADOcXmvE96YPATS1A48XCHw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gWu8jntx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ADOcXmvE96YPATS1A48XCHw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No matter where we browse in our storefront now, we can go straight to the Magic route just by using a query param.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🐘 What if we want to be able to do this trick only once per session? Which event should we listen to in our hooks.json? (hint: it rhymes with passion)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And there you have it — a way to invoke code based on events and not by user interaction. Just make sure to use this wisely otherwise you will create some heavy load on the request flow, resulting in slow responses from the server.&lt;/p&gt;

&lt;p&gt;Tomorrow we are going to deal with a really fun concept of SFCC — Jobs.&lt;/p&gt;

&lt;p&gt;As always, looking forward to your comments either here or on &lt;a href="https://twitter.com/fullstackj"&gt;Twitter&lt;/a&gt; 😎&lt;/p&gt;




</description>
      <category>sfcc</category>
      <category>sfra</category>
      <category>salesforce</category>
      <category>javascript</category>
    </item>
    <item>
      <title>11 Days of Salesforce Storefront Reference Architecture (SFRA) — Day 7: More Services Framework</title>
      <dc:creator>Johnny Tordgeman</dc:creator>
      <pubDate>Tue, 12 May 2020 16:30:32 +0000</pubDate>
      <link>https://forem.com/pxjohnny/11-days-of-salesforce-storefront-reference-architecture-sfra-day-7-more-services-framework-55k4</link>
      <guid>https://forem.com/pxjohnny/11-days-of-salesforce-storefront-reference-architecture-sfra-day-7-more-services-framework-55k4</guid>
      <description>&lt;h3&gt;
  
  
  11 Days of Salesforce Storefront Reference Architecture (SFRA) — Day 7: More Services Framework
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JCEXxX2V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AdV5yNCHV-2wXVHqB3GMMdQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JCEXxX2V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AdV5yNCHV-2wXVHqB3GMMdQ.jpeg" alt=""&gt;&lt;/a&gt;Photo by &lt;a href="https://unsplash.com/@lefterisk?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Lefteris kallergis&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/service?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/pxjohnny/11-days-of-salesforce-storefront-reference-architecture-sfra-day-6-using-services-framework-1bl1-temp-slug-3392900"&gt;Yesterday&lt;/a&gt; we built our first service using the Services framework, and as much joy as we got from the dad jokes it returned, there was something much less funny about the whole thing: it was static 😱. We had one URL we were calling and that is. No paths, no on-demand headers, no query params — nothing. Well, today we are going to change all that! We are going to build the ultimate dad jokes widget that allows you not only to display a random dad joke (as we did yesterday) but also search a dad joke on a specific term 🤓&lt;/p&gt;

&lt;h3&gt;
  
  
  Searching for the Perfect Dad Joke
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://icanhazdadjoke.com/"&gt;icanhazdadjoke.com&lt;/a&gt; allows us to search for a dad joke using its search endpoint: &lt;a href="https://icanhazdadjoke.com/search"&gt;https://icanhazdadjoke.com/search&lt;/a&gt; and a query param: &lt;code&gt;term&lt;/code&gt;, for the search term. Let’s extend the Services Framework entity we created yesterday to be able to handle the new &lt;code&gt;/Magic-Search&lt;/code&gt; route.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the &lt;code&gt;Magic.js&lt;/code&gt; controller we created yesterday in your IDE.&lt;/li&gt;
&lt;li&gt;Below the &lt;code&gt;Show&lt;/code&gt; handle function, add the following function:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Let’s go over what we have here:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 3&lt;/strong&gt; :Sets &lt;code&gt;magicSearch&lt;/code&gt; as the template that the controller will render (we will create it in the next section).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 4&lt;/strong&gt; : Gets the &lt;code&gt;term&lt;/code&gt; query parameter from the &lt;code&gt;req&lt;/code&gt; object’s &lt;code&gt;querystring&lt;/code&gt; object. This querystring object holds all the query parameters passed to the SFRA controller, and each query parameter can be accessed by specifying its name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 6&lt;/strong&gt; : The &lt;code&gt;getURL()&lt;/code&gt; method returns the URL set in the Services Framework entity credentials. We can use the result of this method to append any path we wish for the service, and in our case, the &lt;code&gt;search&lt;/code&gt; path.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 7&lt;/strong&gt; : This line introduces two new methods: &lt;code&gt;setURL()&lt;/code&gt; and &lt;code&gt;addParam()&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;* &lt;code&gt;setURL()&lt;/code&gt; is used to set the URL for the service call, overriding the static one defined in the Services Framework entity’s credentials. In case the entity does not use any credentials, &lt;code&gt;setURL()&lt;/code&gt; will define the URL the service will call.&lt;/p&gt;

&lt;p&gt;* &lt;code&gt;addParams()&lt;/code&gt; is used to add parameters to the service call. If your service is using the GET method, the parameters will be added as query params. If your service is using the &lt;code&gt;POST&lt;/code&gt;/&lt;code&gt;PUT&lt;/code&gt; method, the parameters will be added as body parameters.&lt;/p&gt;

&lt;p&gt;In our implementation, we use &lt;code&gt;setURL()&lt;/code&gt; to set the service call to the URL we created in line 6, and &lt;code&gt;addParams()&lt;/code&gt; to add the &lt;code&gt;term&lt;/code&gt; parameter needed by &lt;a href="https://icanhazdadjoke.com/"&gt;icanhazdadjoke.com&lt;/a&gt;’s search endpoint.&lt;/p&gt;

&lt;p&gt;Finally, we use the &lt;code&gt;service&lt;/code&gt; object’s &lt;code&gt;call&lt;/code&gt; method to make the actual call to the &lt;a href="https://icanhazdadjoke.com/"&gt;icanhazdadjoke.com&lt;/a&gt; service and store the result with the svcResult variable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lines 8–11&lt;/strong&gt; : If the service call was successful, the &lt;code&gt;svcResult&lt;/code&gt;’s &lt;code&gt;object&lt;/code&gt; property will hold the JSON response from the service. This JSON response contains a &lt;code&gt;results&lt;/code&gt; property that holds an array of &lt;code&gt;joke&lt;/code&gt; objects. We will save &lt;code&gt;results&lt;/code&gt; to a new property on our &lt;code&gt;properties&lt;/code&gt; object called &lt;code&gt;jokes&lt;/code&gt;, and the search term to a new property called &lt;code&gt;term&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 13&lt;/strong&gt; : Calls the render method of the &lt;code&gt;res&lt;/code&gt; object, passing it the &lt;code&gt;properties&lt;/code&gt; object we created in line 2. This object can later be used in an ISML template when it renders.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 14&lt;/strong&gt; : Calls the &lt;code&gt;next()&lt;/code&gt; method passed as an argument to the function, which calls the next middleware in the chain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rendering the Laughs
&lt;/h3&gt;

&lt;p&gt;With the new route handler under our belt, let’s create the ISML template that it will render:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;cd to the &lt;code&gt;templates/default&lt;/code&gt; folder of our cartridge and create a new file called &lt;code&gt;magicSearch.isml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add the following to the new template:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Most of the code in this template is nothing new, so let’s focus on the interesting part — the loop of jokes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lines 14–17&lt;/strong&gt; : These lines introduce the &lt;code&gt;isloop&lt;/code&gt; element. This element enables us to iterate through an array of items, similar to other JavaScript iterators such as &lt;code&gt;forEach&lt;/code&gt;. Here we loop through the jokes collection of the &lt;code&gt;pdict&lt;/code&gt; object (go back and read yesterday’s post if you don’t remember what the &lt;code&gt;pdict&lt;/code&gt; is) while naming each iteration as &lt;code&gt;jokeObject&lt;/code&gt; (as it contains a &lt;code&gt;joke&lt;/code&gt; object, similar to the one we saw yesterday), and add it’s &lt;code&gt;joke&lt;/code&gt; property as a &lt;code&gt;li&lt;/code&gt; element to the unordered list (&lt;code&gt;ul&lt;/code&gt; element) on the page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Go Wild 🌈
&lt;/h3&gt;

&lt;p&gt;In order to test our new route and template we need to upload the cartridge back to SFCC. Using our favorite command &lt;code&gt;npm run uploadCartridge&lt;/code&gt; on the root of our cartridge folder will take care of that.&lt;/p&gt;

&lt;p&gt;To test our search route, use its base url (should be something like &lt;a href="https://&amp;lt;instance%20name&amp;gt;.demandware.net/on/demandware.store/Sites-RefArch-Site/default/Magic-Search"&gt;https://.demandware.net/on/demandware.store/Sites-RefArch-Site/default/Magic-Search&lt;/a&gt;) and append a query parameter named term with the value you want to search for. The end result looks like this: &lt;a href="https://&amp;lt;instance%20name&amp;gt;.demandware.net/on/demandware.store/Sites-RefArch-Site/default/Magic-Search?term=&amp;lt;search%20term"&gt;https://.demandware.net/on/demandware.store/Sites-RefArch-Site/default/Magic-Search?term=&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If all went well you should get a page similar to this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ko7UotsW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/724/1%2AN5ZqE5xgQhyu_0DHWhwM_w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ko7UotsW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/724/1%2AN5ZqE5xgQhyu_0DHWhwM_w.png" alt=""&gt;&lt;/a&gt;Guess which term I searched for here?&lt;/p&gt;

&lt;p&gt;That wraps up our Services Framework fun. Of course, there are other properties you can use with your service, such as &lt;code&gt;.addHeader(name, value)&lt;/code&gt; to add a header to the request, or &lt;code&gt;setRequestMethod(method)&lt;/code&gt; to change the HTTP method (such as &lt;code&gt;POST&lt;/code&gt; or &lt;code&gt;PUT&lt;/code&gt;) or even use the &lt;code&gt;setOutFile(file)&lt;/code&gt; method to set an output file to store the service response, however, we will save working with these for later.&lt;/p&gt;

&lt;p&gt;Tomorrow we will have fun with a very important aspect of working with cartridges — Events (and specifically the &lt;code&gt;onRequest&lt;/code&gt; event).&lt;/p&gt;

&lt;p&gt;As always, looking forward to your comments either here or on &lt;a href="https://twitter.com/fullstackj"&gt;Twitter&lt;/a&gt; 😎&lt;/p&gt;




</description>
      <category>sfra</category>
      <category>sfcc</category>
      <category>salesforce</category>
    </item>
    <item>
      <title>11 Days of Salesforce Storefront Reference Architecture (SFRA) — Day 6: Using Services Framework</title>
      <dc:creator>Johnny Tordgeman</dc:creator>
      <pubDate>Mon, 11 May 2020 15:49:46 +0000</pubDate>
      <link>https://forem.com/pxjohnny/11-days-of-salesforce-storefront-reference-architecture-sfra-day-6-using-services-framework-ie4</link>
      <guid>https://forem.com/pxjohnny/11-days-of-salesforce-storefront-reference-architecture-sfra-day-6-using-services-framework-ie4</guid>
      <description>&lt;h3&gt;
  
  
  11 Days of Salesforce Storefront Reference Architecture (SFRA) — Day 6: Using Services Framework
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Oar0T80B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AM0WJ8OTDiPK2YmD6_d40aQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Oar0T80B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AM0WJ8OTDiPK2YmD6_d40aQ.jpeg" alt=""&gt;&lt;/a&gt;Photo by &lt;a href="https://unsplash.com/@k8townsend?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Kate Townsend&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/service?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A common use case for &lt;a href="https://dev.to/pxjohnny/11-days-of-salesforce-storefront-reference-architecture-sfra-day-4-creating-a-basic-cartridge-5a93-temp-slug-4805464"&gt;cartridges&lt;/a&gt; is to retrieve data from outside sources, and our cartridge is no different. Today, we are going to add a random dad joke below our magic gif because, well, nothing captures the essence of magic like a good dad joke, does it?&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a Service
&lt;/h3&gt;

&lt;p&gt;The Services Framework helps us manage calls to external web services and analyze their performance. It is a site-wide setting and is accessible from the Administration section of the Business Manager. A service definition, which is how we describe and set a service within the Services framework, usually consists of 3 parts: Credentials, Profile, and Service, however in some use cases, the credentials and/or profile parts can be omitted (we will see such a scenario on day 7).&lt;/p&gt;

&lt;p&gt;Let’s go ahead and create our dad joke service:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open your Business Manager and navigate to &lt;strong&gt;Administration&lt;/strong&gt; &amp;gt; &lt;strong&gt;Operations&lt;/strong&gt; &amp;gt; &lt;strong&gt;Services&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click on the &lt;strong&gt;Credentials&lt;/strong&gt; tab and then  &lt;strong&gt;New&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Credentials&lt;/strong&gt; enable us to set the URL (and, if needed, authentication details) for our service. Set the URL to &lt;a href="https://icanhazdadjoke.com/"&gt;https://icanhazdadjoke.com/&lt;/a&gt; and name our credentials MagicCatridge.Dad.Credentials. Click &lt;strong&gt;Apply&lt;/strong&gt; to save &lt;strong&gt;.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--b3QfapoL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AH4SNP9-IOsvXMn2wDe3eOw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--b3QfapoL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AH4SNP9-IOsvXMn2wDe3eOw.png" alt=""&gt;&lt;/a&gt;icanhazdadjoke FTW!&lt;/p&gt;

&lt;p&gt;Next, we will create a profile for our service. The profile enables us to configure connection related settings to our service, such as timeout and rate-limiting.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click on the &lt;strong&gt;Profiles&lt;/strong&gt; tab and then  &lt;strong&gt;New&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Name the new profile &lt;code&gt;MagicCartridge.Dad.Profile&lt;/code&gt; and set its connection timeout to 500. This will ensure that if we cannot connect to the service within 500ms, the connection will be dropped. Click  &lt;strong&gt;Apply&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Finally, let’s create the service itself. Service is where we combine all of the settings for a service, such as its type, status (live/disabled), mode, etc.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click on the &lt;strong&gt;Services&lt;/strong&gt; tab and then  &lt;strong&gt;New&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Set the following:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Name the service &lt;code&gt;MagicCartridge.Dad.Service&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Check the &lt;code&gt;Enabled&lt;/code&gt; checkbox.&lt;/li&gt;
&lt;li&gt;Set the profile to &lt;code&gt;MagicCartridge.Dad.Profile&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set the credentials to &lt;code&gt;MagicCartridge.Dad.Credentials&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click &lt;strong&gt;Apply&lt;/strong&gt; to save.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5BQa7Ysv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AAgdNDOVoxFDfchU5EidUvw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5BQa7Ysv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AAgdNDOVoxFDfchU5EidUvw.png" alt=""&gt;&lt;/a&gt;Our new Dad service! ❤️&lt;/p&gt;

&lt;p&gt;This concludes our dad joke service configuration. But since nothing uses it yet, it’s sitting all alone in the dark waiting for a purpose in life. We will fix this issue next.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initializing the Dad Joke Service
&lt;/h3&gt;

&lt;p&gt;Just like many things in life, before we can use our new dad joke service in the cartridge, we have to initialize it. All of our initialization logic will be handled in a single file, &lt;code&gt;dadjokeservice.js&lt;/code&gt;, created under a services folder within our cartridge:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;cd to the root of the MagicCartridge folder (&lt;code&gt;cd cartridges/magicCartridge/cartridge&lt;/code&gt;), and create a new folder named &lt;code&gt;services&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Inside the new &lt;code&gt;services&lt;/code&gt; folder, create a new file called &lt;code&gt;dadjokeservice.js&lt;/code&gt; and add the following content:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;So what are we seeing here?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1&lt;/strong&gt; : Imports the &lt;code&gt;LocalServiceRegistery&lt;/code&gt; module, which is the base class for creating services.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 3&lt;/strong&gt; : Creates an instance of the &lt;code&gt;MagicCartridge.Dad.Service&lt;/code&gt; we previously defined and saves it to the &lt;code&gt;dadJokeAPIService&lt;/code&gt; variable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lines 4–8&lt;/strong&gt; : Defines a &lt;code&gt;createRequest&lt;/code&gt; method, which allows you to set different properties related to the service. In our example, we set the service method always to be &lt;code&gt;GET&lt;/code&gt; (line 5) and to always have an &lt;code&gt;Accept&lt;/code&gt; header of &lt;code&gt;application/json&lt;/code&gt; (line 6). We end the method by returning the &lt;code&gt;params&lt;/code&gt; object (line 7).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🐘 There are plenty of properties we can set on the svc object other then headers and method. Refer to &lt;a href="https://documentation.b2c.commercecloud.salesforce.com/DOC1/topic/com.demandware.dochelp/DWAPI/scriptapi/html/api/class_dw_svc_HTTPService.html?resultof=%22%73%65%74%52%65%71%75%65%73%74%4d%65%74%68%6f%64%22%20%22%73%65%74%72%65%71%75%65%73%74%6d%65%74%68%6f%64%22%20"&gt;Salesforce Commerce Cloud docs&lt;/a&gt; for more information.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Lines 9–18&lt;/strong&gt; : Defines a &lt;code&gt;parseResponse&lt;/code&gt; method, which allows you to get the raw response of the service call, and parse or manipulate it to your needs. In our example, we try to parse the service call response (&lt;code&gt;httpClient.text&lt;/code&gt;) to JSON (line 13) and save that to the &lt;code&gt;result&lt;/code&gt; variable. If we fail (for example, we got a bad response, etc.) we will save the raw service call response to the &lt;code&gt;result&lt;/code&gt; variable (line 15). We end the method by returning the &lt;code&gt;result&lt;/code&gt; variable (line 17).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lines 21–23&lt;/strong&gt; : Exports the &lt;code&gt;dadJokeAPIService&lt;/code&gt; object.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the Dad Joke Service
&lt;/h3&gt;

&lt;p&gt;To display the result of our service call using the Magic template, we have to call the service on the Magic controller and pass the result to the Magic template on the pipeline dictionary (&lt;code&gt;pdict&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;First, let’s modify our &lt;code&gt;Magic.js&lt;/code&gt; controller to use the dad joke service:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Can you spot the changes from yesterday’s version?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 2&lt;/strong&gt; : Imports the Dad joke service and sets the &lt;code&gt;service&lt;/code&gt; variable to reference it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 5&lt;/strong&gt; : Defines an empty properties object.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 8&lt;/strong&gt; : Uses the &lt;code&gt;service&lt;/code&gt; object’s &lt;code&gt;call&lt;/code&gt; method to make the actual call to the icanhazdadjoke.com service and store its result with the &lt;code&gt;svcResult&lt;/code&gt; variable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lines 9–11&lt;/strong&gt; : If the service call was successful, the &lt;code&gt;svcResult&lt;/code&gt;’s &lt;code&gt;object&lt;/code&gt; property will hold the JSON response from the service. This JSON response contains a &lt;code&gt;joke&lt;/code&gt; property that holds the actual joke. We will save that property to a new property on our &lt;code&gt;properties&lt;/code&gt; object called &lt;code&gt;joke&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 13&lt;/strong&gt; : Calls the render method of the &lt;code&gt;res&lt;/code&gt; object, passing it the &lt;code&gt;properties&lt;/code&gt; object we created on line 5. This object can later be used in an ISML template when it renders. To call this object in an ISML template we will use the &lt;code&gt;pdict&lt;/code&gt; global object. We will see how to use &lt;code&gt;pdict&lt;/code&gt; next.&lt;/p&gt;

&lt;h3&gt;
  
  
  Updating the Template
&lt;/h3&gt;

&lt;p&gt;With all the backend stuff behind us, its time to update the Magic cartridge’s ISML template to actually display the joke.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;cd to the &lt;code&gt;templates/default&lt;/code&gt; folder of our cartridge and open the &lt;code&gt;magic.isml&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;Change the code as follows:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;So what's changed from yesterday?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lines 16–25&lt;/strong&gt; : Adds 3 new CSS classes to be used for the dad joke display.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lines 31–34&lt;/strong&gt; : Adds the container and content of the joke. Notice the use of pdict at &lt;strong&gt;line 33&lt;/strong&gt; - it is the equivalent to the &lt;code&gt;properties&lt;/code&gt; object we set on the render method above. That object had a &lt;code&gt;joke&lt;/code&gt; key and, as such, so does &lt;code&gt;pdict&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Go Wild 🌈
&lt;/h3&gt;

&lt;p&gt;So now we have all the pieces in place let’s see how it renders:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Smtb1QjL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AcjYhb8lx8LmhzW0wg1Zpfw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Smtb1QjL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AcjYhb8lx8LmhzW0wg1Zpfw.png" alt=""&gt;&lt;/a&gt;ROTFL 🤣🤣🤣🤣&lt;/p&gt;

&lt;p&gt;Every time you refresh the page, a call will be made to the dad joke service, grabbing a fresh (and hilarious) joke. That joke will then be stored in an object we pass to the render function, which is then used by the ISML template (via the &lt;code&gt;pdict&lt;/code&gt; object) to render the joke!&lt;/p&gt;

&lt;p&gt;With this, we can wrap up the Services framework for today. Tomorrow we will continue to tinker with Services framework and see how we can make it more dynamic.&lt;/p&gt;

&lt;p&gt;As always, looking forward to your comments either here or on &lt;a href="https://twitter.com/fullstackj"&gt;Twitter&lt;/a&gt; 😎&lt;/p&gt;




</description>
      <category>sfra</category>
      <category>sfcc</category>
      <category>salesforce</category>
    </item>
  </channel>
</rss>
