<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Stuart Sewell</title>
    <description>The latest articles on DEV Community by Stuart Sewell (@stubrew24).</description>
    <link>https://dev.to/stubrew24</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%2F240893%2F5d1b6000-10e2-4057-802b-aa85ea72fcc6.jpeg</url>
      <title>DEV Community: Stuart Sewell</title>
      <link>https://dev.to/stubrew24</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/stubrew24"/>
    <language>en</language>
    <item>
      <title>AWS API Architecture</title>
      <dc:creator>Stuart Sewell</dc:creator>
      <pubDate>Sat, 28 Nov 2020 16:54:25 +0000</pubDate>
      <link>https://dev.to/stubrew24/aws-api-architecture-57j2</link>
      <guid>https://dev.to/stubrew24/aws-api-architecture-57j2</guid>
      <description>&lt;p&gt;I recently worked on a project which involved separating out the API from a monolith application, containerizing and deploying it to AWS. This was my first experience deploying to AWS, so in order to solidify what I learned during this process I've decided to document some of the resources I used and how they interact with one another.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpt54c3ngioormlozwv2j.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpt54c3ngioormlozwv2j.jpg" alt="API Diagram"&gt;&lt;/a&gt;&lt;/p&gt;
This diagram gives an outline of the architecture and the resources used.



&lt;h2&gt;
  
  
  Regions &amp;amp; Availability Zones
&lt;/h2&gt;

&lt;p&gt;Regions are a grouping of AWS resources in a certain geographical location. Within each region are clusters of data centres called availability zones.&lt;/p&gt;

&lt;p&gt;Each region contains multiple availability zones which are physically separate from one another to ensure they are isolated from failures in other zones. The zones are then connected through ultra-low-latency networks.&lt;/p&gt;

