{"@attributes":{"version":"2.0"},"channel":{"title":"DEV Community: George Offley","description":"The latest articles on DEV Community by George Offley (@georgeoffley).","link":"https:\/\/dev.to\/georgeoffley","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%2F3198%2Fccc96445-59d2-481e-b8ad-a44e5e91b8af.jpg","title":"DEV Community: George Offley","link":"https:\/\/dev.to\/georgeoffley"},"language":"en","item":[{"title":"Easy CDN using S3 and CloudFront","pubDate":"Wed, 07 Sep 2022 17:50:46 +0000","link":"https:\/\/dev.to\/aws-builders\/easy-cdn-using-s3-and-cloudfront-5ghf","guid":"https:\/\/dev.to\/aws-builders\/easy-cdn-using-s3-and-cloudfront-5ghf","description":"<h3>\n  \n  \n  Introduction\n<\/h3>\n\n<p>Since I started blogging, I have been using S3 to store images for my blog. I just used the publicly accessible S3 Link. Easy, simple, no problem.<\/p>\n\n<p>I did this for a long time without realizing two things.<\/p>\n\n<ol>\n<li><p>I was leaving some performance on the table by not utilizing a content delivery network. <\/p><\/li>\n<li><p>I was probably using the least secure method for serving images.<\/p><\/li>\n<\/ol>\n\n<p>So I combined S3 with CloudFront to create a more secure and performant static asset delivery workflow.<\/p>\n\n<p>My only regret is not taking controlled measurements of my image serving times, as once this was completed, my static assets loaded much faster. Regardless let\u2019s go through what I did.<\/p>\n\n<h3>\n  \n  \n  Setup\n<\/h3>\n\n<p>I already had an S3 bucket set up, but it is a simple process if you don't.<\/p>\n\n<p>Sign in to your AWS console and navigate to the S3 management screen.<\/p>\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fslc67y31hpsodslaimj2.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fslc67y31hpsodslaimj2.png\" alt=\"S3 Page\" width=\"800\" height=\"261\"><\/a><\/p>\n\n<p>You can create a new bucket by hitting the \u201cCreate bucket\u201d button.<\/p>\n\n<p>You can leave all the default options for the bucket. We\u2019ll take an extra step to ensure only our new distribution has access to our bucket.<\/p>\n\n<p>After completing this, head over to the CloudFront screen in AWS and hit the \u201cCreate distribution\u201d button.<\/p>\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6myz1ss09183iy0vj33z.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6myz1ss09183iy0vj33z.png\" alt=\"CloudFront page\" width=\"800\" height=\"222\"><\/a><\/p>\n\n<p>The first option is setting the origin. Clicking that input box brings down a list of your S3 buckets; I chose the one I made earlier.<\/p>\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdrpeex8eg74q7aiwzarq.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdrpeex8eg74q7aiwzarq.png\" alt=\"Setting the origin\" width=\"800\" height=\"631\"><\/a><\/p>\n\n<p>There are dozens of different settings for the distribution that you can go through and customize to fit your situation, but I want to focus on the \u201cOrigin access\u201d section. I clicked the option for \u201cOrigin access control settings,\u201d which has you choose an origins access control template. I created a new one for this purpose.<\/p>\n\n<p>Once you click the create button, you\u2019ll be taken back to the main page while the distribution starts deploying. At the top, you\u2019ll see a button to copy the bucket policy for S3. Clicking this button will copy some JSON code into your clipboard meant to be copied into your S3 permissions tab. The console will also have a convenient link to open the \u201cPermissions\u201d tab in your S3 bucket.<\/p>\n\n<p>Scroll down to the \u201cBucket policy\u201d section, where you can hit the \u201cEdit\u201d button and copy in the JSON CloudFront provided.<\/p>\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0xjbqc3zrouk1z18ut63.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0xjbqc3zrouk1z18ut63.png\" alt=\"Bucket policy section in S3 bucket\" width=\"800\" height=\"237\"><\/a><\/p>\n\n<p>Note: I had to go to <a href=\"https:\/\/jsonformatter.org\/json-pretty-print\" rel=\"noopener noreferrer\">this site<\/a> and copy in the JSON to better format it for S3 to accept the settings.<\/p>\n\n<p>Once you do that, you click \u201cSave changes,\u201d and you\u2019re done. You can now serve images of Serena being fantastic in a performant and scalable way. <\/p>\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkj9e0fk75xbh92s6yi1o.gif\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkj9e0fk75xbh92s6yi1o.gif\" alt=\"Serena being fantastic\" width=\"480\" height=\"480\"><\/a><\/p>\n\n<p>Just note that you\u2019ll have to go back to distribution and get the distribution URL. You just add the route to your S3 assets from there, like below, and you\u2019re golden.<\/p>\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjus9l8ztkvsbzzsggx95.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjus9l8ztkvsbzzsggx95.png\" alt=\"URL breakdown for CloudFront assets\" width=\"800\" height=\"450\"><\/a><\/p>\n\n<h3>\n  \n  \n  Conclusion\n<\/h3>\n\n<p>An easy solution to hosting images and whatever else you want. I have some issues with it that I will get into, but so far, so good.<\/p>\n\n<p>-George<\/p>\n\n","category":["aws","cloudfront","s3","beginners"]},{"title":"Browser Testing With Cypress","pubDate":"Sun, 17 Jul 2022 13:52:43 +0000","link":"https:\/\/dev.to\/georgeoffley\/browser-testing-with-cypress-33e6","guid":"https:\/\/dev.to\/georgeoffley\/browser-testing-with-cypress-33e6","description":"<h3>\n  \n  \n  Introduction\n<\/h3>\n\n<p>When I write code, I try to remember that everything is broken until proven otherwise. I\u2019ve been shifting my learning to browser-based platforms that I am working on and with that shift, browser tests have started to be folded into that mindset.<\/p>\n\n<p><a href=\"https:\/\/www.cypress.io\/\">Cypress<\/a> is a tool for browser tests that I\u2019ve started learning, and it\u2019s been an interesting week. I\u2019ve <a href=\"https:\/\/georgeoffley.com\/blog\/dockerizing-system-tests-with-selenium.html\">written about browser testing before<\/a>, so this will be a bit less comprehensive and will mostly be my thoughts on the tool and how useful I think it is. Complete tutorials for creating end-to-end browser testing solutions using Cypress can be <a href=\"https:\/\/docs.cypress.io\/guides\/overview\/why-cypress\">found in their docs<\/a>.<\/p>\n\n<h3>\n  \n  \n  Browser Tests\n<\/h3>\n\n<p>Testing has a lot of different connotations. In this context, browser tests are tests that try to use your app and tell you if something is broken. Cypress is one such tool, but there are many others.  <\/p>\n\n<h3>\n  \n  \n  Cypress Setup\n<\/h3>\n\n<p>Compared to something like Selenium, the setup was simple. Cypress advertises as an all-in-one solution for end-to-end testing. And so far, that\u2019s been true. Selenium requires a web driver and external resources to function, whereas Cypress seems to work quickly out of the box.<\/p>\n\n<p>Their docs suggest setting up the cypress commands in your <code>package.json<\/code> file for easier running. This is a good approach to test your app how you need to.<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--llXdbDo9--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/d4kma4si4pw0z.cloudfront.net\/2022-07-16-browser-testing-with-cypress\/package-json-scripts-cypress-open.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--llXdbDo9--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/d4kma4si4pw0z.cloudfront.net\/2022-07-16-browser-testing-with-cypress\/package-json-scripts-cypress-open.png\" alt=\"Example snippit of a cypress command which can be written into the local package.json file.\" width=\"678\" height=\"164\"><\/a><\/p>\n\n<p>To help with your setup, you have access to their testing GUI.<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--tzDjpXtj--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/docs.cypress.io\/_nuxt\/img\/launchpad.fcc7cac.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--tzDjpXtj--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/docs.cypress.io\/_nuxt\/img\/launchpad.fcc7cac.png\" alt=\"Cypress testing GUI found on the Cypress docs website.\" width=\"880\" height=\"612\"><\/a><\/p>\n\n<p>This is a vast improvement over other tools I\u2019ve learned since everything can be set up in a GUI, including choosing a browser to do your testing on.<\/p>\n\n<p>I\u2019ve only been able to try end-to-end testing, but I\u2019d like to dive a little more into component testing. More to come.<\/p>\n\n<h3>\n  \n  \n  Simple Cypress Tests\n<\/h3>\n\n<p>So the tests themselves are relatively simple. The scripts only need a few lines of code, as most of the setup is in the project config and support files. Another great advantage over other tools I\u2019ve tried so far.<\/p>\n\n<p>A test might look something like this.<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--WbWobI7c--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/d4kma4si4pw0z.cloudfront.net\/2022-07-16-browser-testing-with-cypress\/simple-test.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--WbWobI7c--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/d4kma4si4pw0z.cloudfront.net\/2022-07-16-browser-testing-with-cypress\/simple-test.png\" alt=\"A simple test taken from Cypress docs to test if a website loads.\" width=\"680\" height=\"164\"><\/a><\/p>\n\n<p>The above test, taken from their docs, is put into a <code>describe()<\/code> block. This gives us flexibility in creating testing classes and organizing our tests. Within that block is another block, the <code>it()<\/code> block, which is our test itself. We can be as granular as we want with our tests. For example, if we want to write an <code>it()<\/code> block for every step in an end-to-end test, we can do so with the confidence that we\u2019ll see which stage failed.<\/p>\n\n<p>The <code>cy.visit()<\/code> is a command and assertion. So, in this example, if a website is not sending a response, we can see this test fail. So this gives us the flexibility to write out the exact behavior we expect.<\/p>\n\n<p>So we can add all the steps needed to test a part of our app. Like so.<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--ajz1L905--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/d4kma4si4pw0z.cloudfront.net\/2022-07-16-browser-testing-with-cypress\/full-test.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--ajz1L905--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/d4kma4si4pw0z.cloudfront.net\/2022-07-16-browser-testing-with-cypress\/full-test.png\" alt=\"Complete Cypress test example from Cypress docs\" width=\"680\" height=\"454\"><\/a><\/p>\n\n<p>This example, also taken from their docs, takes advantage of everything described above. It also introduces chaining, which we can use for multi-step processes.<\/p>\n\n<h3>\n  \n  \n  Testing GUI\n<\/h3>\n\n<p>OK, on to some of the stuff that makes Cypress a fun tool to dive into. Namely the GUI.<\/p>\n\n<p>Browser-based engineering is still a space I\u2019ve only been in for a while, so this might be new to me, but adding a browser tool for developing your apps blows me away. Let me tell you why.<\/p>\n\n<p>So we wrote the test above. Great. Now we need directions to tell a Cypress how to navigate our app. So we need some selectors, which are always murky to me as relying on class selectors is a brittle test that can be broken with a new release. We need something better, and it\u2019s not always clear what that \u201cbetter\u201d may be. So in comes the testing playground.<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--HCg454A5--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880\/https:\/\/d4kma4si4pw0z.cloudfront.net\/2022-07-16-browser-testing-with-cypress\/cypress-browser-gui.gif\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--HCg454A5--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880\/https:\/\/d4kma4si4pw0z.cloudfront.net\/2022-07-16-browser-testing-with-cypress\/cypress-browser-gui.gif\" alt=\"Cypress Testing Playground taken from the Cypress docs showing all the browser tools.\" width=\"600\" height=\"322\"><\/a><\/p>\n\n<p>The above, also taken from their docs, demonstrates what made using Cypress enjoyable. Their testing suite gives you valuable tools like a real-time test runner, a test builder, a time machine so you can go through each testing step to see where issues might pop up, and an advanced selector playground.<\/p>\n\n<p>This tool does a great job of helping you create robust selectors for your test. It allows you to hover over elements, highlight them, and the selector playground will provide you with their best guess for a <code>cy.get()<\/code> command so tests can be filled out quickly.<\/p>\n\n<h3>\n  \n  \n  Some More Cool Stuff\n<\/h3>\n\n<p>Just a couple more things I wanted to mention. One was how easy their API makes it to <a href=\"https:\/\/docs.cypress.io\/api\/cypress-api\/custom-commands\">creating new commands in their API<\/a> for common functionality to your testing apparatus.<\/p>\n\n<p>For example, we created one which goes to our site, types in login info, and clicks the login button. Now we have all that functionality in a single command for use in any test we need authentication for. Before long we\u2019ll have tons of them so we can focus on testing our platform's behavior.<\/p>\n\n<p>Another was using what they call <a href=\"https:\/\/docs.cypress.io\/api\/commands\/fixture\">fixtures<\/a> for injecting static data into your tests, which I love. Static data, like login credentials, names, etc, are much cleaner when you can create a JSON file and utilize the existing API to access the necessary values. I love that; it makes maintenance so much easier.<\/p>\n\n<h3>\n  \n  \n  Conclusion\n<\/h3>\n\n<p>After all that, I can confidently say I enjoy writing tests using Cypress. It allows me to write tests the right (easy) way. Testing is often not something people think about. So make it easy to do, and Cypress does that. I\u2019m excited to continue learning.<\/p>\n\n<p>-George<\/p>\n\n","category":["testing","javascript","webdev"]},{"title":"Context In React","pubDate":"Tue, 19 Apr 2022 00:44:38 +0000","link":"https:\/\/dev.to\/georgeoffley\/context-in-react-4fda","guid":"https:\/\/dev.to\/georgeoffley\/context-in-react-4fda","description":"<h2>\n  \n  \n  Table Of Contents\n<\/h2>\n\n<ul>\n<li>Introduction<\/li>\n<li>Data In React<\/li>\n<li>Context In React<\/li>\n<li>Context In Use<\/li>\n<li>Conclusion<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Introduction <a><\/a>\n<\/h3>\n\n<p>React offers the ability to build out web applications quickly. One of the details of this strategy includes passing data to different components in the <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Document_Object_Model\/Introduction\" rel=\"noopener noreferrer\">DOM<\/a>. This can consist of needed data to build features, states of a component, and anything you can think of.<\/p>\n\n<h3>\n  \n  \n  Data In React <a><\/a>\n<\/h3>\n\n<p>One great pattern in React is how data can be passed through the different components. However, this can get messy. <\/p>\n\n<p>An application might be broken down like below.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-04-18-context-in-react%2Fbasic-app-layout.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-04-18-context-in-react%2Fbasic-app-layout.png\" alt=\"Basic layout of an app\"><\/a><\/p>\n\n<p>A collection of components. Some of these components return other components. These are called parent components, and their children are nested components. <\/p>\n\n<p>We can pass data back and forth throughout the lifetime of each component. Working with only props, for example, lets us pass data down the tree to the components that need it. However, this can present a problem.<\/p>\n\n<p>Using props or properties is a great way to handle data. However, the deeper the component is buried, the more you have to pass the props down. This is called <a href=\"https:\/\/beta.reactjs.org\/learn\/passing-data-deeply-with-context#the-problem-with-passing-props\" rel=\"noopener noreferrer\">prop drilling<\/a>.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-04-18-context-in-react%2Freact-props-only.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-04-18-context-in-react%2Freact-props-only.png\" alt=\"React app with only Props\"><\/a><\/p>\n\n<p>Using the workflow above, we have a couple of nested components passing the <code>Username<\/code> prop down the tree. The <code>Page<\/code> and <code>MainContent<\/code> props are just passing down the props used by the <code>UserCard<\/code> component like a vertical <a href=\"https:\/\/youtu.be\/uviAFx4K78Y\" rel=\"noopener noreferrer\">game of telephone<\/a>.<\/p>\n\n<p>Now combine this with having to scale out your context to include hundreds of bits of data or state, which need to be passed down to various components at various levels of the tree, and we\u2019ve got a problem.<\/p>\n\n<h3>\n  \n  \n  Context in React <a><\/a>\n<\/h3>\n\n<p><a href=\"https:\/\/reactjs.org\/docs\/context.html\" rel=\"noopener noreferrer\">Context<\/a> solves the problem by allowing us to pass down data without relying on continually passing props through components. Context in React should be used handling global data that does not have to change often. Using context to keep track of our username state improves the workflow by allowing components to use context as needed without passing it down the tree. Pictured below.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-04-18-context-in-react%2Freact-context.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-04-18-context-in-react%2Freact-context.png\" alt=\"React with Context\"><\/a><\/p>\n\n<p>As illustrated above, we can provide the context to one component, and the children component will be able to access the context regardless of the level they are at. All without needing to have their parent components pass the data down.<\/p>\n\n<h3>\n  \n  \n  Context In Use <a><\/a>\n<\/h3>\n\n<p>So let\u2019s look at an example of context. I created a small React app and just made some barebones components. The first file we should check out is the <code>App<\/code> component.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-04-18-context-in-react%2Fapp.js.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-04-18-context-in-react%2Fapp.js.png\" alt=\"App.js file\"><\/a><\/p>\n\n<p>There are some lines of note, as you\u2019ve undoubtedly seen, and then some other stuff needed for using context. The first out-of-place thing is using the React function <code>React.createContext()<\/code>, which we use to create a context object. We also made a <a href=\"https:\/\/reactjs.org\/docs\/context.html#contextprovider\" rel=\"noopener noreferrer\"><em>provider<\/em><\/a> for our context object and wrapped our <code>Page<\/code> component in it.<\/p>\n\n<p>Context works using Providers and Consumers. In this case, we are looking to provide the context to our app for consumption by the components. So we use the provider tag, which every context object has, to pass in the <code>value<\/code> string to our nested components.<\/p>\n\n<p>The <code>value<\/code> attribute is a prop that the provider accepts and can pass down the tree. Many consumers can subscribe to one provider, and we\u2019ll talk about that more. <\/p>\n\n<p>We're not passing anything to the <code>Page<\/code> component except the <code>Header<\/code> and <code>MainContent<\/code> components.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-04-18-context-in-react%2Fpage.js.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-04-18-context-in-react%2Fpage.js.png\" alt=\"Page.js component\"><\/a><\/p>\n\n<p>Let\u2019s look at the <code>Header<\/code> component. <\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-04-18-context-in-react%2Fheader.js.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-04-18-context-in-react%2Fheader.js.png\" alt=\"Header.js component\"><\/a><\/p>\n\n<p>The header is a regular old React component. However, we use the React hook <code>React.createContent()<\/code> to subscribe to the <code>UserContext<\/code> object that we import into this component from the <code>App<\/code> component. We can now use the curly brackets to pass in the <code>userNameContext<\/code> into the JSX being returned by the component.<\/p>\n\n<p>Let\u2019s look at another example. Below we have our <code>MainContent<\/code> component.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-04-18-context-in-react%2Fmaincontent.js.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-04-18-context-in-react%2Fmaincontent.js.png\" alt=\"MainContent.js component\"><\/a><\/p>\n\n<p>Just another component with a nested component, <code>UserBox<\/code>. Let\u2019s look at what is in the <code>UserBox<\/code> component.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-04-18-context-in-react%2Fuserbox.js.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-04-18-context-in-react%2Fuserbox.js.png\" alt=\"userbox.js.png\"><\/a><\/p>\n\n<p>The <code>UserBox<\/code> component can do as our header did; import the context object, subscribe to the provider using the <code>useContext<\/code> hook and pass in the context using that context object. This is cool because we\u2019re using context two levels below from where it was created without passing props through subsequent components. <\/p>\n\n<p>The app would look something similar to the below image. We can see the username string in the <code>header<\/code> and the <code>UserCard<\/code> components. I am not one for styling things effectively, so hold your judgments.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-04-18-context-in-react%2Fwhole-app.jpg\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-04-18-context-in-react%2Fwhole-app.jpg\" alt=\"The Whole App\"><\/a><\/p>\n\n<h3>\n  \n  \n  Conclusion <a><\/a>\n<\/h3>\n\n<p>Changing the value of the state would cause a render for the other components subscribed to the context. So it could cause issues if the state is constantly changing. So context fits nicely with a global state that is not likely to change often.<\/p>\n\n<p>The code for the above example can be <a href=\"https:\/\/github.com\/georgeoffley\/Blog-Code\/tree\/3f6e720bfedcc049c73e8a2fd14b8c06ec7edf78\/context-in-react\/context-in-react\" rel=\"noopener noreferrer\">found on my GitHub<\/a>.<\/p>\n\n<p>This has been an interesting learning experience. I\u2019m happy to have gotten one of the fundamentals of React down on paper, so to speak. I hope this helps someone new coming into the React scene.<\/p>\n\n<p>-George<\/p>\n\n","category":["javascript","react","beginners","tutorial"]},{"title":"Spiking Tailwind CSS in a React App","pubDate":"Sat, 02 Apr 2022 14:33:14 +0000","link":"https:\/\/dev.to\/georgeoffley\/spiking-tailwind-css-in-a-react-app-5198","guid":"https:\/\/dev.to\/georgeoffley\/spiking-tailwind-css-in-a-react-app-5198","description":"<h2>\n  \n  \n  Table Of Contents\n<\/h2>\n\n<ul>\n<li>Introduction<\/li>\n<li>Tailwind<\/li>\n<li>Setup<\/li>\n<li>Using Tailwind in React<\/li>\n<li>Something a Little More<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Introduction <a><\/a>\n<\/h3>\n\n<p>It\u2019s been some time since I did any frontend development, and I don\u2019t miss it. After a couple of years of learning the fundamentals, I would have loved to have some alternatives to manually writing CSS.<\/p>\n\n<p>Now that I am diving back into it, I am happy there are tools not to replace but improve the CSS experience. In that spirit, I want to look at <a href=\"https:\/\/tailwindcss.com\/\" rel=\"noopener noreferrer\">Tailwind CSS<\/a>.<\/p>\n\n<h3>\n  \n  \n  Tailwind CSS <a><\/a>\n<\/h3>\n\n<p>Tailwind is different from other CSS frameworks I\u2019ve tried. The software works on a lower level to allow easy CSS styling utilizing class names. Bootstrap works similarly, but the difference is that Tailwind does not come with predefined components. It is also different because the class names are compiled into CSS code. <\/p>\n\n<p>Tailwind is also not opinionated about how you make your designs, and thus they give you the tools you need and let you create unique components. It\u2019s the difference between <a href=\"https:\/\/www.timberland.com\/shop\/CategoryDisplay?catalogId=10101&amp;langId=-1&amp;categoryId=13502&amp;storeId=7101&amp;productId=p_20355&amp;audience=men&amp;page=configure\" rel=\"noopener noreferrer\">designing boots on a website<\/a> and having all the materials right before you to cobble together your shoes. This alone is valuable because you can avoid falling into the <a href=\"https:\/\/www.dagusa.com\/\" rel=\"noopener noreferrer\">Bootstrap design trap<\/a>.<\/p>\n\n<p>Tailwind is a <a href=\"https:\/\/tailwindcss.com\/docs\/utility-first\" rel=\"noopener noreferrer\">\u201cutility-first CSS Library,\u201d<\/a> From what I glean from their site, it means they tried to create a framework from a set of constrained utilities. This seems to translate into the following:<\/p>\n\n<ul>\n<li>There are no more CSS class names to create in both HTML and CSS files as styles are implemented using low-level utility classes.<\/li>\n<li>You add the styles you want into the HTML classes, which the compiler uses to generate CSS (which is attractive to me).<\/li>\n<li>Your CSS files don\u2019t grow since you\u2019re generally not creating new styles.<\/li>\n<li>The ability to create reusable styles using things like <a href=\"https:\/\/tailwindcss.com\/docs\/reusing-styles#loops\" rel=\"noopener noreferrer\">loops<\/a>.<\/li>\n<\/ul>\n\n<p>Tailwind also gives you ways to easily extend their utilities by utilizing config files for adding things like custom colors, fonts, etc. <\/p>\n\n<p>I\u2019ve noticed that they seem to lean into the idea of long strings of class names in HTML over regular CSS. You\u2019ll see what I mean.<\/p>\n\n<h3>\n  \n  \n  Setup <a><\/a>\n<\/h3>\n\n<p>So to try this and to learn the tech better for use in my work, I created a quick React application. <\/p>\n\n<p>After the React app creation, we can run the below commands.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>npm <span class=\"nb\">install <\/span>tailwindcss\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>This will install the needed packages.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>npx tailwindcss init\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>The above command will create the config files we need, the <code>tailwind.config.js<\/code> and the <code>postcss.config.js<\/code> files. The <code>tailwind.config.js<\/code> is where any customization options will go. By default, Tailwind looks for this file at the root of a project to create any customizations. For example, if you want to add colors or fonts that Tailwind does not have built-in, they will go in that config file.<\/p>\n\n<p>After that is installed, you replace everything in your <code>index.css<\/code> file with the below lines.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight css\"><code><span class=\"k\">@tailwind<\/span> <span class=\"n\">base<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">@tailwind<\/span> <span class=\"n\">components<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">@tailwind<\/span> <span class=\"n\">utilities<\/span><span class=\"p\">;<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>And finally, to ensure that all the template files are added to the Tailwind config, make sure the <code>tailwind.config.js<\/code> file looks like the below code.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"nx\">module<\/span><span class=\"p\">.<\/span><span class=\"nx\">exports<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n  <span class=\"na\">content<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">.\/src\/**\/*.{html,js}<\/span><span class=\"dl\">\"<\/span><span class=\"p\">],<\/span>\n  <span class=\"na\">theme<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\n    <span class=\"na\">extend<\/span><span class=\"p\">:<\/span> <span class=\"p\">{},<\/span>\n  <span class=\"p\">},<\/span>\n  <span class=\"na\">plugins<\/span><span class=\"p\">:<\/span> <span class=\"p\">[],<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>It\u2019s a bit much, but that\u2019s essentially it. You\u2019re now ready to start styling stuff.<\/p>\n\n<h3>\n  \n  \n  Using Tailwind in React <a><\/a>\n<\/h3>\n\n<p>After setting up our React project and installing Tailwind, I was ready to go. So I got rid of all the startup React stuff and started small.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code><span class=\"nt\">&lt;h1<\/span> <span class=\"na\">className=<\/span><span class=\"s\">\"\"<\/span><span class=\"nt\">&gt;<\/span>I'm using Tailwind!<span class=\"nt\">&lt;\/h1&gt;<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Pretty easy, and we get a simple heading tag.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-04-02-spiking-tailwind-in-a-react-app%2Fh1_no_style.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-04-02-spiking-tailwind-in-a-react-app%2Fh1_no_style.png\" alt=\"H1 Tag with no style\"><\/a><\/p>\n\n<p>Now let\u2019s start small and add some styling.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code><span class=\"nt\">&lt;h1<\/span> <span class=\"na\">className=<\/span><span class=\"s\">\"text-red-700 text-6xl hover:text-9xl\"<\/span><span class=\"nt\">&gt;<\/span>I'm using Tailwind!<span class=\"nt\">&lt;\/h1&gt;<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Now I added a couple of styling classes to the JSX, and just like we were editing a CSS file, we got some results.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-04-02-spiking-tailwind-in-a-react-app%2Fh1_style_no_hover.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-04-02-spiking-tailwind-in-a-react-app%2Fh1_style_no_hover.png\" alt=\"H1 tag with some basic styles\"><\/a><\/p>\n\n<p>You may also notice the <code>hover<\/code> selector in there. Tailwind takes care of these, similar to how CSS does. You prepend the effect you want and the outcome, and it works just the same.And we can see the style change a little when we hover over the text.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-04-02-spiking-tailwind-in-a-react-app%2Fh1_style_hover.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-04-02-spiking-tailwind-in-a-react-app%2Fh1_style_hover.png\" alt=\"Hover effect\"><\/a><\/p>\n\n<p>Adding these class names saved me from opening up VSCode and adding styles to a CSS file. I am already sold on Tailwind.<\/p>\n\n<p>You can also see the core use of Tailwind in adding class names to the HTML tags. This is a small example, but tags can have tons of styles, so adding a class name into the HTML can get overwhelming quickly. This is the language they lean into that I mentioned above. <\/p>\n\n<h3>\n  \n  \n  Something a Little More <a><\/a>\n<\/h3>\n\n<p>I am not a designer, but I find this setup easy to create components. So let\u2019s say I broke my app into pieces. How can I style this card component I made? Tailwind makes it simple.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"k\">export<\/span> <span class=\"k\">default<\/span> <span class=\"kd\">function<\/span> <span class=\"nf\">Card<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">return <\/span><span class=\"p\">(<\/span>\n        <span class=\"o\">&lt;<\/span><span class=\"nx\">div<\/span> <span class=\"kd\">class<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">p-20 bg-green-100<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span>\n            <span class=\"o\">&lt;<\/span><span class=\"nx\">h3<\/span> <span class=\"kd\">class<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">text-green-300 mb-4 text-sm font-bold<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span>\n                <span class=\"nx\">This<\/span> <span class=\"nx\">is<\/span> <span class=\"nx\">some<\/span> <span class=\"nx\">cool<\/span> <span class=\"nx\">Tailwind<\/span> <span class=\"nx\">Stuff<\/span><span class=\"o\">!<\/span>\n            <span class=\"o\">&lt;<\/span><span class=\"sr\">\/h3<\/span><span class=\"err\">&gt;\n<\/span>            <span class=\"o\">&lt;<\/span><span class=\"nx\">div<\/span> <span class=\"kd\">class<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">border-4 border-green-800 bg-white p-6 rounded-lg shadow-lg<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span>\n                <span class=\"o\">&lt;<\/span><span class=\"nx\">h2<\/span> <span class=\"kd\">class<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">text-2xl font-bold mb-2 text-gray-800<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span><span class=\"nx\">Look<\/span> <span class=\"nx\">at<\/span> <span class=\"k\">this<\/span><span class=\"o\">!&lt;<\/span><span class=\"sr\">\/h2<\/span><span class=\"err\">&gt;\n<\/span>                <span class=\"o\">&lt;<\/span><span class=\"nx\">p<\/span> <span class=\"kd\">class<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">text-gray-700<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span><span class=\"nx\">We<\/span> <span class=\"nx\">did<\/span> <span class=\"nx\">some<\/span> <span class=\"nx\">Tailwind<\/span><span class=\"o\">!&lt;<\/span><span class=\"sr\">\/p<\/span><span class=\"err\">&gt;\n<\/span>            <span class=\"o\">&lt;<\/span><span class=\"sr\">\/div<\/span><span class=\"err\">&gt;\n<\/span>        <span class=\"o\">&lt;<\/span><span class=\"sr\">\/div<\/span><span class=\"err\">&gt;\n<\/span>    <span class=\"p\">)<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>And the results.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-04-02-spiking-tailwind-in-a-react-app%2Fcard_styles.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-04-02-spiking-tailwind-in-a-react-app%2Fcard_styles.png\" alt=\"Basic card with styles\"><\/a><\/p>\n\n<p>I didn\u2019t have to write a single bit of CSS for this, and now I have a perfectly usable component. There\u2019s no ending to this rabbit hole. Design all you want.<\/p>\n\n<h3>\n  \n  \n  Conclusion\n<\/h3>\n\n<p>I can\u2019t bring myself to write CSS. It\u2019s a doomed relationship; with too much bad blood and too much history. However, I might just get through with Tailwind as a buffer for those awkward times I have to sit with it. <\/p>\n\n<p>Hyperbole aside, Tailwind is not a replacement for CSS but a fantastic addition to CSS for easily styling web components. Coupled with React, this was how we were meant to make apps. I\u2019m excited to continue learning and hope this helped.<\/p>\n\n<p><strong>Small disclaimer<\/strong>: I am not suggesting anyone reading this who might be new to frontend development jump straight into learning Tailwind. That journey starts with <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Learn\/CSS\/First_steps\/How_CSS_works\" rel=\"noopener noreferrer\">learning how CSS works<\/a>. Much like filmmaking, learn all the fundamentals first and then break the rules at your leisure.<\/p>\n\n<p>-George<\/p>\n\n","category":["javascript","react","tailwindcss","webdev"]},{"title":"Table Resource VS Client in AWS","pubDate":"Sun, 20 Mar 2022 01:22:41 +0000","link":"https:\/\/dev.to\/aws-builders\/table-resource-vs-client-in-aws-418","guid":"https:\/\/dev.to\/aws-builders\/table-resource-vs-client-in-aws-418","description":"<h2>\n  \n  \n  Table Of Contents\n<\/h2>\n\n<ul>\n<li>Introduction<\/li>\n<li>The Problem<\/li>\n<li>The Answer<\/li>\n<li>The Answer<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Introduction <a><\/a>\n<\/h3>\n\n<p>DynamoDB provides an excellent way to store data in a flexible and scalable way. Add it to Lambda and API Gateway, and you have a powerful group of tools, <a href=\"https:\/\/georgeoffley.com\/blog\/using-api-gateway-with-lambda.html\">which I have written about<\/a>. It was for these reasons that I chose to use it for a side project I am building to familiarize myself with React. It was in these features that I struggled with an issue in how <a href=\"https:\/\/github.com\/boto\/boto3\">boto3<\/a>, the SDK for talking with AWS in Python, implements their libraries.<\/p>\n\n<h3>\n  \n  \n  The Problem <a><\/a>\n<\/h3>\n\n<p>I have a personal rule; if it takes a certain amount of time to debug an issue, then there is something about the underlying technology that I do not understand. As it happens, I spent some time trying to get the APIs to work correctly in my side app recently. The problem boiled down to how my return data from the API was displayed in the application. It confounded me for some time. So I stepped back and challenged my assumptions about the tech. I followed the rabbit hole back to the API I wrote, where I found the problem. <\/p>\n\n<p>It turned out the problem was in using the <a href=\"https:\/\/boto3.amazonaws.com\/v1\/documentation\/api\/latest\/reference\/services\/dynamodb.html#client\">Client class<\/a> in boto3. From their docs, Amazon calls the Client class a \u201clow-level client representing Amazon DynamoDB.\u201d So this made sense when I started seeing how the API would interact with my app. <\/p>\n\n<p>When making a call to the API, the JSON returned would have all these extra tags on them. Below is an example.<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--w6bNQ2Gj--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-19-table-resource-vs-client-in-aws\/client_resp.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--w6bNQ2Gj--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-19-table-resource-vs-client-in-aws\/client_resp.png\" alt=\"client_resp.png\" width=\"398\" height=\"462\"><\/a><\/p>\n\n<p>It seems that DynamoDB was tagging the data types, as string types would have the type \u201cS\u201d for string values and \u201cN\u201d for number values. It made little sense to me. There are possible solutions available in the library that will help <a href=\"https:\/\/towardsaws.com\/making-use-of-boto3-out-of-the-box-dynamodb-serializers-1dffbc7deafe\">unmarshal the data and clean it up a little<\/a>, but these tools are <a href=\"https:\/\/github.com\/boto\/boto3\/blob\/e353ecc219497438b955781988ce7f5cf7efae25\/boto3\/dynamodb\/types.py#L233\">buried in the source code for boto3<\/a> and don\u2019t seem to have official documentation. There\u2019s a <a href=\"https:\/\/github.com\/boto\/boto3\/issues\/1630\">yet unresolved GitHub issue about it<\/a>. So I had to look deeper for a solution.<\/p>\n\n<h3>\n  \n  \n  The Answer <a><\/a>\n<\/h3>\n\n<p>After a while of searching through the AWS docs and trying various solutions, I was able to come up with a fix. I rewrote my API to grab all the records using the <a href=\"https:\/\/boto3.amazonaws.com\/v1\/documentation\/api\/latest\/reference\/services\/dynamodb.html#table\">Table<\/a> class rather than the Client class. <\/p>\n\n<p>It turns out that the Client class works precisely like a low-level abstraction should, returning all the stuff that\u2019s stashed into DynamoDB data tags and all. Not very reader-friendly. <\/p>\n\n<p>Here you can see what the code looks like using the Client class.<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--cG99I_R9--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-19-table-resource-vs-client-in-aws\/client_code.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--cG99I_R9--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-19-table-resource-vs-client-in-aws\/client_code.png\" alt=\"client_code.png\" width=\"880\" height=\"651\"><\/a><\/p>\n\n<p>And here is the updated code for the Table resource.<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--5Lm2ClX5--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-19-table-resource-vs-client-in-aws\/table_code.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--5Lm2ClX5--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-19-table-resource-vs-client-in-aws\/table_code.png\" alt=\"table_code.png\" width=\"880\" height=\"723\"><\/a><\/p>\n\n<p>Very little in the logic changed. We are still creating a connection to AWS using a Lambda function. We are still returning the response to that function. <\/p>\n\n<p>There are, however, a couple of differences. We call the Table resource a little differently from the client, and I added some pagination to the table code. As boto3 will only return everything up to 1 MB, you need to put in pagination to get all your results.<\/p>\n\n<p>Making that change makes the API returns a cleaner response.<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--tGtunsjA--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-19-table-resource-vs-client-in-aws\/table_resp.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--tGtunsjA--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-19-table-resource-vs-client-in-aws\/table_resp.png\" alt=\"table_resp.png\" width=\"320\" height=\"257\"><\/a><\/p>\n\n<p>No data tags and no messy nesting in our API data anymore. <\/p>\n\n<h3>\n  \n  \n  Conclusion <a><\/a>\n<\/h3>\n\n<p>I like challenging my assumptions. Being outside my comfort zone is how I learn best. I\u2019ve been making small scripts similar to that using the Client class for a while now, so it was good to understand the limitations in the tool and the tradeoffs using others. How this discomfort shakes out in the React app remains to be seen, but I am sure I\u2019ll figure those problems out too. I hope this helps someone.<\/p>\n\n<p>-George<\/p>\n\n","category":["aws","python"]},{"title":"Modules in React","pubDate":"Fri, 18 Mar 2022 20:10:10 +0000","link":"https:\/\/dev.to\/georgeoffley\/modules-in-react-274d","guid":"https:\/\/dev.to\/georgeoffley\/modules-in-react-274d","description":"<h2>\n  \n  \n  Table Of Contents\n<\/h2>\n\n<ul>\n<li>Introduction<\/li>\n<li>React Modules<\/li>\n<li>In-App Example<\/li>\n<li>Named Imports vs. Default Imports<\/li>\n<li>Conclusion<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Introduction <a><\/a>\n<\/h3>\n\n<p>The organization of your apps is one of the most effortless quality of life improvements you can make. Recently I\u2019ve been deep-diving into React for a work project, and I was able to get a crash course in how you organize one such app. Including how React treats its files and how we\u2019re importing them. So today, I\u2019d like to get into how React handles modules and how importing is done.<\/p>\n\n<h3>\n  \n  \n  React Modules <a><\/a>\n<\/h3>\n\n<p><a href=\"https:\/\/reactjs.org\/docs\/faq-structure.html#is-there-a-recommended-way-to-structure-react-projects\" rel=\"noopener noreferrer\">React has no opinions on how you organize your code<\/a>. This is fine as engineers usually have plenty of views on this, and the subject matter expert we\u2019re working with was no exception. After talking it through, we decided to organize our app where each feature was organized into its own directory. This also gives us a choice to utilize <code>index.js<\/code> files to handle exports. <\/p>\n\n<p>The most straightforward analogy coming from Python was that React lets you put your files into a directory and then create an <code>index.js<\/code> file that exports everything. This is similar to how Python will utilize an <code>__init__.py<\/code> file to export everything into the main logic files. <\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-03-18-modules-in-react%2Freact_modules.jpeg\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-03-18-modules-in-react%2Freact_modules.jpeg\" alt=\"React Modules diagram\"><\/a><\/p>\n\n<p>So if I have one or more modules I need to import into the <code>App.js<\/code> file for a feature, I can utilize the <code>index.js<\/code> file to import all of them and serve as one export point for your <code>App.js<\/code> or wherever you are utilizing said feature. <\/p>\n\n<h3>\n  \n  \n  In-App Example <a><\/a>\n<\/h3>\n\n<p>Let\u2019s go through a quick example. I created a small React application to demonstrate what I am talking about. I organized it as such.<\/p>\n\n<ul>\n<li>Src\n\n<ul>\n<li>App Feature\n\n<ul>\n<li>Hello.js<\/li>\n<li>Worlds.js<\/li>\n<li>Index.js<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>App.js<\/li>\n\n<\/ul>\n\n<\/li>\n\n<\/ul>\n\n<p>I created a directory named AppFeature to hold the modules I want to organize under there. The Hello and World modules look similar; they are only components that render a new div tag with some words. See the code below.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-03-18-modules-in-react%2Fhello.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-03-18-modules-in-react%2Fhello.png\" alt=\"hello.png\"><\/a><\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-03-18-modules-in-react%2Fworld.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-03-18-modules-in-react%2Fworld.png\" alt=\"world.png\"><\/a><\/p>\n\n<p>The AppFeature directory will have an <code>index.js<\/code> file that will handle exporting. This file will be used as a \u201ccentral hub\u201d where we can export all our modules into different parts of the application. You can see the code below.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-03-18-modules-in-react%2Findexjs.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-03-18-modules-in-react%2Findexjs.png\" alt=\"indexjs.png\"><\/a><\/p>\n\n<p>In the code above I put in two export statements. From here is where our modules will be exported from. This makes for cleaner imports into our <code>App.js<\/code> file. As seen below.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-03-18-modules-in-react%2Fappjs.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-03-18-modules-in-react%2Fappjs.png\" alt=\"appjs.png\"><\/a><\/p>\n\n<p>At the top, you can see a clean import statement where we import a list of modules from the AppFeature directory. After that, we can apply them right into our application. It comes out looking like this.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-03-18-modules-in-react%2Fapp_page.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-03-18-modules-in-react%2Fapp_page.png\" alt=\"app_page.png\"><\/a><\/p>\n\n<h3>\n  \n  \n  Named Imports vs. Default Imports <a><\/a>\n<\/h3>\n\n<p>The above example details what are referred to as Named Imports, but that is not the only way to handle exporting and importing. There are other ways to export\/import your needed modules. For example, suppose we are building components with multiple modules that do not need to be imported into the main application files. In that case, we can organize them so our main module can import all it needs and serve as the main component or class module to be exported. As demonstrated below.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-03-18-modules-in-react%2Fdefualt_hello_world.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-03-18-modules-in-react%2Fdefualt_hello_world.png\" alt=\"defaulthelloworld.png\"><\/a><\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-03-18-modules-in-react%2Fdefault_indexjs.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-03-18-modules-in-react%2Fdefault_indexjs.png\" alt=\"default_index.js\"><\/a><\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-03-18-modules-in-react%2Fdefault_appjs.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2022-03-18-modules-in-react%2Fdefault_appjs.png\" alt=\"default_app.js\"><\/a><\/p>\n\n<p>If we organize our code such that we want to keep internal modules internal, we can explore this type of organization. Using Default Imports, we\u2019re still doing the same thing: we use our <code>index.js<\/code> file to handle our exports. The difference is that we\u2019re organizing everything into one module and only exporting that one module. This makes everything even cleaner. <\/p>\n\n<h3>\n  \n  \n  Conclusion <a><\/a>\n<\/h3>\n\n<p>One of the goals for the application we are building is to optimize our workflow. Organizing your code by utilizing modules in React is just one way in which we are meeting that goal. There are many things to consider, but I believe we are headed in the right direction. I hope this helps someone looking to organize their React projects.<\/p>\n\n<p>-George<\/p>\n\n","category":["javascript","beginners","react"]},{"title":"Dockerizing System Tests With Selenium","pubDate":"Mon, 14 Mar 2022 12:26:33 +0000","link":"https:\/\/dev.to\/georgeoffley\/dockerizing-system-tests-with-selenium-5dn0","guid":"https:\/\/dev.to\/georgeoffley\/dockerizing-system-tests-with-selenium-5dn0","description":"<p>Originally posted on my blog <a href=\"https:\/\/georgeoffley.com\/blog\/dockerizing-system-tests-with-selenium.html\">georgeoffley.com<\/a><\/p>\n\n<h2>\n  \n  \n  Table Of Contents\n<\/h2>\n\n<ul>\n<li>Introduction<\/li>\n<li>Selenium WebDriver<\/li>\n<li>Setup<\/li>\n<li>Running Tests<\/li>\n<li>Notes<\/li>\n<li>Conclusion<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Introduction <a><\/a>\n<\/h3>\n\n<p>We are spinning up a new application for some end users to enter data, so we need to build a robust testing system. Unit tests are a must, but those only test to ensure that all the classes, methods, and functions do what we expect. On top of that, we also need to verify that the web app as a whole looks and behaves how we hope it does to have a complete end-to-end testing apparatus. My goal for these first few spikes in the project was to find a tool for system testing and see if we could make it modular and easily automate it to not interfere with our workflow. I believe I found the solution. <a href=\"https:\/\/www.selenium.dev\/\">Selenium<\/a> is a suite of tools for creating and automating browser tests, and I think it is what I was looking for. Let\u2019s dive in.<\/p>\n\n<h3>\n  \n  \n  Selenium WebDriver <a><\/a>\n<\/h3>\n\n<p>Selenium is a multi-language suite of tools for creating browser-based automation tests. This tool will automate opening a browser, looking for a test condition, and reporting a pass or fail. Selenium is a whole suite of tools, but I decided to focus on <a href=\"https:\/\/www.selenium.dev\/documentation\/webdriver\/\">Selenium Web Driver<\/a>.<\/p>\n\n<p>Much like in the name, the software \u201cdrives\u201d the web browser. Much like humans, we can bring up the webpage in a browser, enter in data, look up tags, and utilize all these capabilities to write tests using the API Selenium provides. A test opens a browser, <a href=\"https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-10-dockerizing-system-tests-with-selenium\/selenium_video.mp4\">and like magic, many things happen<\/a>.<\/p>\n\n<p>My goal is to automate as much of this process as possible. So it would not be ideal to have a bunch of browsers launch with with ghosts running tests. A better solution was to run <a href=\"https:\/\/github.com\/SeleniumHQ\/docker-selenium\"><em>headless browsers<\/em><\/a> using container images provided by Selenium. This solution gives us a container with a built-in web browser which we don't see that our script runs a test against. The results we can see in the terminal.<\/p>\n\n<p>As our project utilizes <a href=\"https:\/\/www.docker.com\/\">Docker<\/a>, the easiest way to start is to grab the <a href=\"https:\/\/github.com\/SeleniumHQ\/docker-selenium\">Docker image for the browser<\/a> and start making some scripts. How this will look in the final solution is still to be determined, but I can replicate what I did for the sake of this write-up.<\/p>\n\n<h3>\n  \n  \n  Setup <a><\/a>\n<\/h3>\n\n<p>To begin, I set up a <code>docker-compose.yml<\/code> file with the following:<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--9_sucTMo--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-10-dockerizing-system-tests-with-selenium\/docker-compose.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--9_sucTMo--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-10-dockerizing-system-tests-with-selenium\/docker-compose.png\" alt=\"docker-compose.yml file\" width=\"880\" height=\"935\"><\/a><\/p>\n\n<p>This gave us two containers, our browser using the Chrome-based selenium image and a Ruby-based container to run the script. Our new stack uses a lot of Ruby. The system container is built using an image from the docker file in the test directory.<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--6IYDT-XZ--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-10-dockerizing-system-tests-with-selenium\/ruby-dockerfile.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--6IYDT-XZ--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-10-dockerizing-system-tests-with-selenium\/ruby-dockerfile.png\" alt=\"Dockerfile for Ruby based system\" width=\"814\" height=\"628\"><\/a><\/p>\n\n<p>This build handles installing the gems we need, including selenium-webdriver and the chromedriver-helper. Both are used to run our Web Driver script and utilize Chrome capabilities. <\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--Bsc2J-qV--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-10-dockerizing-system-tests-with-selenium\/gemfile.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--Bsc2J-qV--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-10-dockerizing-system-tests-with-selenium\/gemfile.png\" alt=\"Gemfile\" width=\"880\" height=\"435\"><\/a><\/p>\n\n<p>Finally, the last bit is the script itself.<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--J2qUhP7u--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-10-dockerizing-system-tests-with-selenium\/test-script.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--J2qUhP7u--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-10-dockerizing-system-tests-with-selenium\/test-script.png\" alt=\"Test Script\" width=\"880\" height=\"514\"><\/a><\/p>\n\n<h3>\n  \n  \n  Running Tests <a><\/a>\n<\/h3>\n\n<p>Let\u2019s look at this script. My Ruby is rusty, but I tried my best. We set all our requirements, set a timer to make the thread sleep (more on that later), and then we write our test. In the script, we are writing the tests using the <a href=\"https:\/\/rspec.info\/\">RSpec<\/a>. RSpec is a <a href=\"https:\/\/www.jetbrains.com\/mps\/concepts\/domain-specific-languages\/\">domain-specific language<\/a> built using Ruby to test Ruby code. We use this to test our behaviors using the describe and it blocks. <\/p>\n\n<p>We start by defining the <a href=\"https:\/\/www.selenium.dev\/documentation\/webdriver\/capabilities\/\">capabilities<\/a> we are looking for; in this case, we are testing a chrome browser, so we need to specify that. <\/p>\n\n<p>Then we use a variant of WebDriver called the <a href=\"https:\/\/www.selenium.dev\/documentation\/webdriver\/remote_webdriver\/\">Remote WebDriver<\/a>. Remote Driver is written identically to WebDriver, just with the caveat of the driver logic looking for the browser in another system. Here we set the address for the Chrome Selenium container so that our WebDriver knows to look for this remote machine to run the test against.<\/p>\n\n<p>Both containers are in the same network provided by Docker Compose, so we use the hostnames. Also, note that we are <a href=\"https:\/\/docs.docker.com\/compose\/networking\/\">mapping port 4444<\/a> as the WebDriver will use this port to communicate.<\/p>\n\n<p>We then set the driver to navigate to our chosen website as an action. The following line sets what we expect to see using RSpec\u2019s handy <a href=\"https:\/\/relishapp.com\/rspec\/rspec-expectations\/docs\/built-in-matchers\"><em>expect function<\/em><\/a>. We expect the page's title to be equal to a string we provide and fail if the title is mismatched. Then we\u2019ll just take a screenshot and save the image to a local drive using one of the built-in save_screenshot functions. Finally, and this was important, use the <em>quit<\/em> function. <\/p>\n\n<p>We run this just by running <code>docker-compose up<\/code>, and we can see the test passed as going to Google does indeed yield a page title of \u201cGoogle.\u201d<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--Dmji3kQV--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-10-dockerizing-system-tests-with-selenium\/test-results.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--Dmji3kQV--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-10-dockerizing-system-tests-with-selenium\/test-results.png\" alt=\"Test results in terminal\" width=\"880\" height=\"173\"><\/a><\/p>\n\n<p>We can also see the screenshot taken from the remote browser.<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--hNEy3TOQ--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-10-dockerizing-system-tests-with-selenium\/test_image.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--hNEy3TOQ--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-10-dockerizing-system-tests-with-selenium\/test_image.png\" alt=\"Resulting image from test\" width=\"880\" height=\"717\"><\/a><\/p>\n\n<h3>\n  \n  \n  Notes <a><\/a>\n<\/h3>\n\n<p>Using the <em>quit<\/em> function was essential to kill the connection, but it also closed the browser we can't see. Additionally, I mentioned I would come back to using the sleep function in Ruby. It turns out using the <a href=\"https:\/\/docs.docker.com\/compose\/startup-order\/\"><em>depends_on<\/em><\/a> feature in Docker Compose is not enough to ensure services are available to each other. When I began running the network, the remote driver would continually fail to connect. It turns out we just needed a moment for everything to boot. <a href=\"https:\/\/docs.docker.com\/compose\/startup-order\/\">Docker recommends creating a wait script<\/a> but pausing the thread for a moment worked just as well.<\/p>\n\n<h3>\n  \n  \n  Conclusion <a><\/a>\n<\/h3>\n\n<p>This was a pretty simple example, but it answered my questions. We can use this to test website behavior, make it modular, and automate the tests. That checks enough boxes for me to keep going down this rabbit hole. The next goal is to develop an automated solution and possibly clean up the deployment a little. I\u2019m thinking of having these two containers not run with the rest of the project and boot up the containers using a bash script specifically for testing. I might write about that too.<\/p>\n\n<p>-George<\/p>\n\n","category":["docker","testing","selenium","ruby"]},{"title":"Implementing Routing in React","pubDate":"Sun, 13 Mar 2022 14:43:28 +0000","link":"https:\/\/dev.to\/georgeoffley\/implementing-routing-in-react-3ab8","guid":"https:\/\/dev.to\/georgeoffley\/implementing-routing-in-react-3ab8","description":"<h2>\n  \n  \n  Table Of Contents\n<\/h2>\n\n<ul>\n<li>Introduction<\/li>\n<li>React Router Dom<\/li>\n<li>Setup<\/li>\n<li>Explainer<\/li>\n<li>Conclusion<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Introduction <a><\/a>\n<\/h3>\n\n<p>Implementing routing in React applications can be one of the first tasks you undertake in the coding part of the development lifecycle. This was true for my team when we sat down to a mob programming session to go through a couple of our stories for a project. We brought in some help from people who know React to help us get started. I am not a React developer, so this is the first time I had actual exposure to people with expertise, so I am grateful it was a group programming session. I don\u2019t know what I was doing when the rest of the world learned React, but I can only guess it had something to do with playing the Sims. Regardless I use the right tool for the job, and I need to learn it now. The first thing we did was implement some routing, and I will implement a much more simplified version of what we did below to show what I learned.<\/p>\n\n<h3>\n  \n  \n  React Router Dom <a><\/a>\n<\/h3>\n\n<p>I understand React is a set of APIs and libraries used in different ways to implement cool stuff on your screen. We got more into using TypeScript on top of React, but I like to write about things even if I only have a cursory knowledge of them, and my understanding of TypeScript doesn\u2019t even measure up to that. So I\u2019ll stick with React only for now.<\/p>\n\n<p>Routing in a React app is what the app does when a user goes to a specific URL. As we\u2019re dealing with React, we need to create components that make up our pages, and we\u2019ll use a library to route to those components. In our case, we used the ever-popular <a href=\"https:\/\/reactrouter.com\/\">React Router Dom<\/a>.<\/p>\n\n<h3>\n  \n  \n  Setup <a><\/a>\n<\/h3>\n\n<p>An easy bit of setup. I created a new app using <code>npx create-react-app react-router<\/code>, which gave me a basic app. I then ran <code>npm install react-router-dom<\/code> to install the needed package. Then I was off to the races. <\/p>\n\n<p>I created two simple page components to then import into my main App.js.<\/p>\n\n<p>The Home component.<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--13Vz30dx--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-12-implementing-routing-in-react\/home.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--13Vz30dx--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-12-implementing-routing-in-react\/home.png\" alt=\"Home component\" width=\"880\" height=\"682\"><\/a><\/p>\n\n<p>And the About component.<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--yQhhHPby--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-12-implementing-routing-in-react\/about.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--yQhhHPby--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-12-implementing-routing-in-react\/about.png\" alt=\"About component\" width=\"880\" height=\"668\"><\/a><\/p>\n\n<p>Finally, I went through some of the docs and found an easy way to get basic routing. All of which is reflected in my main App.js file.<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--ypXlhq-V--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-12-implementing-routing-in-react\/app.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--ypXlhq-V--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-12-implementing-routing-in-react\/app.png\" alt=\"App.js file\" width=\"880\" height=\"914\"><\/a><\/p>\n\n<h3>\n  \n  \n  Explainer <a><\/a>\n<\/h3>\n\n<p>This needs explaining. I created a basic component for the home and the about pages. Both of them just return a header with the name in the tag. I imported them into app.js and imported BrowserRouter, Routes, and Route from the React Router Dom package. Each of these is going to help us create routing.<\/p>\n\n<p>First, we create the router using the BrowserRouter tag. Then nested in there, we make the Routes block. The routes block, which took the place of the Switch block in v6 of the React Router Package, looks at our nested routes and tells the app where to go. Finally, we have the \u201clinks\u201d in the Route tags. We specify the path to look for in the Route tag and which element to point at. It\u2019s also good to remember that the element should take the form of curly brackets and an open and closing tag (the <code>{&lt;Home\/&gt;}<\/code> you see in my code). I mention this as most tutorials I looked up about this used Switch, Links, and the elements used the <code>{Home}<\/code> syntax.<\/p>\n\n<p>And that is it. If I navigate to <code>localhost:3000\/<\/code>, we see the below image.<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--OYlztwI2--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-12-implementing-routing-in-react\/home_page.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--OYlztwI2--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-12-implementing-routing-in-react\/home_page.png\" alt=\"Home Page after implementing routing\" width=\"853\" height=\"601\"><\/a><\/p>\n\n<p>And the same thing on the about page at <code>localhost:3000\/about<\/code>.<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--jpbWrYd3--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-12-implementing-routing-in-react\/about_page.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--jpbWrYd3--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-03-12-implementing-routing-in-react\/about_page.png\" alt=\"About Page after implementing routing\" width=\"853\" height=\"601\"><\/a><\/p>\n\n<h3>\n  \n  \n  Conclusion <a><\/a>\n<\/h3>\n\n<p>It is a simple thing but something I learned while working with a team of React people. Using React is still akin to reading an upsidedown French map of Germany. However, I am starting to grasp the basics. Everything seems just to be something that\u2019s been imported from somewhere else. Next time I think I\u2019ll write about how you can create React packages similar to Python for easy and clean importing. <\/p>\n\n","category":["javascript","react","webdev","beginners"]},{"title":"Using Amazon API Gateway with Lambda","pubDate":"Thu, 10 Feb 2022 02:12:19 +0000","link":"https:\/\/dev.to\/aws-builders\/using-amazon-api-gateway-with-lambda-36nb","guid":"https:\/\/dev.to\/aws-builders\/using-amazon-api-gateway-with-lambda-36nb","description":"<h2>\n  \n  \n  Table Of Contents\n<\/h2>\n\n<ul>\n<li>Introduction<\/li>\n<li>Amazon API Gateway<\/li>\n<li>Setting up an API<\/li>\n<li>Adding the Trigger<\/li>\n<li>Setting the Methods<\/li>\n<li>Conclusion<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Introductions <a><\/a>\n<\/h3>\n\n<p>I follow this movie podcast where they review and talk about well movies. It\u2019s a fantastic podcast with a diverse set of people who\u2019ve worked in the industry a long time, and I enjoy their opinions. At the end of each episode, they do a \u201cStaff Pick\u201d where they pick out a movie that shares themes with the movie they just reviewed or movies they think people should see. As I don\u2019t have time to watch all the movies they suggest every week, I need to keep a running list of these films. They offer some good stuff.<\/p>\n\n<p>This presented a good opportunity to get some practice using React. I could build a tiny site cataloging all the suggested films. I have no React knowledge, so I started by creating a database to store their suggested films to stick with the iterative approach. Now I need to set up something to query the database and get back a list of the movies. That is where Amazon API Gateway and Lambda come in.<\/p>\n\n<h3>\n  \n  \n  Amazon API Gateway <a><\/a>\n<\/h3>\n\n<p><a href=\"https:\/\/georgeoffley.com\/blog\/creating-a-twitter-bot-using-aws-lambda-and-go.html\">I\u2019ve covered AWS Lambda before<\/a>, so I won\u2019t go into it much. Amazon API Gateway, however, is an AWS service that allows you to quickly spin up API endpoints for use in your web applications. When you need to request data for your website, an API endpoint is what you\u2019ll use. An <em>API endpoint<\/em> is a URL that your application can reach out to request some data. For example, <a href=\"https:\/\/ghibliapi.herokuapp.com\/films\/58611129-2dbc-4a81-a72f-77ddfc1b1b49\">this API endpoint<\/a> lets me look up Studio Ghibli movies. <\/p>\n\n<p>These can scale like crazy, and API Gateway lets you manage, monitor, and add endpoints to your service quickly. For this project I am spinning up, we only need to return a list of the movies in the table. So let\u2019s begin.<\/p>\n\n<h3>\n  \n  \n  Setting up an API <a><\/a>\n<\/h3>\n\n<p>The first thing is setting up something to process the request once our service reaches out via an API endpoint. AWS Lambda is what we\u2019ll use to create the process to query our database and return all our stuff. <\/p>\n\n<ul>\n<li>So we go into the AWS Console and create our Lambda. We\u2019re returning all our items with a simple query, so it\u2019s an easy setup. Here\u2019s the code:\n<\/li>\n<\/ul>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">import<\/span> <span class=\"nn\">boto3<\/span>\n<span class=\"kn\">import<\/span> <span class=\"nn\">os<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">lambda_handler<\/span><span class=\"p\">(<\/span><span class=\"n\">event<\/span><span class=\"p\">,<\/span> <span class=\"n\">context<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">client<\/span> <span class=\"o\">=<\/span> <span class=\"n\">boto3<\/span><span class=\"p\">.<\/span><span class=\"n\">client<\/span><span class=\"p\">(<\/span>\n        <span class=\"s\">'dynamodb'<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">aws_access_key_id<\/span><span class=\"o\">=<\/span><span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"n\">environ<\/span><span class=\"p\">.<\/span><span class=\"n\">get<\/span><span class=\"p\">(<\/span><span class=\"s\">'KEY'<\/span><span class=\"p\">),<\/span>\n        <span class=\"n\">aws_secret_access_key<\/span><span class=\"o\">=<\/span><span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"n\">environ<\/span><span class=\"p\">.<\/span><span class=\"n\">get<\/span><span class=\"p\">(<\/span><span class=\"s\">'SECRET'<\/span><span class=\"p\">)<\/span>\n        <span class=\"p\">)<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">get_all_items<\/span><span class=\"p\">():<\/span>\n\n        <span class=\"n\">response<\/span> <span class=\"o\">=<\/span> <span class=\"n\">client<\/span><span class=\"p\">.<\/span><span class=\"n\">scan<\/span><span class=\"p\">(<\/span>\n            <span class=\"n\">TableName<\/span><span class=\"o\">=<\/span><span class=\"s\">'MaxFilmStaffPicks'<\/span><span class=\"p\">,<\/span>\n        <span class=\"p\">)<\/span>\n\n        <span class=\"k\">return<\/span> <span class=\"n\">response<\/span>\n\n\n    <span class=\"k\">return<\/span> <span class=\"n\">get_all_items<\/span><span class=\"p\">()<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Adding the Trigger <a><\/a>\n<\/h3>\n\n<ul>\n<li>After we have the Lambda function up and running, we need to create something to initiate it, like a trigger.<\/li>\n<li>You can see a button to <em>Add trigger<\/em> at the top of the Lambda menu. You can click that and select <em>API Gateway<\/em> in the proceeding menu.<\/li>\n<\/ul>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--n872Q-3B--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-02-09-using-api-gateway-with-lambda\/trigger.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--n872Q-3B--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-02-09-using-api-gateway-with-lambda\/trigger.png\" alt=\"Trigger\" width=\"788\" height=\"412\"><\/a><\/p>\n\n<ul>\n<li>Then you can hit <em>Create API<\/em>, which brings up the options for APIs. In this case, I\u2019m making a <em>REST API<\/em>, so I select that. <\/li>\n<li>For security, I pick <em>Open<\/em>, as this is just a practice app. You can see what I chose below.<\/li>\n<\/ul>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--ggvQqFRT--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-02-09-using-api-gateway-with-lambda\/create_api_screen.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--ggvQqFRT--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-02-09-using-api-gateway-with-lambda\/create_api_screen.png\" alt=\"Create API Screen\" width=\"819\" height=\"629\"><\/a><\/p>\n\n<h3>\n  \n  \n  Setting the Methods <a><\/a>\n<\/h3>\n\n<ul>\n<li>I finish off by going into the API Gateway menu to check out the newly created endpoint. <\/li>\n<li>After that, you\u2019ll be greeted by a screen with all our methods. The default created method is the <em>ANY<\/em> method; I want this to be a <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Methods\/GET\"><em>GET<\/em><\/a> method. The difference between HTTP messages is a bit out of scope, <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Methods\">but you should know them<\/a>. We are using this endpoint only to request information for our application, so we stick to GET. <\/li>\n<li>We\u2019ll select the ANY method, click the <em>Action<\/em> menu above it, and delete the method.<\/li>\n<li>Then we go back to the same menu and click Create Method. <\/li>\n<li>From the dropdown, we select GET. <\/li>\n<li>Following this, we enter the name of the Lambda function this is for, and we\u2019re done.<\/li>\n<\/ul>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--fxglOuB_--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-02-09-using-api-gateway-with-lambda\/method_creation.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--fxglOuB_--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-02-09-using-api-gateway-with-lambda\/method_creation.png\" alt=\"Method Creation\" width=\"880\" height=\"376\"><\/a><\/p>\n\n<p>Very last step is to deploy the API. <\/p>\n\n<ul>\n<li>We click the same menu and click <em>Deploy API<\/em>.<\/li>\n<li>You\u2019ll then be asked which <em>Stage<\/em> you want to deploy in. When creating APIs, you can create many stages for your APIs, which will affect how they are used\u2014for example, setting up a dev stage or creating different versions of your API. Whatever stage you set will reflect in the endpoint. See below.<\/li>\n<\/ul>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--kwv6GYP7--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-02-09-using-api-gateway-with-lambda\/stage_url.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--kwv6GYP7--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-02-09-using-api-gateway-with-lambda\/stage_url.png\" alt=\"Stage URL\" width=\"867\" height=\"120\"><\/a><\/p>\n\n<ul>\n<li>For this instance, it is one API endpoint, in one app, for one specific purpose. I just used the default. <\/li>\n<li>Now we\u2019re done. We test the endpoint, and we get data!<\/li>\n<\/ul>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--OemXrmnH--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-02-09-using-api-gateway-with-lambda\/data.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--OemXrmnH--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2022-02-09-using-api-gateway-with-lambda\/data.png\" alt=\"Data!\" width=\"822\" height=\"651\"><\/a><\/p>\n\n<h3>\n  \n  \n  Conclusion <a><\/a>\n<\/h3>\n\n<p>Now I have a working API for grabbing my data. React confuses me, as I thought I\u2019d be able just to pull data like I would a Python app. However, I am sure I will learn much more as I continue. And now you also have some knowledge of setting up endpoints in Amazon API Gateway.<\/p>\n\n","category":["aws","python","api","beginners"]},{"title":"Shenanigans with Shaders","pubDate":"Sun, 21 Nov 2021 23:22:52 +0000","link":"https:\/\/dev.to\/georgeoffley\/shenanigans-with-shaders-3i97","guid":"https:\/\/dev.to\/georgeoffley\/shenanigans-with-shaders-3i97","description":"<h2>\n  \n  \n  Table Of Contents\n<\/h2>\n\n<ul>\n<li>Introduction<\/li>\n<li>Shaders<\/li>\n<li>Setup<\/li>\n<li>Shader Code<\/li>\n<li>Conclusion<\/li>\n<\/ul>\n\n<p>For those of you who love rabbit holes, learning graphics programming is a pretty deep one. There\u2019s always some new thing to learn, there\u2019s a bunch of different new languages and toolsets to know, and on top of all that, <a href=\"https:\/\/www.youtube.com\/watch?v=tt_gPXpx0eo&amp;t=101s&amp;ab_channel=SamwellTarly\">there\u2019s math<\/a>. Like anything else in programming, you pick up momentum with each new thing you build, so I <a href=\"https:\/\/github.com\/Xibanya\/ShaderTutorials\">found a tutorial<\/a> and started making shaders. I know very little about this. However, I\u2019m writing what I\u2019m learning, so don\u2019t come for me if I\u2019m off on anything. <\/p>\n\n<h3>\n  \n  \n  Shaders <a><\/a>\n<\/h3>\n\n<p>A shader is a program that runs on the GPU as part of the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Graphics_pipeline\">graphics pipeline<\/a>. We\u2019re going to focus primarily on shaders in Unity. There are other ways to tackle this, but Unity gives an easy setup to get started quickly. For the context of Unity, a shader is a small script containing logic and calculations for determining the colors of a pixel.<\/p>\n\n<p>In Unity, we create <em>shader objects<\/em> which act as wrappers for our shader program. A shader object exists in a <em>shader asset<\/em> which is just the script we are writing. Creating these in Unity allows for a great deal of freedom in what we make. What we\u2019ll focus on is adding some basic functionality to a shader. We\u2019ll be focusing on using <a href=\"https:\/\/docs.unity3d.com\/Manual\/SL-Reference.html\"><em>ShaderLab<\/em><\/a> to create shaders.<\/p>\n\n<h3>\n  \n  \n  Setup <a><\/a>\n<\/h3>\n\n<p>The first thing to set yourself up making shaders in Unity is Unity. So <a href=\"https:\/\/unity3d.com\/get-unity\/download\">download it<\/a>, and create a new project.<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--d6EGPlkZ--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2021-11-21-shenanigans-in-shaders\/new_scene.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--d6EGPlkZ--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2021-11-21-shenanigans-in-shaders\/new_scene.png\" alt=\"New Scene in Unity\" width=\"880\" height=\"487\"><\/a><\/p>\n\n<p>I won\u2019t give a full rundown of Unity and the stuff you can do. I leave that to <a href=\"https:\/\/learn.unity.com\/\">better minds<\/a>. In the <em>Hierarchy Window<\/em>, right-click and scroll to <em>3D Object<\/em> and click whichever object grabs your fancy. I always pick sphere for testing stuff. Now we have a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Polygon_mesh\"><em>3D Mesh<\/em><\/a> on the screen that we can begin adding things to it. In the <em>Project Window<\/em>, right-click on the word <em>Assets<\/em> and create two new folders, <em>Materials<\/em> and <em>Shaders<\/em>. Double click into the Materials folder, right-click and Create is right at the top -&gt; click Material. Materials are similar to skins we can apply to 3D objects. We will use this new material to add our new shader to the 3D Mesh. After that, drag our new material into the <em>Scene Window<\/em> where our sphere is and onto the sphere we made. Now right-click our Shaders folder scroll to Create -&gt; Shader -&gt; Standard Surface Shader. Click the sphere in the Scene window to bring up the <em>Inspector Window<\/em>. Finally, drag the shader file over to the inspector window with our sphere covered in our new material. We have just applied our shader to the materials. You should see this in the Inspector Window.<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--1hRhFMhw--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2021-11-21-shenanigans-in-shaders\/test_material.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--1hRhFMhw--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2021-11-21-shenanigans-in-shaders\/test_material.png\" alt=\"Test Material inspector window\" width=\"277\" height=\"616\"><\/a><\/p>\n\n<p>Now go back to the Project window and double click our new Shader file. Unity will launch an IDE for use to check out the code. You can configure your choice of IDE; I have VSCode configured. Open the Shader file, and let\u2019s check out the code. I created some basic shader code you can use.<\/p>\n\n<h3>\n  \n  \n  Shader Code <a><\/a>\n<\/h3>\n\n<p>Here is the complete, minimal shader code:<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--a90si7LV--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2021-11-21-shenanigans-in-shaders\/code.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--a90si7LV--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2021-11-21-shenanigans-in-shaders\/code.png\" alt=\"Full Shader Code\" width=\"880\" height=\"611\"><\/a><\/p>\n\n<p>It looks a bit much to anyone new to this, including myself, so let\u2019s take it a section at a time. The first thing at the top, starting with \u201cShader,\u201d is the <em>Shader Block<\/em>. This is used to define our Shader Object. You can use this to define your properties, create many shaders using the <em>SubShader<\/em> blocks, assign custom options, and assign a <em>fallback<\/em> shader object. Here you can see the name of our shader and that it is in the \u201cCustom\u201d directory.<\/p>\n\n<p>Within the Shader block curly brackets, we have our other sections. The first is our <em>Properties<\/em>. The properties box is where we define the properties for our materials. A material property is what Unity stores along with our materials. This allows for different configurations within Unity by creating things like sliders and inputs within the Inspector window for us to play around with. We defined two properties, the <em>MainColor<\/em> and the <em>MainTexture<\/em>. Using square brackets, I outlined which property was the default color and default texture. We also defined the default values for these properties. There\u2019s a bit to these values but suffice it to say, both values are default white.<\/p>\n\n<p>The second block is our SubShader; this is where our shader logic goes. You can define multiple sub shaders for many different uses. For example, depending on the graphics hardware you want to support, you can make shaders for the various graphics APIs. Within our block, you can see some code for assigning <a href=\"https:\/\/docs.unity3d.com\/Manual\/SL-SubShaderTags.html\"><em>tags<\/em><\/a>, assigning <a href=\"https:\/\/docs.unity3d.com\/Manual\/SL-ShaderLOD.html\"><em>levels of detail (LOD)<\/em><\/a>, and the <a href=\"https:\/\/en.wikibooks.org\/wiki\/Cg_Programming\/Unity\"><em>CGPROGRAM<\/em><\/a> block. I want to draw your attention to this section of the code:<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--5ET4sGMX--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2021-11-21-shenanigans-in-shaders\/output.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--5ET4sGMX--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2021-11-21-shenanigans-in-shaders\/output.png\" alt=\"Output function\" width=\"880\" height=\"543\"><\/a><\/p>\n\n<p>First, we define the data types for our inputs and outputs and create a function for us to serve the outputs into unity. Our Input we set up as <em>uv_Maintex<\/em>; this allows for us to input a texture object. Then we create a <em>fixed4<\/em> variable for our <em>_Color<\/em> attribute. The <em>o.Albedo<\/em> parameter is what is used to control the base color of the surface. Here we are taking the values of our texture and multiplying them by our color input. The code above gets you something similar to this:<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--dbifhzAV--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2021-11-21-shenanigans-in-shaders\/color.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--dbifhzAV--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/georgeoffley-blog-images.s3.amazonaws.com\/2021-11-21-shenanigans-in-shaders\/color.png\" alt=\"Output function\" width=\"857\" height=\"716\"><\/a><\/p>\n\n<p>I was proud of myself the first time I made this from memory. Our coded shader lets us control the color of the material and add basic textures to it. Working in graphics does not lead to instant gratification, as anything you do requires a ton of setup. However, this and <a href=\"https:\/\/www.shadertoy.com\/\">ShaderToy<\/a> get you that dopamine hit. <\/p>\n\n<h3>\n  \n  \n  Conclusion <a><\/a>\n<\/h3>\n\n<p>Above I went through some fundamentals of shaders in Unity. I skipped over a ton of information as I\u2019m still learning a lot, and a full informed explainer would be twenty pages long. There is a lot to programming graphics and shaders specifically. I suggest you check out stuff like <a href=\"https:\/\/github.com\/Xibanya\/ShaderTutorials\">Team Dogpit\u2019s shader tutorial<\/a> for a way better deep dive. I\u2019m excited to dig into this world. I want to learn to create some of the incredible stories I see in animation, and any first step is a step in the right direction. Thanks for reading.<\/p>\n\n<p>-George<\/p>\n\n","category":["unity3d","graphics"]},{"title":"Messaging and Madness: Sending Messages with AMQP and Amazon MQ","pubDate":"Sat, 30 Oct 2021 17:23:47 +0000","link":"https:\/\/dev.to\/aws-builders\/messaging-and-madness-sending-messages-with-amqp-and-amazon-mq-2m9b","guid":"https:\/\/dev.to\/aws-builders\/messaging-and-madness-sending-messages-with-amqp-and-amazon-mq-2m9b","description":"<p><em>Originally posted on <a href=\"https:\/\/georgeoffley.com\/blog\/messaging-and-madness-sending-messages-with-amqp-and-amazon-mq.html\" rel=\"noopener noreferrer\">my personal blog<\/a><\/em><\/p>\n\n<h2>\n  \n  \n  Table Of Contents\n<\/h2>\n\n<ul>\n<li>Introduction<\/li>\n<li>AMQP<\/li>\n<li>AMQP and Amazon MQ<\/li>\n<li>Serialization<\/li>\n<li>Conclusion<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Introduction <a><\/a>\n<\/h3>\n\n<p>How do software systems talk to each other? Back-end systems can scale into giant melted together <a href=\"https:\/\/youtu.be\/NH-8L1iZq20\" rel=\"noopener noreferrer\">Cronenberg monsters<\/a>, often making up different tools and languages. So, communicating between these services can become an untenable challenge without some shared vocabulary. We can communicate in many ways, but today I wanted to talk about asynchronous messaging protocols and figure out how AWS can help.<\/p>\n\n<h3>\n  \n  \n  AMQP <a><\/a>\n<\/h3>\n\n<p>AMQP stands for Advanced Message Queuing Protocol. I\u2019ve been working to implement it for some back-end software suites I\u2019m building out to enable them to talk to each other. AMQP utilizes these things called <em>brokers<\/em> to publish messages on, then on the other end, a receiving service subscribed to the same \u201cchannel\u201d that we posted to can pick up that message. <\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2021-10-30-messaging-and-madness%2Fhello-world-example-routing.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2021-10-30-messaging-and-madness%2Fhello-world-example-routing.png\" alt=\"Hello World Visualization\"><\/a><br>\nvia <a href=\"https:\/\/www.rabbitmq.com\/tutorials\/amqp-concepts.html\" rel=\"noopener noreferrer\">Rabbit MQ Tutorials<\/a><\/p>\n\n<p>Let\u2019s dive a little further down; the <em>publisher<\/em> service publishes a message to an <em>exchange<\/em> on a <em>broker<\/em>. This exchange has <em>routes<\/em> that lead to <em>queues<\/em>, or \u201cchannels,\u201d where the payload is published. We make sure to include the sending information with our message to be routed to the correct queue. The broker cannot see the message, although it might look into any metadata attached to the message from the publisher. This workflow asynchronously sends messages. Imagine a server version of a mail sorting machine shooting letters into the correct mail slot based on the address.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2021-10-30-messaging-and-madness%2Fmail_sorting.gif\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2021-10-30-messaging-and-madness%2Fmail_sorting.gif\" alt=\"Mail Sorting Gif from MIB II\"><\/a><\/p>\n\n<p>When referring to a publisher, I mean some code that we utilize to connect and send a message. AMQP is programmable, so I can shape it to fit most situations. In this case, we need to send messages to our different software suites to trigger actions to happen. Learning this took some time, but it\u2019s been simple to implement. <\/p>\n\n<p>There are different types of exchanges that we can use to make these services fit our needs. I\u2019m going to explain what we use briefly.<\/p>\n\n<p>We use a <em>direct exchange<\/em> utilizing <em>routing keys<\/em> to bind queues to exchanges. Our code can use direct exchanges to distribute tasks to many different endpoints, but we used these direct exchanges to make direct routes between our services. Other types of exchanges can be used to broadcast messages. More information can be found <a href=\"https:\/\/www.rabbitmq.com\/tutorials\/amqp-concepts.html\" rel=\"noopener noreferrer\">here<\/a>. For now, we\u2019re going to focus on direct exchanges. <\/p>\n\n<h3>\n  \n  \n  AMQP and Amazon MQ <a><\/a>\n<\/h3>\n\n<p>We touched on all that because I wanted to talk about <a href=\"https:\/\/aws.amazon.com\/amazon-mq\/?amazon-mq.sort-by=item.additionalFields.postDateTime&amp;amazon-mq.sort-order=desc\" rel=\"noopener noreferrer\">Amazon MQ<\/a>. Amazon MQ is a fully managed platform for setting up message brokers. Amazon MQ utilizes both RabbitMQ and Apache Active MQ for creating brokers. We\u2019re sticking with Rabbit MQ for the time being.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2021-10-30-messaging-and-madness%2Famazon_mq_dash.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2021-10-30-messaging-and-madness%2Famazon_mq_dash.png\" alt=\"Amazon MQ Dashboard\"><\/a><\/p>\n\n<p>Here above, you can see you can easily set up a broker in just a few clicks. I left most of the settings on default, except for choosing \u201cRabbitMQ\u201d for our broker engine and setting some security up for accessing our management console. <\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2021-10-30-messaging-and-madness%2Frabbit_mq_dash.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2021-10-30-messaging-and-madness%2Frabbit_mq_dash.png\" alt=\"Rabbit MQ Management Console\"><\/a><\/p>\n\n<p>Once we get that, we have access to the RabbitMQ dashboard Amazon MQ created and is managing. Now that we have a broker set up, we can play with some code. <\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2021-10-30-messaging-and-madness%2Fcode.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2021-10-30-messaging-and-madness%2Fcode.png\" alt=\"Code\"><\/a><\/p>\n\n<p>Above I use the library <a href=\"https:\/\/github.com\/celery\/kombu\" rel=\"noopener noreferrer\">Kombu<\/a> to create some connections and send some stuff. I started by setting up our environment variables. Then created exchange and queue objects. Finally, I made our connection object and the producer object, and then we sent a simple \u201cHello\u201d message.<\/p>\n\n<h3>\n  \n  \n  Serialization <a><\/a>\n<\/h3>\n\n<p>Serialization is <a href=\"https:\/\/www.tutorialspoint.com\/object_oriented_python\/object_oriented_python_serialization.htm\" rel=\"noopener noreferrer\">another blog post<\/a>, but I chose to use JSON to serialize the payload. In the production software, I use a combination of JSON and <a href=\"https:\/\/docs.python.org\/3\/library\/pickle.html\" rel=\"noopener noreferrer\">Pickle<\/a> to serialize things like image data.<\/p>\n\n<p>Now we can see our message published on the queue I declared in our publisher service. An identical receiving service would be set up on the other side to read out messages sent to that queue.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2021-10-30-messaging-and-madness%2Fresults.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2021-10-30-messaging-and-madness%2Fresults.png\" alt=\"Results\"><\/a><\/p>\n\n<h3>\n  \n  \n  Conclusion <a><\/a>\n<\/h3>\n\n<p>In conclusion, using Amazon MQ allows us to set up managed brokers for us to send messages. With AMQP as the broker engine, we have a lightweight message-sending workflow. Thanks for reading.<\/p>\n\n<p>-George<\/p>\n\n","category":["python","aws","amqp","amazonmq"]},{"title":"Health Checking S3 and DynamoDB in AWS","pubDate":"Wed, 03 Mar 2021 14:28:03 +0000","link":"https:\/\/dev.to\/aws-builders\/health-checking-s3-and-dynamodb-in-aws-3ocl","guid":"https:\/\/dev.to\/aws-builders\/health-checking-s3-and-dynamodb-in-aws-3ocl","description":"<p><em>Originally published on my personal blog <a href=\"https:\/\/georgeoffley.com\/aws\/python\/checking-health-in-s3-and-dynamodb.html\" rel=\"noopener noreferrer\">georgeoffley.com<\/a><\/em><\/p>\n\n<h2>\n  \n  \n  Table Of Contents\n<\/h2>\n\n<ul>\n<li>Introduction<\/li>\n<li>Problem<\/li>\n<li>S3 Solution<\/li>\n<li>DynamoDB Solution<\/li>\n<li>Conclusion<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Introduction <a><\/a>\n<\/h3>\n\n<p>A hybrid infrastructure has tons of exciting challenges. Although we host a great deal of our software in AWS at my company, we cannot do everything in the cloud. As such, we have tons of physical infrastructure as well. This hybrid infrastructure presents many challenges that we strive to overcome on the software team. One of the challenges we are working towards is imaging and utilizing software to detect our yields. This piece of that puzzle will focus on storage for our images.<\/p>\n\n<p>We decided that we would use a combination of services offered by AWS. The first is the Amazon Simple Storage Service or S3 for image storage and DynamoDB for holding metadata of said images. Given that we are getting information straight from hardware, many things might go wrong, from getting the pictures to when said pictures are pushed to AWS. This brings us to this evening\u2019s question: How can I be sure these services are available for me to send stuff to? <\/p>\n\n<h3>\n  \n  \n  Problem <a><\/a>\n<\/h3>\n\n<p>Well, as it turns out, there are a few ways this can be done. For example, there are libraries out there that will scan health check websites to see if AWS has any service outages. This would not be a great way to do health checks for a production application. So, I decided to spike this problem and make something myself. I am not worried about AWS services being out as they have high availability using their different availability zones. I am more concerned about our endpoints failing, internet issues, or Cloverfield monsters. So, this needs to be explored.<\/p>\n\n<h3>\n  \n  \n  S3 Solution <a><\/a>\n<\/h3>\n\n<p>A simple solution for checking the health of my resources was needed. Luckily, I quickly put something together using the <a href=\"https:\/\/boto3.amazonaws.com\/v1\/documentation\/api\/latest\/index.html\" rel=\"noopener noreferrer\">Boto3 library<\/a>, which is the AWS SDK for Python. This library gives us easy access to the AWS API for configuring and managing services. The first thing I did was create an object class to utilize the Client class in Boto3.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2021-03-03-checking-health-in-s3-and-dynamodb%2Fclient_object.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2021-03-03-checking-health-in-s3-and-dynamodb%2Fclient_object.png\" alt=\"Client Object\"><\/a><\/p>\n\n<p>We only need to pass in our access credentials and the services we want to create a client object for, and we get our client object back. Each turn in Boto3 allows for interacting with the Client class. The docs define the Client class as <a href=\"https:\/\/boto3.amazonaws.com\/v1\/documentation\/api\/latest\/reference\/services\/s3.html#client\" rel=\"noopener noreferrer\">\u201ca low-level client representing whatever service\u201d<\/a>. In most cases, you would use it to access the various functions for interacting with the service. <\/p>\n\n<p>After that, I put together some simple logic to return some information on the resource we are looking for. In our case, we were trying to get access to a bucket where we will store images. This solution is enough to satisfy me that the resource exists, and I can communicate with it. Below is the code I used for S3.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2021-03-03-checking-health-in-s3-and-dynamodb%2Fs3.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2021-03-03-checking-health-in-s3-and-dynamodb%2Fs3.png\" alt=\"S3\"><\/a><\/p>\n\n<p>The code above sets up a new client instance and utilizes the <a href=\"https:\/\/boto3.amazonaws.com\/v1\/documentation\/api\/latest\/reference\/services\/s3.html#S3.Client.head_bucket\" rel=\"noopener noreferrer\"><em>head_bucket()<\/em> function<\/a>. This is great for seeing if a bucket exists and if the entity polling it has permissions to access it. In my case, I only need to be able to see if I get a message back. So, I pass in the bucket name, and I can receive a 200 message back from the server if the resource is there and I have access to it. I like this approach because it is dead simple, and I also get to utilize the custom exception that we get access to using the client object, which is the <em>NoSuchBucket<\/em> exception. Using this exception allows us to be concise with our exceptions. <\/p>\n\n<p>There were some questions about the limitations on being able to use something like this. We expect to use this frequently to pole S3 and make sure that we can talk to our bucket. If AWS is not available, we need to turn off the spigot and stop our software from sending stuff to AWS and not lose messages in the void of space. That said, we will be polling a few times a second at least; luckily for us, <a href=\"https:\/\/aws.amazon.com\/about-aws\/whats-new\/2018\/07\/amazon-s3-announces-increased-request-rate-performance\/\" rel=\"noopener noreferrer\">S3 upped their request rate to 3500 to add data and 5500 for retrieving data<\/a>. This gives us plenty of room to be able to pole what we need. <\/p>\n\n<h3>\n  \n  \n  DynamoDB Solution <a><\/a>\n<\/h3>\n\n<p>With the client object that we created above, we can also use that to access DynamoDB. As such, the code is below:<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2021-03-03-checking-health-in-s3-and-dynamodb%2Fdynamo.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgeorgeoffley-blog-images.s3.amazonaws.com%2F2021-03-03-checking-health-in-s3-and-dynamodb%2Fdynamo.png\" alt=\"Dynamo\"><\/a><\/p>\n\n<p>The above code snippet does the same thing as the S3 code does. We create a new instance, and we use the <a href=\"https:\/\/boto3.amazonaws.com\/v1\/documentation\/api\/latest\/reference\/services\/dynamodb.html#DynamoDB.Client.describe_table\" rel=\"noopener noreferrer\"><em>describe_table()<\/em> function while passing in the table name<\/a>. This function returns information about the table, including the status. Also, note that the <em>ResourceNotFoundException<\/em> is another custom exception provided by the Dynamo Client object. This bit of code satisfies what I need to be able to check the status of a table. Yay!<\/p>\n\n<p>Using this method also has similar challenges. The <em>decribe_table()<\/em> function uses up an eventually consistent read on your table. So, getting out-of-date data is possible if you are polling something you just created, so give it a second. If you are using a provisioned table in Dynamo, this method will take up one of your reads per second. We will need to make sure this is accounted for when we start designing our database. <\/p>\n\n<h3>\n  \n  \n  Conclusion <a><\/a>\n<\/h3>\n\n<p>The above simple bit of code was a brief spike for a solution we needed to explore. This write-up was inspired by a lot of the help I received from my fellow AWS Community Builders. Checking the health and status of services is one of many things that we will build out using AWS. I am excited to keep up my learning and building. If you have seen or made other stuff to accomplish this type of work, let me know! I would love to learn more.<\/p>\n\n","category":["aws","dynamodb","s3","python"]}]}}