&lt;p&gt;Any AWS resource you create must be placed inside a VPC subnet (we'll cover this), which must be located within an availability zone. It's often a good idea to launch resources in multiple availability zones to ensure maximum uptime.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fu8oiopmn8dofqei0dud0.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fu8oiopmn8dofqei0dud0.png" alt="AWS Global Map"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Virtual Private Cloud (VPC)
&lt;/h2&gt;

&lt;p&gt;A VPC is a private virtual network where you can provision AWS resources - in essence your own private area within AWS. You have complete control over this environment including selecting IP addresses, route tables and network gateways.&lt;/p&gt;

&lt;p&gt;Working with subnets we can setup private and public facing environments and control who can access these, and how. A VPC will span all of the availability zones in a region.&lt;/p&gt;

&lt;h2&gt;
  
  
  Subnets
&lt;/h2&gt;

&lt;p&gt;A subnet is a sub section of a network and can be either public or private. The key difference being, public subnets have a route to the internet whereas private ones do not and can only communicate with other subnets within the same VPC.&lt;/p&gt;

&lt;p&gt;One or more subnets to each availability zone, but each subnet must reside entirely within one zone, and cannot span zones.&lt;/p&gt;

&lt;h2&gt;
  
  
  A quick analogy for everything covered so far
&lt;/h2&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fe2gz5n4gs8n22cdt255t.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fe2gz5n4gs8n22cdt255t.jpg" alt="Office Building"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Imagine an office building as being a region - an outer layer that contains many things.&lt;/p&gt;

&lt;p&gt;Each floor is an availability zone. A region can, and most likely will, have more than one zone, much like a building and floors!&lt;/p&gt;

&lt;p&gt;Each department is a VPC, it can span across floors.&lt;/p&gt;

&lt;p&gt;Finally a subnet is the office suite - it can only reside within a single floor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security Groups
&lt;/h2&gt;

&lt;p&gt;Security groups act as a virtual a firewall - they allow and deny traffic. They operate on an instance level rather than a subnet level, so you would apply a security group to each instance you launch.&lt;/p&gt;

&lt;p&gt;You apply rules to each security group to allow traffic to and from its instances. These rules can be modified at any time and will instantly apply to all instances associated with that security group. Multiple security groups can be added to each instance.&lt;/p&gt;

&lt;p&gt;By default all inbounded traffic is denied, and all outbound is allowed.&lt;/p&gt;

&lt;p&gt;To continue with our office building analogy, security groups would be the key cards to access different areas of the building.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3tin63x03kiwyg6dvpm0.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3tin63x03kiwyg6dvpm0.jpg" alt="Queens Guard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Application Load Balancer
&lt;/h2&gt;

&lt;p&gt;An application load balancer is essentially a server which fronts the application and forwards traffic to instances downstream - so in our case the Fargate instances. It's used to spread the load across multiple instances whilst providing a single point of access.&lt;/p&gt;

&lt;p&gt;It will also perform health checks on our instances and if one instance fails the load balancer will direct traffic to the remaining healthy ones. We provide a route - for example '/health', and if this returns a 200 it knows the instance is healthy. &lt;/p&gt;

&lt;p&gt;Other features of the load balancer includes: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Providing support for SSL/HTTPS.&lt;/li&gt;
&lt;li&gt;Works across availability zones, so if one zone goes down the load balancer will move all traffic to the other zones.&lt;/li&gt;
&lt;li&gt;Separating public from private traffic.&lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpag9h4da9xcwby3e159l.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpag9h4da9xcwby3e159l.jpg" alt="Route 66 Highway"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Route 53 &amp;amp;&amp;amp; Internet Gateways
&lt;/h2&gt;

&lt;p&gt;Route 53 is a managed DNS - a collection of rules and records mapping IP addresses to URLs. It can be used for both public domain names and private domains - which can only be resolved by instances within the VPC. Route 53 can also provide load balancing through DNS and limited health checks.&lt;/p&gt;

&lt;p&gt;Internet gateways provide the VPC with a route to the internet. If you think of your home network as a subnet, your modem would be the internet gateway proving access to your ISP and the wider internet.&lt;/p&gt;

&lt;p&gt;Only one internet gateway can be applied to any VPC, and a gateway cannot be detached from a VPC whilst there are any active instances still running on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  AWS Fargate
&lt;/h2&gt;

&lt;p&gt;The final piece of the puzzle is Fargate - "a serverless compute engine for containers that works with both Elastic Container Service (ECS) and Elastic Kubernetes Service". This is where we provision our API containers.&lt;/p&gt;

&lt;p&gt;Fargate is a kind of evolution of Elastic Container Service. It's managed by AWS - removing the need to provision and manage servers, and it scales up and down seamlessly, meaning you only pay for what you use. You can think of it as containers on demand - where everything is managed at a container level.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4sph8sv6dkp6fd2jjmzk.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4sph8sv6dkp6fd2jjmzk.png" alt="AWS Fargate Sandwich Quote"&gt;&lt;/a&gt;&lt;/p&gt;
This quote perfectly surmises the reason to choose Fargate.



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Hopefully this provides a high level understanding of some of the resources that go into setting up a containerized application on AWS. Of course, the best way to fully grasp these concepts is to dive in and get hands on.&lt;/p&gt;

&lt;p&gt;Here are some resources I have found to be particularly helpful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/playlist?list=PLv2a_5pNAko0Mijc6mnv04xeOut443Wnk" rel="noopener noreferrer"&gt;Linux Academy - AWS Essentials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://acloudguru.com/aws-cloud-training" rel="noopener noreferrer"&gt;A Cloud Guru - Cloud Training&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/playlist?list=PLt1SIbA8guuusDOIqQuiFKerF_4_nQ_Xs" rel="noopener noreferrer"&gt;Stephane Maarek - AWS Certified Solutions Architect Associate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;And of course, the &lt;a href="https://docs.aws.amazon.com" rel="noopener noreferrer"&gt;AWS Documentation&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>cloud</category>
      <category>architecture</category>
      <category>api</category>
    </item>
    <item>
      <title>Redux Saga</title>
      <dc:creator>Stuart Sewell</dc:creator>
      <pubDate>Fri, 06 Mar 2020 13:21:00 +0000</pubDate>
      <link>https://dev.to/stubrew24/redux-saga-1l7l</link>
      <guid>https://dev.to/stubrew24/redux-saga-1l7l</guid>
      <description>&lt;p&gt;I was recently given a technical test which required the use of Redux-Saga. Prior to this I’d had some experience using Redux but sagas were a new concept to me. After a run through of the &lt;a href="https://redux-saga.js.org/docs/introduction/BeginnerTutorial.html"&gt;beginner tutorial in the docs&lt;/a&gt; and a look from some example code I attempted the test was some success. This blog will attempt to solidify what I have learnt by building a small project.&lt;/p&gt;

&lt;h3&gt;
  
  
  What even is Redux Saga?
&lt;/h3&gt;

&lt;p&gt;Redux-Saga is a Redux middleware that attempts to manage side affects in a simple and testable way. It takes advantage of generator functions which were made possible in &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*"&gt;JavaScript ES6,&lt;/a&gt; to enable asynchronous code which can be tested as easily as synchronous code.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Project
&lt;/h3&gt;

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

&lt;p&gt;The project we’re building is a &lt;a href="https://reactjs.org/"&gt;React&lt;/a&gt; app which renders a randomly generated picture of a cat alongside a quote every time the user clicks on a button.&lt;/p&gt;

&lt;h3&gt;
  
  
  See the finished app here:
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://catsandquotes.stuartsewell.dev"&gt;Cats and Quotes&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;This repo is &lt;a href="https://github.com/stubrew24/catsandquotes/"&gt;available here&lt;/a&gt; if you want to code along, clone it down and run npm install. This will give us a base React app with some additional styling. Alternatively, set up a new React app by running npx create-react-app catsandquotesand implement your own styling. Once the React has finished setting up move into the directory and start the app cd catsandquotes &amp;amp;&amp;amp; npm start.&lt;/p&gt;

&lt;p&gt;Once you have a React app up and running install the dependencies with the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm i redux react-redux redux-saga&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;These are all of the dependencies we will need for this project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Actions
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;mkdir src/store &amp;amp;&amp;amp; touch src/store/actions.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Let’s start with the actions, as these will be frequently referred to throughout the app. Start by creating a store directory inside src and inside this create an actions.js file.&lt;/p&gt;

&lt;p&gt;The contents of this file is shown below. We have three actions API_REQUEST API_SUCCESS and API_FAILURE, by declaring these as constants we protect ourselves against typos later on. We also create three corresponding helper functions which return our actions formatted for correctly for Redux to consume.&lt;/p&gt;


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


&lt;h3&gt;
  
  
  Reducer
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;touch src/store/reducer.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The reducer is going to manage the application state. It will be responsible for setting the initial state, as well as updating and returning state. We’ll start by creating a reducer.js file inside the store directory, importing our actions and setting the initial state:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { API_REQUEST, API_SUCCESS, API_FAILURE } from './actions';

const initialState = {
  catImageUrl: '',
  quoteText: '',
  fetching: false,
  error: null
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then we set up the reducer itself. We have three options, plus the default which returns the state unchanged.&lt;/p&gt;

&lt;p&gt;API_REQUEST: any time we make a request to the API we call the API_REQUEST action which sets fetching to true, and error to null (in case there is a previous error still in state).&lt;/p&gt;

&lt;p&gt;API_SUCCESS: if our API call is successful we call the API_SUCCESS action which resets our fetching state to false sets the catImageUrl and quoteText returned from the API’s.&lt;/p&gt;

&lt;p&gt;API_FAILURE: should there be an error with the API call, the API_FAILURE action will reset fetching to false and return the error message.&lt;/p&gt;

&lt;h3&gt;
  
  
  Saga
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;touch src/store/saga.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now onto the crux of the project, the saga! This will be responsible for making our API calls and handling the success or failure of this.&lt;/p&gt;

&lt;p&gt;Add the following imports to the top of the file, we’ll take a closer look at call, put and takeLatest further down.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { apiSuccess, apiFailure, API_REQUEST } from './actions';
import { call, put, takeLatest } from 'redux-saga/effects';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We’ll start by writing our API request functions, I’m using the &lt;a href="https://thecatapi.com/"&gt;thecatapi.com&lt;/a&gt; for the cat images and &lt;a href="https://ron-swanson-quotes.herokuapp.com/"&gt;ron-swanson-quotes.herokuapp.com&lt;/a&gt; for the quotes. We’re using simple async/await functions for this.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const catFetch = async () =&amp;gt; {
  const res = await fetch('https://api.thecatapi.com/v1/images/search');
  const data = await res.json();
  return data[0].url;
};

const quoteFetch = async () =&amp;gt; {
  const res = await fetch('https://ron-swanson-quotes.herokuapp.com/v2/quotes');
  const data = await res.json();
  return data[0];
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next we have our API saga function. This is a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*"&gt;generator function&lt;/a&gt; which is going to do all of the heavy lifting for us. We define a generator function by adding an asterisk (*) at the end of the function keyword. &lt;em&gt;It’s worth noting here that we cannot define generators with the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions"&gt;arrow function&lt;/a&gt; syntax.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;function* apiSaga() { ... }&lt;/p&gt;

&lt;p&gt;We wrap the saga in a try-catch block to enable us to easily handle any errors that may arise.&lt;/p&gt;

&lt;p&gt;try { ... } catch (error) { ... }&lt;/p&gt;

&lt;p&gt;Inside the try block we perform the API fetches then call the API_SUCCESS action.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;try {
  const catImageUrl = yield call(catFetch);
  const quoteText = yield call(quoteFetch);
  const payload = { catImageUrl, quoteText };
  yield put(apiSuccess(payload));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here the first line is calling the catFetch function and saving the return value to a const.&lt;/p&gt;

&lt;p&gt;“The yield keyword is used to pause and resume a generator function” — &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield"&gt;MDN Web Docs&lt;/a&gt;. This tells our saga to pause whilst we perform the asynchronous API call and continue when we have a response.&lt;/p&gt;

&lt;p&gt;call is part of the Redux-saga API. It “creates an Effect description that instructs the middleware to call the function” — &lt;a href="http://redux-saga.js.org"&gt;Redux Saga Docs&lt;/a&gt;. Simply, it tells our saga to call the catFetch function.&lt;/p&gt;

&lt;p&gt;The second line is the same as the first but calling the quotes API. And the third line creates a payload object using &lt;a href="https://alligator.io/js/object-property-shorthand-es6/"&gt;ES6 object shorthand&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The final line of our try block uses the Redux-saga put method which “instructs the middleware to schedule the dispatching of an action to the store.” — &lt;a href="http://redux-saga.js.org"&gt;Redux Saga Docs&lt;/a&gt;. We’re telling the saga to call the Redux API_SUCCESS action with payload from the API calls.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;catch (error) {
  yield put(apiFailure(error));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If there is an error without API fetches we call the Redux API_FAILURE action and pass the error as the payload.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export function* rootSaga() {
  yield takeLatest(API_REQUEST, apiSaga);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The final part of out saga file is the rootSaga generator. The root saga is responsible for starting all of our sagas (in our case we only have one) and allows us to export just one saga. We would see the real benefit of this if we had multiple sagas being defined and exported.&lt;/p&gt;

&lt;p&gt;Notice that we are using takeLatest here, this “forks a saga on each action dispatched to the Store that matches pattern. And automatically cancels any previous saga task started previously if it's still running.” — &lt;a href="http://redux-saga.js.org"&gt;Redux Saga Docs&lt;/a&gt;. It prevents the same saga from being multiple times simultaneously, by cancelling any previous instances every time it is called.&lt;/p&gt;

&lt;p&gt;Full code for src/store/saga.js below:&lt;/p&gt;

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

&lt;p&gt;touch src/store/index.js&lt;/p&gt;

&lt;p&gt;It’s time to bring all of these elements together to build and export our Redux Store. We start with our imports, the reducer and rootSaga we previously created and the rest we’ll cover when we implement them.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import createSagaMiddleware from 'redux-saga';
import { createStore, compose, applyMiddleware } from 'redux';
import { reducer } from './reducer';
import { rootSaga } from './saga';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If you don’t already have Redux DevTools installed on your browser head over to &lt;a href="https://extension.remotedev.io/#installation"&gt;extension.remotedev.io&lt;/a&gt;. These will greatly help with debugging, and give a great insight into the Redux process in your app.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const reduxtools =
  window.__REDUX_DEVTOOLS_EXTENSION__ &amp;amp;&amp;amp; window.__REDUX_DEVTOOLS_EXTENSION__();

const sagaMiddleware = createSagaMiddleware();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The first line checks if DevTools are installed, and if so invokes them. The second line calls on the &lt;a href="https://redux-saga.js.org/docs/api/#createsagamiddlewareoptions"&gt;createSagaMiddleware&lt;/a&gt; function to create a Redux middleware and connect our saga to the Redux Store.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const store = createStore(
  reducer,
  compose(applyMiddleware(sagaMiddleware), reduxtools)
);

sagaMiddleware.run(rootSaga);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Finally it’s time to create our Store and start our saga middleware. &lt;a href="https://redux.js.org/api/createstore"&gt;createStore&lt;/a&gt; first takes in our reducer and secondly takes an enhancer. We want to pass in two enhancers — our middleware, and the devtools, so we can use the Redux &lt;a href="https://redux.js.org/api/compose/"&gt;compose&lt;/a&gt; function two pass in multiple options. Inside compose we pass the Redux applyMiddleware function which will connect our saga to the Redux Store.&lt;/p&gt;

&lt;p&gt;The final line here calls run on our saga middleware and passes in our saga.&lt;/p&gt;

&lt;p&gt;Full code for src/store/index.js below:&lt;/p&gt;

&lt;h3&gt;
  
  
  Bringing it all together
&lt;/h3&gt;

&lt;p&gt;The final thing we need to do is connect our Redux Store to our React app.&lt;/p&gt;

&lt;p&gt;First we update src/index.js by importing Provider from react-redux and the Store we just created. Wrap our App component with the Redux Provider and pass in the store we created.&lt;/p&gt;

&lt;p&gt;The final part of the puzzle is adding Redux to our App component. We’ll use &lt;a href="https://reactjs.org/docs/hooks-intro.html"&gt;React Hooks&lt;/a&gt; to set Redux in our app.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { apiRequest } from './store/actions';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Start by importing useEffect from ‘react’ — this is the hooks equivelant of componentDidMount, useSelector and useDispatch from ‘react-redux’ and our apiRequest action function.&lt;/p&gt;

&lt;p&gt;The hooks implementation of Redux is much cleaner and more precise than it previously was. We can bring in our state and dispatch in just two lines:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { catImageUrl, quoteText } = useSelector(state =&amp;gt; state);
const dispatch = useDispatch();

const handleClick = () =&amp;gt; dispatch(apiRequest());
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The first line uses ES6 syntax to extract catImageUrl and quoteText from the state object provided by useSelector. The second line set up our Redux dispatch function. The last line passes our apiRequest action to the dispatch function inside a handleClick function.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;useEffect(() =&amp;gt; {
    dispatch(apiRequest());
  }, [dispatch]);

return (
    &amp;lt;div className="container"&amp;gt;
      &amp;lt;h1&amp;gt;Cats + Quotes&amp;lt;/h1&amp;gt;
      &amp;lt;div className="row"&amp;gt;
        &amp;lt;img src={catImageUrl} alt="A cat" /&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;blockquote&amp;gt;{quoteText}&amp;lt;/blockquote&amp;gt;
      &amp;lt;button onClick={handleClick}&amp;gt;Gimme more...&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We’ll also pass the dispatch to useEffect to make sure an API request is made as soon as we load the page. Finally, we return the contents of the App component, passing the handleClick function to our ‘more’ button so the user can load a new picture and quote.&lt;/p&gt;

&lt;p&gt;The full App component is shown below.&lt;/p&gt;

&lt;p&gt;That’s our &lt;a href="https://catsandquotes.stuartsewell.dev/"&gt;Cats and Quotes app&lt;/a&gt; complete. Some missing features that I will look to work on in future include handling errors inside the app, as well as some testing of both the React app and the sagas.&lt;/p&gt;

&lt;p&gt;Thanks for reading…&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>redux</category>
    </item>
  </channel>
</rss>
