<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Kurt Kemple</title>
    <description>The latest articles on Forem by Kurt Kemple (@theworstdev).</description>
    <link>https://forem.com/theworstdev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F59436%2Fe2ebdd84-f763-4874-9384-3c487d854058.jpg</url>
      <title>Forem: Kurt Kemple</title>
      <link>https://forem.com/theworstdev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/theworstdev"/>
    <language>en</language>
    <item>
      <title>The Developer Advocate's Guide to Addressing Product Friction</title>
      <dc:creator>Kurt Kemple</dc:creator>
      <pubDate>Sat, 23 Oct 2021 03:06:09 +0000</pubDate>
      <link>https://forem.com/theworstdev/the-developer-advocates-guide-to-addressing-product-friction-1p4j</link>
      <guid>https://forem.com/theworstdev/the-developer-advocates-guide-to-addressing-product-friction-1p4j</guid>
      <description>&lt;p&gt;Over the last three months, we've been developing a framework at Apollo called DX Audits to help us identify, document, report, and address product friction.&lt;/p&gt;

&lt;p&gt;Our team and company is growing quickly and it was becoming increasingly difficult to address product friction. We wanted a framework that would help us make that part of developer advocacy more repeatable, teachable, and reportable.&lt;/p&gt;

&lt;p&gt;So, with a rough outline of a framework and our eyes bright and full of hope, we embarked on a journey of experimentation that led us to some fascinating places. We cried, laughed, and cried some more, and in the end, we discovered that the fundamentals behind these audits were sound and can provide a lot of value, but we were working with the wrong separation of concerns!&lt;/p&gt;

&lt;p&gt;In this article, I'll share what worked and what didn't work in the first version, how v2 differs from v1, and then we'll look at the updated DX audit process.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you're not familiar with the first version of the &lt;a href="https://www.apollographql.com/blog/community/devrel/dx-audits-a-framework-for-developer-advocacy/" rel="noopener noreferrer"&gt;DX Audit framework&lt;/a&gt; or if you just want to know what the framework looks like, you can skip to the "DX Audits v2" section. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What we learned
&lt;/h2&gt;

&lt;p&gt;Overall the framework is solid. Adding structure around how we approach understanding developer pain points and delivering that feedback to other teams has largely impacted our dev advocacy work at Apollo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;p&gt;The biggest win of the process by far was the friction logs. They have already had a significant impact on our ability to demonstrate the problems community members are facing. Other teams loved the detailed walkthroughs and additional context that we could provide with our insider knowledge. Because we were looking at developer workflows holistically, it exposed friction that otherwise was undocumented or unknown.&lt;/p&gt;

&lt;p&gt;Aside from friction logs, we also benefitted from the audit process in two other significant ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Consistency and structure -&lt;/strong&gt; DX audits provide structure around what is otherwise an abstract part of developer advocacy. For example, our newest team member found it easier to understand how everyone approached delivering feedback because we all spoke the same language and followed the same process. On the other side, using the framework allowed us to extend that same consistency to other teams. For example, we now all deliver feedback in a unified format. A consistent method of feedback makes it easier for other teams to integrate it into their workflows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proof of impact -&lt;/strong&gt; Ask any developer advocate what the most challenging part of the job is, and they'll likely say it's proving the impact they have. It's always been notoriously difficult to track the outcomes that stem from feedback. Now, we can keep track of our accomplishments in our DevRel database. Saving every friction log and action item that stems from an audit provides a direct paper trail from our work to the resulting changes made throughout the Apollo platform and the company.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Drawbacks
&lt;/h3&gt;

&lt;p&gt;While overall, the process was a success, there were some issues with the first version of DX audits. Navigating any new approach will bring challenges, but the three things that caused significant friction (pun 100% intended) were: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Slow feedback loop -&lt;/strong&gt; I listed &lt;strong&gt;consistency and structure&lt;/strong&gt; as benefits from DX audits, but the framework created slow feedback loops in its original form. For example, with the cycle taking place over a few months, a friction log done in week two wouldn't technically get reported on or have any action items done to improve that friction for another five weeks or more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workload bottlenecks -&lt;/strong&gt; With everyone on the team going through the cycle together, we ended up with surges in activity during certain stages and lulls in others. A more concrete example is that we released very little content during the build phase, but then during the implementation phase (now called the follow up phase), we had a surge of content in response to the findings in the audits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Too much ceremony -&lt;/strong&gt; We were doing way too much on the reporting front. I'm generally a big believer that you can't have too much documentation. Still, the original framework caused a lot of duplicated effort around documenting and reporting on our findings to others. So we spent a lot of time figuring out the best way to organize our feedback to be respectful of everyone's time and avoid duplication of communication.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Our epiphany
&lt;/h2&gt;

&lt;p&gt;As I mentioned before, the framework was sound, but we used the wrong separation of concerns! The most significant issues we faced were related to timing. Forcing each use case to wait for all the others to advance to the next step in the process created a bottleneck, preventing value from being created until the very end of the process.&lt;/p&gt;

&lt;p&gt;Now, audits are scoped to an individual use case, and developer advocates move through each step independently of other use cases. This allows us to provide value in a much shorter timeframe.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzktkbwl78e8yk17htcmr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzktkbwl78e8yk17htcmr.png" alt="Illustration showcasing each version of the audit process as a timeline. It shows the stark difference in time to receive feedback in each version of the framework. (1 week instead of 5)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  DX Audits v2
&lt;/h2&gt;

&lt;p&gt;The goal of a DX audit is to document, report, and address product friction by having a developer advocate experience a given developer workflow, document and report their findings, and surface actionable steps to take to reduce friction.&lt;/p&gt;

&lt;p&gt;An audit is scoped to a single use case that a developer advocate wants to experience. A use case is essentially a workflow that a developer would have to go through to complete a given task (i.e., add monitoring to a GraphQL server).&lt;/p&gt;

&lt;p&gt;Audits consist of four steps. Discover, build, report, and follow up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fagc1y910xdlqtuh59kl7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fagc1y910xdlqtuh59kl7.png" alt="An infographic showing the flow through the four steps of the dx audit framework. Each step has four bullets below it summarizing each step of the framework."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Download the &lt;a href="https://theworst.dev/dx-audits-flow.png" rel="noopener noreferrer"&gt;full-size version&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Discover
&lt;/h3&gt;

&lt;p&gt;This step is the work before the work. Discovery is where developer advocates should gather as much context about the use case they're about to audit. Depending on what initiates the audit, you might already have enough context to move ahead. However, there may be times you want to gather more information. In those cases, some great places to get feedback are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Community and customers&lt;/strong&gt; - GitHub, forums, social media, events, surveys and forms, issues raised by solutions, support and customer success, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Input from stakeholders&lt;/strong&gt; - product updates, roadmaps, engineering timelines, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What makes these audits so valuable to others is that aside from identifying friction, we also use our insider knowledge to surface actionable steps we can take to remedy it. Your feedback is only as good as the context you have!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you don't spend the time to make sure you have the full scope of the use case and have strong relationships with other teams, your feedback won't be as impactful as it could. Check out &lt;a href="https://theworst.dev/developer-advocates-guide-to-getting-buy-in" rel="noopener noreferrer"&gt;The Developer Advocate's Guide to Getting Buy-in&lt;/a&gt; to learn more about providing quality feedback.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Build
&lt;/h3&gt;

&lt;p&gt;During this step, you'll work through the developer workflow from the previous step and record your experience in a friction log. Generally, developer advocates build a project that allows you to experience the workflow you want to audit.&lt;/p&gt;

&lt;p&gt;What you build could be anything from an example app to working entirely within a given product UI. The important part is that you complete the workflow from start to finish with as much empathy and minimal assumptions as possible.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Friction logging is an excellent opportunity to create some content as well! For example, live streaming yourself going through these workflows and open-sourcing any projects you build can be a great resource of information for developers and an opportunity to get feedback from the community!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here are some helpful best practices we've landed on for making the most out of friction logs!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Channel your empathy&lt;/strong&gt; – You want to approach the workflow as a developer might. Try to make no assumptions and question if the step would be more difficult for someone without your insider knowledge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More detail is better than less&lt;/strong&gt; – The goal is to provide enough context about the steps you took to achieve your goal that anyone can read the document and understand or retrace your steps to reach the same outcome.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't forget the good&lt;/strong&gt; – When you experience something delightful, make sure to document that and also be sure to include the positive experiences when summarizing a friction log!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency is key&lt;/strong&gt; – Everyone should be using the same template to create friction logs. Of course, DAs should have the freedom to use whatever tools allow them to be most productive, but friction logs need to be accessible and structured similarly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Report
&lt;/h3&gt;

&lt;p&gt;The purpose of this step is to create a clear outline of what we see as wins and issues and provide that feedback to related decision-makers as quickly as possible.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Developer advocates should use their best judgment when deciding where and when to deliver feedback from an audit. In scenarios where someone may not expect input, it's best to make sure you include the right people and that you've done enough work upfront to &lt;a href="https://theworst.dev/developer-advocates-guide-to-getting-buy-in" rel="noopener noreferrer"&gt;get the buy-in, you'll need&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once a friction log is complete, the next step is to summarize and report your findings to involved parties. Add a detailed executive summary to the top of the friction log, including the highs and lows of the experience, any realizations or insights you uncovered. Be sure to document possible action items decision-makers could take to address any friction points discovered and add them to the friction log.&lt;/p&gt;

&lt;h3&gt;
  
  
  Follow Up
&lt;/h3&gt;

&lt;p&gt;In this step, DAs work on the action items outlined in the friction log and track progress from any items that require cross-team collaboration.&lt;/p&gt;

&lt;p&gt;It's essential to ask action item owners for a link to track the progress of the work. Having a direct link to the work done in response to your feedback allows you to 1) make sure you follow up and nothing falls through the cracks, and 2) directly connects the audit to every Jira issue, Airtable entry, or document that resulted from your feedback.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We use Airtable and some automation to make sure we see action items through to completion.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw3g39bhodzv3mvzp2nsm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw3g39bhodzv3mvzp2nsm.png" alt="A kanban view in Airtable that shows action items being moved through stages of completion. Each card in the "&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;DX Audits provide structure and make it easier to teach, repeat, and report on a part of developer advocacy work that is difficult to quantify. Not only are the audits beneficial to the DevRel team, but many other teams at Apollo have found them valuable, and they are becoming a standard part of our collaboration process.&lt;/p&gt;

&lt;p&gt;While the initial version of DX audits was beneficial in many ways, we didn't realize those benefits until the very end of the cycle. Scoping audits down to a single-use case allows us to deliver value much faster while still maintaining enough structure to support our goals around collaboration and consistency.&lt;/p&gt;

</description>
      <category>devrel</category>
      <category>frictionlogs</category>
      <category>howto</category>
    </item>
    <item>
      <title>The Developer Advocate's Guide to Getting Buy-In</title>
      <dc:creator>Kurt Kemple</dc:creator>
      <pubDate>Wed, 13 Oct 2021 04:20:22 +0000</pubDate>
      <link>https://forem.com/theworstdev/the-developer-advocates-guide-to-getting-buy-in-1ba4</link>
      <guid>https://forem.com/theworstdev/the-developer-advocates-guide-to-getting-buy-in-1ba4</guid>
      <description>&lt;p&gt;It's finally time for your meeting with the Product team, and you're excited to share some feedback you got from the community. Not only that, but you even have an idea of how to fix the issue! You sit down at your computer, fire up that Zoom call, give yourself a quick check, and join. Eventually, your turn comes around, and you explain the problem and the possible fix. Everyone is super excited to receive your feedback and loves your idea! Victory!&lt;/p&gt;

&lt;p&gt;You follow up and ask when they think they'll be able to prioritize that work. You eagerly wait as the product team talks about timelines and current projects, eventually saying, "We want to do it, but we're focused on X until the end of this year. So let's circle back." Finally, the meeting wraps up, everyone says their goodbyes, and you leave the meeting feeling frustrated. You know this issue is essential, so why are they not prioritizing it?&lt;/p&gt;

&lt;p&gt;There are many reasons that decision-makers may not act upon the feedback we deliver. Still, one thing we can always ask ourselves is, "did I get enough buy-in before I asked them to commit?"&lt;/p&gt;

&lt;p&gt;In this post, I'll cover what buy-in is, how it applies to developer advocacy, what skills help the most when trying to get buy-in, and the processes I use.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is buy-in?
&lt;/h2&gt;

&lt;p&gt;Buy-in is an agreement to support a decision. So, when we are trying to get buy-in, we're trying to get decision-makers to support our ideas. So, the act of getting buy-in is a process that involves building trust, communicating your ideas well, and hopefully creating champions so that when you ask for a commitment, you already have the right people on board.&lt;/p&gt;

&lt;h2&gt;
  
  
  Buy-in &amp;amp; developer advocacy
&lt;/h2&gt;

&lt;p&gt;You might often hear developer advocates say they advocate on behalf of the community, but what exactly do they advocate for, and to who?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Developer advocates advocate for changes to a company's products, offerings, and software based on friction experienced by developers in the community.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Getting buy-in as a developer advocate is a unique challenge. We usually are not the owners or even direct contributors to what we're trying to change. Instead, we represent this bizarre ephemeral thing called a "community."&lt;/p&gt;

&lt;p&gt;Because of this relationship, we have to be extremely careful in our approach to initiating change. We have to go the extra mile and make sure we've built a relationship with the people we need in our corner.&lt;/p&gt;

&lt;p&gt;We need to take the time to make sure we understand what they are currently invested in, what effect our changes would have on their plans, and the amount of work it would take to make it happen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Skills to develop for getting buy-in
&lt;/h2&gt;

&lt;p&gt;One thing you might have noticed is that getting buy-in is all about working with other people. As such, the skills that will show the most dividends will be the ones that help you interface with the most complex computers of all, people.&lt;/p&gt;

&lt;h3&gt;
  
  
  Communication
&lt;/h3&gt;

&lt;p&gt;Getting someone to support your ideas will be difficult if you cannot clearly state the problem, present a solution (if you have one), and provide enough context and supporting information to make informed decisions.&lt;/p&gt;

&lt;p&gt;A significant part of developer advocacy is helping people understand their problems with a given product/technology and providing solutions. Lean on that!&lt;/p&gt;

&lt;p&gt;Make sure to explain the problem in a relatable way to whoever it is you are trying to educate. Make sure you're framing the problem so that they can see how it will affect their success. For example, are they tracking MAUs (monthly active users) for a particular feature? Will this fix increase that metric? Look for commonality!&lt;/p&gt;

&lt;h3&gt;
  
  
  Empathy
&lt;/h3&gt;

&lt;p&gt;It's important to remember that initiating change requires consent from all involved parties. So we need to build relationships with the people we'll ask to help us and ensure that the relationship is mutually beneficial. We can do that by understanding what goals they are working towards, what metrics they are concerned with, and what plans they have for the future.&lt;/p&gt;

&lt;p&gt;When we include these things in our conversations with them, it shows we've thought about what effect our changes will have on them and how it could benefit them and goes a long way towards building trust.&lt;/p&gt;

&lt;h3&gt;
  
  
  Patience
&lt;/h3&gt;

&lt;p&gt;Change is slow! Sometimes it might take a significant amount of time to get the buy-in you need to push something through. Depending on the size of the company you work for, this could be months for things that feel like they should be quick.&lt;/p&gt;

&lt;p&gt;Make sure you're aware of product roadmaps and engineering timelines—plan for changes to take a while if adopted at all. Also, have fallbacks and short-term fixes to help reduce friction until you can get a proper fix.&lt;/p&gt;

&lt;h3&gt;
  
  
  Persistence
&lt;/h3&gt;

&lt;p&gt;You might do all the right things and STILL not get buy-in. It happens! It's essential not to give up and look for other avenues to get the buy-in to initiate that change. This process is a cycle, and you repeat it until you get the desired outcome.&lt;/p&gt;

&lt;p&gt;Look for other ways to help remove that friction for users. For example, are there any intermediate steps you can take or content that you can create to help people work through it?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It's important to constantly reassess the efficacy of the change as time goes on as it may become obsolete.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Tips for getting buy-in
&lt;/h2&gt;

&lt;p&gt;So you know the skills you need to improve your odds of getting buy-in, but how do you put that into practice? Here are some of the tactics I've used to initiate change.&lt;/p&gt;

&lt;h3&gt;
  
  
  Collect data
&lt;/h3&gt;

&lt;p&gt;Want to get someone on board for a change you are proposing? Show them quantitative data related to their goals, and it won't take much of a conversation.&lt;/p&gt;

&lt;p&gt;Collect as much qualitative data and quantitative data as you possibly can. Qualitative data is feedback provided by the community or findings from your investigations. Quantitative data is the metrics that relate to the area you want to change.&lt;/p&gt;

&lt;p&gt;Quantitative data is more valuable but usually harder to connect directly to a pain point developers are facing. Qualitative data holds less value but is generally easier to collect. If you lack quantitative data, it's essential to gather as much qualitative data as possible!&lt;/p&gt;

&lt;h3&gt;
  
  
  Record experiences
&lt;/h3&gt;

&lt;p&gt;We know that empathy is an effective tool for helping us better understand the needs of people we communicate with, but we can also use empathy to help others understand the frustration users feel when they experience a particular pain point.&lt;/p&gt;

&lt;p&gt;By recording either our own or users' experiences with a given workflow, we can clearly frame the issue for others. In addition, sometimes, users will experience the same pain point across multiple workflows, which helps outline the severity of the problem.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;At Apollo, we use &lt;a href="https://www.apollographql.com/blog/community/devrel/dx-audits-a-framework-for-developer-advocacy/"&gt;friction logs&lt;/a&gt; to record experiences.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Build desired outcomes
&lt;/h3&gt;

&lt;p&gt;Building desired outcomes is a technique I brought over from my time as a tech lead. Tech lead is another position that is constantly initiating change. One of the techniques I came to rely upon was building prototypes or desired outcomes so that decision-makers could experience the change.&lt;/p&gt;

&lt;p&gt;A more concrete example is when I wanted to adopt GraphQL at Major League Soccer. I knew it would solve many problems for us, but I needed everyone else to understand that too. Our existing architecture consisted of REST APIs, and our product managers would often examine data from these APIs due to partnerships we had with other companies.&lt;/p&gt;

&lt;p&gt;Because they wanted to explore the data, we would build an "API browser" or small client application that allowed people to interact with the API through a UI. Since we discussed rewriting the API and versioning it again, I knew that we would need to build these UIs again. Knowing that product managers rely on this, I showed them how we could get the same functionality from &lt;a href="https://graphiql-test.netlify.app/"&gt;GraphiQL&lt;/a&gt; if we adopted GraphQL. The idea of getting that same result without any development effort was exciting to them.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It's much easier to decide on something when you can experience its benefits before you build it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Look for alignment
&lt;/h3&gt;

&lt;p&gt;Sometimes getting enough buy-in can be the result of aligning your changes with existing plans to change something! So stay up to date on the product roadmap, look for opportunities to include your changes into a current initiative.&lt;/p&gt;

&lt;p&gt;I recently spoke with someone trying to get the buy-in to dedicate engineering time to their navigation component. The existing solution was requesting the navigation metadata on the client-side. Not rendering the navigation on the server prevents some SEO benefits you get by having navigation be crawlable.&lt;/p&gt;

&lt;p&gt;They have wanted to implement this fix for a while and tried to get buy-in for it previously. However, it wasn't until a new project for the navigation came along that they were able to resurface the change and finally get the buy-in they needed as the work aligned with the project.&lt;/p&gt;

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

&lt;p&gt;As developer advocates, we'll often face situations where the best way to help the community is through initiating change. However, because we're generally asking people to change things they are responsible for, we have to be sure we're doing our due diligence to understand the changes we're asking people to make. We have to provide so much compelling evidence for our case that not only do they support our ideas but champion them as well.&lt;/p&gt;

</description>
      <category>devrel</category>
      <category>communication</category>
      <category>howto</category>
    </item>
    <item>
      <title>Distributing Challenge: On Building Highly Engaged Teams</title>
      <dc:creator>Kurt Kemple</dc:creator>
      <pubDate>Tue, 05 Oct 2021 01:53:21 +0000</pubDate>
      <link>https://forem.com/theworstdev/distributing-challenge-on-building-highly-engaged-teams-2d3c</link>
      <guid>https://forem.com/theworstdev/distributing-challenge-on-building-highly-engaged-teams-2d3c</guid>
      <description>&lt;p&gt;I've been thinking a lot over the last few years about how vital the distribution of challenge is to a team's success.&lt;/p&gt;

&lt;p&gt;In fact, it's one of the primary considerations I have when managing.&lt;/p&gt;

&lt;p&gt;How many developers do you know who have left their job because either 1) the work is no longer challenging / there is no career growth, or 2) the work is too challenging, and they have no support?&lt;/p&gt;

&lt;p&gt;Challenge plays an essential role in our happiness.&lt;/p&gt;

&lt;p&gt;However, making sure that everyone on a team, in an org, or in a company is adequately challenged is a complicated task.&lt;/p&gt;

&lt;p&gt;In response, I've developed a model called the &lt;code&gt;Pyramid of Challenge&lt;/code&gt; that I use whenever I am managing others.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pryamid of Challenge
&lt;/h2&gt;

&lt;p&gt;The model is composed of a triangle which represents a group's entire workload. The &lt;code&gt;x axis&lt;/code&gt; represents the amount of work available and the &lt;code&gt;y axis&lt;/code&gt; represents the complexity of the work available. Together they represent that as work increases in complexity, it decreases in availablity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foossjx96rc28e64x0mm4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foossjx96rc28e64x0mm4.png" alt="an illustration titled "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ensuring everyone is challenged is about ensuring everyone on the team has the correct workload.&lt;/p&gt;

&lt;h2&gt;
  
  
  Balancing the Distribution of Challenge
&lt;/h2&gt;

&lt;p&gt;In order to have a balanced distribution of challenge, you need a team makeup that doesn't leave any gaps in the pyramid or put too many people into one part of the pyramid, creating a &lt;code&gt;challenge gap&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A challenge gap is an area of responsibility for a team that either doesn't have anyone challenged by that work, or the work is too challenging for anyone on the team.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftgfur95qalt376awgcsp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftgfur95qalt376awgcsp.png" alt="an illustration titled "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you compare that previous illustration to most teams today, it's starkly different. So is this a practical model?&lt;/p&gt;

&lt;p&gt;If we apply the model to the responsibilities of a team tasked with building an application, you can see that it holds up. As the work decreases in complexity it increases in availability.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi72wyi45iy7kg3pkzdfm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi72wyi45iy7kg3pkzdfm.png" alt="an illustration titled "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You only need 1 or 2 people to architect an application, but you'll need many more to build it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;So why is this important?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's important because if we don't provide people with the right level of responsibilities so that they are properly challenged it could grind your team's productivity to a halt.&lt;/p&gt;

&lt;p&gt;With a model to work from, let's look at some of the most common team makeups you'll come across and discuss some of the challenge gaps they face.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A challenge gap is an area of responsibility for a team that either doesn't have anyone challenged by that work, or the work is too challenging for anyone on the team.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Analyzing Common Distributions of Challenge
&lt;/h2&gt;

&lt;p&gt;As we look at these distributions, it's important to remember that teams will come in all different sizes and makeups, and some teams that fit into one of these common distributions might be really high performing, happy, and engaged.&lt;/p&gt;

&lt;p&gt;It's also very likely that teams will more accurately reflect a combination of these distributions. This model is meant as a guide to help you create a holistic view of your teams makeup according to their experience level and the work available for the team. &lt;/p&gt;

&lt;h3&gt;
  
  
  Top Distribution of Challenge
&lt;/h3&gt;

&lt;p&gt;Let's start with the most common distribution of challenge, the top distribution. If a team has too many senior members, it suffers from a challenge gap at the bottom of the pyramid.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7x4fwjl7dftabx56ra7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7x4fwjl7dftabx56ra7.png" alt="illustration titled "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Senior developers are forced to do the less complex and more frequent tasks even though it's not challenging, essentially leaving them toiling. These teams could suffer from overly complex software, inability to reach consensus, and high turnover as team members leave to seek new challenges.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bottom Distribution of Challenge
&lt;/h3&gt;

&lt;p&gt;Another makeup we see often is bottom-distributed teams or a team without enough seniorty or leadership. These teams suffer from a challenge gap at the top of the pyramid.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frsiydgy2sr0w2zerzilh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frsiydgy2sr0w2zerzilh.png" alt="illustration titled "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These teams face a situation where they are overchallenged by not having the skills/experience needed to meet their responsibilities. Team members are likely to suffer from burnout and software could be brittle without proper guidance from more experienced developers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Opposing Distribution of Challenge
&lt;/h3&gt;

&lt;p&gt;Another makeup you might see is the opposing distribution of challenges. These teams tend to have one or two very senior people and then more junior developers.&lt;/p&gt;

&lt;p&gt;These teams face a challenge gap at the center of the pyramid.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkpszyqvb64wlpm8spirr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkpszyqvb64wlpm8spirr.png" alt="illustration titled "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With an opposing distribution of challenges, senior developers will be forced to work on all non-challenging tasks that more junior developers aren't capable of handling yet, while also tyring to mentoring them.&lt;/p&gt;

&lt;p&gt;This will greatly impact their ability to handle their own responsibilities while other responsibilities get dropped or mishandled.&lt;/p&gt;

&lt;p&gt;The less experienced developers won't get the support they need and will often be tasked with work outside their current skillset.&lt;/p&gt;

&lt;h3&gt;
  
  
  Centered Distribution of Challenge
&lt;/h3&gt;

&lt;p&gt;Lastly, we have a centered distribution of challenges. In this scenario, teams consist of mid-level developers but lack any really senior or more junior developers creating a challenge gap at each end of the pyramid.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ku46nvikkf4tqy54czp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ku46nvikkf4tqy54czp.png" alt="illustration titled "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Teams with this makeup are susceptible to infighting around responsibilities looking for work that will fit within their comfort zone. Some of the work could be too complex causing fragility in the solutions.&lt;/p&gt;

&lt;p&gt;It's also possible for teams of this makeup to be very process heavy as team members look for ways to contribute. Some team members may try to step up and take on responsibilities that are too challenging to fill gaps and burnout.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Framework for Growth
&lt;/h2&gt;

&lt;p&gt;Another significant benefit I've found from using this model is that it creates a system that makes it easier to scale a team or teams as you take on more responsibility because the pyramid can be applied to any level of challenge.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fftgm3zesspy43n4soqxw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fftgm3zesspy43n4soqxw.png" alt="an illustration titled "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Caveats &amp;amp; Conclusion
&lt;/h2&gt;

&lt;p&gt;When it comes to humans we're better served by communication than models.&lt;/p&gt;

&lt;p&gt;While this model might help you identify potential gaps in challenge, it's more important to constantly check in with your team and make sure they are in fact happy, engaged, and challenged appropriately.&lt;/p&gt;

</description>
      <category>management</category>
      <category>teambuilding</category>
      <category>leadership</category>
    </item>
    <item>
      <title>Visualizing Focus with Neurosity's Notion and AWS Amplify</title>
      <dc:creator>Kurt Kemple</dc:creator>
      <pubDate>Thu, 16 Jan 2020 16:36:44 +0000</pubDate>
      <link>https://forem.com/theworstdev/visualizing-focus-with-neurosity-s-notion-and-aws-amplify-57gg</link>
      <guid>https://forem.com/theworstdev/visualizing-focus-with-neurosity-s-notion-and-aws-amplify-57gg</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fn1ihbioag6hpsiuk46ve.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fn1ihbioag6hpsiuk46ve.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That brain of mine is something more than merely mortal, as time will show.&lt;/strong&gt; - &lt;em&gt;Ada Lovelace&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Right now, billions of people around the world are tracking their health with some sort of device. Heart rate, sleeping patterns, exercise, steps taken, calories in and out, all kinds of metrics are recorded to help individuals better understand what their body is doing.&lt;/p&gt;

&lt;p&gt;However, none of this data can help you understand what's going on in your brain. It's unfortunately difficult to monitor your brain activity, this is where &lt;a href="https://neurosity.co/" rel="noopener noreferrer"&gt;Neurosity&lt;/a&gt; comes in. I was lucky enough to be selected to try out the first edition of their headset, the Notion.&lt;/p&gt;

&lt;p&gt;The Notion reads your brainwaves and allows you to collection data about things like your calmness or focus, as well as train models to execute certain commands when it encounters the corresponding brainwaves. Essentially turning thought into action.&lt;/p&gt;

&lt;p&gt;I really like data-driven health and it's been a really big part of my life over the last few years. There is something about graphing the body that really appeals to me, so when I discovered Neurosity I was extremely excited about being selected for the first round of devices released.&lt;/p&gt;

&lt;p&gt;The Notion has APIs that allow you to interact with your device and receive all the data from it. I thought a good first experiment would be to wear the Notion while I'm at my computer working and try to figure out when I'm most focused. This seemed like a good first run as I plan to do a lot of experiments around focus and how different factors can affect it.&lt;/p&gt;

&lt;p&gt;In this post I'll talk about setting up and recording the data, and in the next post I'll cover reading the data and visualizing it!&lt;/p&gt;

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

&lt;p&gt;Because I want to visualize this data I decided to spin up a new React app using &lt;a href="https://github.com/facebook/create-react-app" rel="noopener noreferrer"&gt;&lt;code&gt;create-react-app&lt;/code&gt;&lt;/a&gt;. I also knew that I would need to store the data from the headset so that I could read it back out later when I wanted to visualize it. For that part I set up a GraphQL API with [Amplify](I set up a GraphQL API with &lt;a href="https://aws-amplify.github.io/" rel="noopener noreferrer"&gt;Amplify&lt;/a&gt; and &lt;a href="https://aws.amazon.com/appsync/" rel="noopener noreferrer"&gt;AWS AppSync&lt;/a&gt; via the &lt;a href="https://aws-amplify.github.io/docs/cli-toolchain/quickstart?sdk=js" rel="noopener noreferrer"&gt;Amplify CLI&lt;/a&gt;.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up the Infrastructure
&lt;/h2&gt;

&lt;p&gt;To record the data :&lt;/p&gt;

&lt;p&gt;To set up my app and GraphQL API, I ran the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-react-app visualizing-focus
amplify init
amplify add api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also created a DynamoDB table by using the &lt;code&gt;@model&lt;/code&gt; directive in my GraphQL schema during API set up, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FocusDataPoint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not only is a table created, but all the queries and mutations needed to perform CRUD operations on this data point were created in AppSync for me and the CLI generated those queries, mutations, and subscriptions for me for use in my app and Node script.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For more on creating GraphQL APIs with Amplify and AppSync, check out the &lt;a href="https://aws-amplify.github.io/docs/js/api#automated-configuration-with-cli" rel="noopener noreferrer"&gt;docs&lt;/a&gt;!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once I had the infrastructure in place it was time to create a script to run during the day to record the data coming out of the Notion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the Tracking Script
&lt;/h2&gt;

&lt;p&gt;All that I needed to start tracking my focus was a small NodeJS script that would listen for the focus events coming out of my Notion headset and send them to AppSync. It took less than 70 lines of code in total.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// in src/track-focus.js&lt;/span&gt;

&lt;span class="c1"&gt;// Get deviceId, email, and password for Notion login&lt;/span&gt;
&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// polyfill fetch for node env&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node-fetch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;global&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fetch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;global&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Notion&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@neurosity/notion&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AWSAppSyncClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws-appsync&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;graphql-tag&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// get all config&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;amplifyConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./aws-exports&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;deviceId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DEVICE_ID&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EMAIL&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PASSWORD&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// set up Notion&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Notion&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;deviceId&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// set up client to send data to AppSync&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AWSAppSyncClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;disableOffline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;amplifyConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_appsync_graphqlEndpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;amplifyConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_appsync_region&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;amplifyConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_appsync_authenticationType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;amplifyConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_appsync_apiKey&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// copy the mutation out of the generated graphql operations created by Amplify CLI&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mutation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;gql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`mutation CreateFocusDataPoint($input: CreateFocusDataPointInput!) {
    createFocusDataPoint(input: $input) {
      id
      value
      timestamp
    }
  }
`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hydrated&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// login to Neurosity&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// listen for focus events&lt;/span&gt;
  &lt;span class="nx"&gt;mind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;focus&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// { probability: 0.51, metric: "awareness", label: "focus", timestamp:  1569961321102 }&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mutate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="nx"&gt;mutation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;probability&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First I set up the API client and Notion SDK and then set up the listener for &lt;code&gt;focus&lt;/code&gt; events coming from the headset. Now whenever I sit down to work, I can turn on the Notion, run this script, and all the data will be collected for me and stored in the cloud.&lt;/p&gt;

&lt;p&gt;We can verify that the data is being stored by running a query in the AppSync console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fzsaiirt133gztkm7zvos.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fzsaiirt133gztkm7zvos.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now all that's left is to record some data! Stay tuned for the second part of this series where I build out the frontend and data visualizations!&lt;/p&gt;

</description>
      <category>neurosity</category>
      <category>aws</category>
      <category>amplify</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Amplify at Scale - Beyond the First Users</title>
      <dc:creator>Kurt Kemple</dc:creator>
      <pubDate>Mon, 06 Jan 2020 15:24:34 +0000</pubDate>
      <link>https://forem.com/theworstdev/amplify-at-scale-beyond-the-first-users-3nkf</link>
      <guid>https://forem.com/theworstdev/amplify-at-scale-beyond-the-first-users-3nkf</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F5ecd4xbdcyblwvwelxtx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F5ecd4xbdcyblwvwelxtx.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I want to take a second to talk about why Amplify exists, the problem it's solving, and what that can mean for scale.&lt;/p&gt;

&lt;p&gt;At the end of the day the goal should be to focus as much time as possible on producing product, no matter what that is. Which means we need to automate or abstract away anything we can. The closer to the surface you can work on something, the less time you spend working on things that are not the actual product or service itself.&lt;/p&gt;

&lt;p&gt;A great example of this is the &lt;code&gt;No Code&lt;/code&gt; revolution. Services like &lt;a href="https://webflow.com/" rel="noopener noreferrer"&gt;Webflow&lt;/a&gt; and &lt;a href="https://draftbit.com/" rel="noopener noreferrer"&gt;Draftbit&lt;/a&gt; are abstracting the need to know how to code to make beautiful and engaging websites and mobile applications. However, there are times when you need to do more than what you currently can do with a No Code solution. That's where &lt;code&gt;Low Code&lt;/code&gt; solutions step in to pick up the slack.&lt;/p&gt;

&lt;p&gt;A Low Code solution is a tool/framework/etc that allows you to focus as much as possible on business logic and spend minimal time working on technical code, or code that isn't actually solving a business problem. Things like setting up APIs and authentication, or setting up data management on the client are technical code. It's very important, but isn't a feature itself, just the technological choices backing them.&lt;/p&gt;

&lt;p&gt;Something that falls under this category would be &lt;a href="https://www.gatsbyjs.org/" rel="noopener noreferrer"&gt;GatsbyJS&lt;/a&gt;. If you're unfamiliar, Gatsby is an OSS framework that allows you to build really performant and compliant websites and apps by abstracting away the messy complexity behind an API that focuses on having a small surface but being flexible enough to get really deep under the hood.&lt;/p&gt;

&lt;p&gt;Even if you have very little experience with Gatsby you can get started by creating a file in a directory and it will magically show up on your website, with all the best practices already baked in. You have to actively work against Gatsby to build a poorly performing app.&lt;/p&gt;

&lt;p&gt;Given it's flexible API, you can also really get into the nitty gritty. You can do all kinds of things, like adding dynamic sections to your site, building pages programmatically, and even pull from an eco-system of plugins that do way more. Gatsby is by no means the only one doing this. There are hundreds of tools and frameworks all working at making it easier to do something, but the tools I want to talk about today are the ones that are making it possible to build robust applications using a framework like Gatsby by providing the infrastructure needed to support your application.&lt;/p&gt;

&lt;p&gt;However, tools that offer this type of experience often fail to scale once you move beyond the basics, making it impossible to grow without removing the tool that allowed you the speed you needed to get to growth in the first place. The reason is that the comfort they offer often limits the flexibility. It's not easy to do what Gatsby does and allow for that progressive disclosure of complexity (if you're unfamiliar with that terminology Jason Lengstorf wrote a great article about it &lt;a href="https://lengstorf.com/progressive-disclosure-of-complexity/" rel="noopener noreferrer"&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;These are services like &lt;a href="https://firebase.google.com/" rel="noopener noreferrer"&gt;Firebase&lt;/a&gt;, &lt;a href="https://www.netlify.com/" rel="noopener noreferrer"&gt;Netlify&lt;/a&gt;, and &lt;a href="https://aws-amplify.github.io" rel="noopener noreferrer"&gt;Amplify&lt;/a&gt;. Any one of these provides some combination of authentication, serverless functions, APIs, data and file storage, and even some things like machine learning services. All targeted at making it possible to build on top of cloud environments, while using best practices, without having to manage all the complexity yourself. However, the question with these types of services always is, will I outgrow it?&lt;/p&gt;

&lt;h2&gt;
  
  
  Scaling with Amplify
&lt;/h2&gt;

&lt;p&gt;When we talk about scale in regard to a toolset like Amplify, we're actually talking about two types of scale. Scaling to accommodate more users (a great user experience), and scaling to accommodate more developers working on the product (a great developer experience). So when we ask the question, does Amplify scale, it's important to think of both the UX and DX, because both need to scale in order to be usable beyond the first users.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scaling the Developer Experience
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;"Great things in business are never done by one person; they're done by a team of people."&lt;/strong&gt; – &lt;em&gt;Steve Jobs&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;While Amplify provides a great DX for the individual developer, DX isn't just about what's going on inside your code. It's also about sharing code across teams or an organization, working with environments for QA and feature development, where and how data is sourced to clients, or how the project is built and deployed. While most of these things are generally thought of as separate ideas or workflows, you can't ship efficiently if any of these pieces are not working or set up properly.&lt;/p&gt;

&lt;p&gt;Providing a great developer experience may cause issues with scalability of services, and making services scale well generally adds complexity at the infrastructure layer, making the developer experience worse.&lt;/p&gt;

&lt;p&gt;Things like serverless multiple this by allowing you to only write code that solves business problems by shifting all the complexity to the infrastructure layer. Development is about tradeoffs and we have to really know what tradeoffs we're making. This is why there are entire teams dedicated to solving this problem.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;DevOps is a response to a need for better developer experience in cloud environments and cloud environments are a response to a need for better user experience.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Scaling Tooling
&lt;/h4&gt;

&lt;p&gt;This tweet by &lt;a class="mentioned-user" href="https://dev.to/swyx"&gt;@swyx&lt;/a&gt; really summarizes what makes a good DX for tooling:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1113478881086988288-795" src="https://platform.twitter.com/embed/Tweet.html?id=1113478881086988288"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1113478881086988288-795');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1113478881086988288&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;The Amplify CLI exemplifies a lot of these characteristics and I'd like to go over a few in particular:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Good defaults:&lt;/strong&gt; When you use the Amplify CLI to configure AWS services, the CLI walks you through your options and always provides the opportunity to either use the current best practices defaults or allows you to configure yourself (there's that progressive disclosure of complexity). This allows you to do things like set up authentication that is enterprise ready in a matter of minutes without having to be a security expert.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Incrementally adoptable:&lt;/strong&gt; Don't want to use Amplify for everything? Cool, just pick a category and start there! Amplify uses &lt;code&gt;categories&lt;/code&gt; to break logic up into common workflows or scenarios that developers face when creating any product. You can incrementally add as many categories as you want. Some popular categories are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://aws-amplify.github.io/docs/js/authentication" rel="noopener noreferrer"&gt;Authentication&lt;/a&gt; (Federated, LDAP, etc)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aws-amplify.github.io/docs/js/api" rel="noopener noreferrer"&gt;API&lt;/a&gt; (REST and GraphQL supported)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws-amplify.github.io/docs/js/analytics" rel="noopener noreferrer"&gt;Analytics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aws-amplify.github.io/docs/js/storage" rel="noopener noreferrer"&gt;Storage&lt;/a&gt; (File storage or data)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aws-amplify.github.io/docs/cli-toolchain/graphql#function" rel="noopener noreferrer"&gt;Functions&lt;/a&gt; (Serverless functions with Lambda)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aws-amplify.github.io/docs/js/predictions" rel="noopener noreferrer"&gt;Predictions&lt;/a&gt; (Machine Learning and Artificial Intelligence)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Small API/config surface area:&lt;/strong&gt; Amplify CLI only has a few base commands and requires no config from you. It may ask a few questions to help you select the proper options, but it generates the necessary config. At the end of the day the CLI is really a &lt;code&gt;codegen&lt;/code&gt; tool, whether it's generating CloudFormation templates (responsible for what services get created and how they interact), types (Flow or Typescript), or GraphQL operations (queries, mutations, subscriptions), it eliminates a lot of boilerplate code that would otherwise be needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Learn once and reuse forever:&lt;/strong&gt; The Amplify CLI's small surface area and repeated patterns make it intuitive to use for any category once you learn the basics of the CLI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remembers and adapts to you:&lt;/strong&gt; One of the best features of the CLI is how it's aware of the current Amplify configuration and can generate the necessary config to tie together services. This is one of the hardest parts for most developers to understand about AWS, and the Amplify CLI handles this for you. If you add authentication and then want to add an API, Amplify will set up the proper permissions between the services. Also, when it comes to adaption, the CLI's plugin based architecture makes it possible for DevOps teams to extend the functionality of the CLI by creating custom in-house plugins. Allowing them to add categories or workflows for other AWS services, or even other cloud providers. You can find out more about the plugin system &lt;a href="https://aws-amplify.github.io/docs/cli-toolchain/plugins" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The CLI does a lot more than this, but these are a few of the key features that allow the tooling to scale to handle any needs and any number of developers. Learn more about the CLI &lt;a href="https://aws-amplify.github.io/docs/cli-toolchain/quickstart#concepts" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Scaling Collaboration
&lt;/h4&gt;

&lt;p&gt;When it comes to a good DX, collaboration is a must. Unless you're a sole developer working on a project (and even then you most likely don't work completely in isolation) than you are going to want to use tools and services that make it easy to share/show/ship products. The Amplify framework provides a number of features that make collaboration not only possible, but pretty darn enjoyable. Here's a few of my faves:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Git like workflow for CLI:&lt;/strong&gt; It's not uncommon to want to set up specific environments of your system. Whether it's for testing or feature development, generally not everything is done in same environment that your users use. There may be a QA env, a staging env, or maybe a new environment is created for each bit of work done. Amplify supports all of these workflows with &lt;a href="https://docs.aws.amazon.com/amplify/latest/userguide/multi-environments.html" rel="noopener noreferrer"&gt;multiple environments&lt;/a&gt;. By using commands similar to git, you can create, push, and pull environments like you can with git branches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ephemeral environments:&lt;/strong&gt; While we're talking about environments, having the ability to recreate them on the fly is invaluable. As your team and projects grow, generally so will the environment around it. Being able to easily recreate them opens the door to some really efficient workflows. A very common workflow I see is &lt;a href="https://dev.to/kkemple/branch-based-deployment-strategies-with-aws-amplify-console-1n3c"&gt;branched based deployments&lt;/a&gt;. Branch based deployments is when you deploy a new environment for each branch pushed to whatever git provider you are using. You do this via Amplify Console which is a hosting service for fullstack serverless web apps. This makes it easy to create isolated environments for testing, previewing, or sharing with other developers. When your infrastructure is easily repeatable it can scale to accommodate any number of new collaborators.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deploy previews:&lt;/strong&gt; It's hard to talk about collaboration without talking about pull requests. Pull requests are the epicenter of a project and it's generally where the most collaboration takes place. When I was at Major League Soccer everyone from product, QA, and design would all collaborate around pull requests and whether it was a web app or mobile app, we all wanted to be able to be able to preview the environment. The most efficient way to do this was to have a deployment preview linked in the PR itself. Now we had to set this up ourselves but it was definitely worth the work because of how efficient it was.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you're curious about deploy previews with Amplify Console give me a follow as I'll be writing about it very soon!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Starters and sharing config&lt;/strong&gt;: Because we can create these environments based off of CloudFormation templates generated by the Amplify CLI, we're able to share configuration across an organization if needed. Complete starters can be created and deployed to Amplify Console in a matter of minutes with the &lt;code&gt;Deploy to Amplify Console&lt;/code&gt; button. If you're an agency that regularly builds e-commerce sites for clients, you can set up a default template that teams can use as a starting point for each project. They can then add any other functionality they need on top of the starter in their own environment. It's also possible to &lt;a href="https://aws-amplify.github.io/docs/cli-toolchain/usage#amplify-pull-parameters" rel="noopener noreferrer"&gt;pull down existing config&lt;/a&gt; for an Amplify project from Amplify Console, much like pulling a remote branch with git.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scaling Infrastructure
&lt;/h3&gt;

&lt;p&gt;Until recently it was really difficult to take advantage of the recent developments in cloud and serverless computing. Without have a team of seasoned devops engineers or outsourcing that work it was nearly impossible to create the right configuration to scale well. Entire companies exist just to help you optimize your infrastructure configuration, making sure you don't waste money on unneeded resources, or worse that you aren't scaling properly to meet the demands of your customers.&lt;/p&gt;

&lt;p&gt;However, as serverless and cloud move more into the commodity phase there has been a lot of progress on the user experience around serverless and cloud computing. Nader Dabit sums it up well in the following tweet: &lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1212497443805442049-926" src="https://platform.twitter.com/embed/Tweet.html?id=1212497443805442049"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1212497443805442049-926');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1212497443805442049&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;It's now possible to take advantage of serverless without being a master of cloud engineering and developers further up the stack are starting to build cloud based products on top of serverless. By using Amplify you get to take advantage of best practices when it comes to managing your infrastructure on AWS without having to know how to set it up yourself. Let's take a look at a few of the ways Amplify can help you scale.&lt;/p&gt;

&lt;h4&gt;
  
  
  Backend Infrastructure
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Infrastructure based on data needs:&lt;/strong&gt; When you use Amplify to create your GraphQL APIs you can specify what data should be stored via the &lt;code&gt;@model directive&lt;/code&gt; in your GraphQL schema. This allows you to only create the storage needed at that exact moment. You can easily update this at any time by changing the schema. More info &lt;a href="https://aws-amplify.github.io/docs/js/api#updating-your-graphql-schema" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enterprise ready services:&lt;/strong&gt; Amplify itself isn't a service, it creates the underlying CloudFormation templates needed to spin up the AWS services needed to complete that workflow. If setting up an API this could involve &lt;a href="https://aws.amazon.com/cognito/" rel="noopener noreferrer"&gt;Amazon Cognito&lt;/a&gt; for authentication, &lt;a href="https://aws.amazon.com/appsync/" rel="noopener noreferrer"&gt;AppSync&lt;/a&gt; for querying data, and &lt;a href="https://aws.amazon.com/dynamodb/" rel="noopener noreferrer"&gt;DynamoDB&lt;/a&gt; for data storage. All of these services are relied on by enterprise level companies that need enterprise level services to ensure that their customers needs are always met. By using Amplify you get to use those same services without having to handle them yourself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;API performance:&lt;/strong&gt; AppSync provides built-in server-side caching capabilities for any supported data source, improving the performance of latency-sensitive and high-throughput applications and allowing developers to fetch data from a fast, in-memory, managed cache, delivering data at low latency. As well as enhancements to GraphQL real-time subscriptions with pure WebSockets supporting a higher maximum payload size (240kb vs. 128kb with MQTT over WebSockets), enhanced connection and broadcast rates to effortlessly scale to millions of connections, CloudWatch metrics, and selection set filtering for GraphQL subscriptions. Check out &lt;a href="https://aws.amazon.com/blogs/mobile/appsync-caching-transactions/" rel="noopener noreferrer"&gt;this link&lt;/a&gt; for more info.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Serverless functions:&lt;/strong&gt; Need to do some computing outside of CRUD operations? No worries, by connecting serverless functions to your API (or using via events or a REST endpoint) you can scale workloads infinitely. Need to create thousands of thumbnails as images are uploaded to your new e-commerce platform? Lambda can handle that and pretty much anything else.&lt;/p&gt;

&lt;h4&gt;
  
  
  Frontend Infrastructure
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;DataStore for Client Performance:&lt;/strong&gt; When we think of infrastructure we generally think of backend services. But what about the network layer on device? &lt;a href="https://aws-amplify.github.io/docs/js/datastore" rel="noopener noreferrer"&gt;Amplify DataStore&lt;/a&gt; provides a persistent on-device storage repository for you to write, read, and observe changes to data if you are online or offline, and seamlessly sync to the cloud as well as across devices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Custom components and multi-platform support:&lt;/strong&gt; Amplify also has pre-built components for most front-end frameworks and platforms that allow you to quickly connect to your backing infrastructure without having to manually set up anything. Display S3 files or handle uploads with the Picker component, set up entire auth flows without having to write any backing logic, or present a UI for interacting with chatbots. All of these components are plug-and-play, saving you countless hours or even weeks of development time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;While I've covered some of the more key features here it's important to note that I've really only scratched the surface in ways that Amplify can help you scale, both from a DX and infrastructure point of view. If you're curious about how else Amplify can help you get your product in production then I highly recommend taking a look at the &lt;a href="https://aws-amplify.github.io/docs/" rel="noopener noreferrer"&gt;docs&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>ux</category>
      <category>collaboration</category>
      <category>aws</category>
      <category>amplify</category>
    </item>
    <item>
      <title>Everything Serverless Functions in AWS Amplify - Part 3</title>
      <dc:creator>Kurt Kemple</dc:creator>
      <pubDate>Thu, 12 Sep 2019 23:56:22 +0000</pubDate>
      <link>https://forem.com/theworstdev/everything-serverless-functions-in-aws-amplify-part-3-2496</link>
      <guid>https://forem.com/theworstdev/everything-serverless-functions-in-aws-amplify-part-3-2496</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/huvKSMjqfA4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In this episode we dive into using a serverless function to handle multiple graphql resolvers as well as interact with a DynamoDB table set up with the Amplify CLI. Also, instead of using amplify mock in this episode we use the AppSync console.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Links from video:
&lt;/h2&gt;


&lt;div class="ltag__link"&gt;
  &lt;div class="ltag__link__content"&gt;
    &lt;div class="missing"&gt;
      &lt;h2&gt;Article No Longer Available&lt;/h2&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;div class="ltag__link"&gt;
  &lt;div class="ltag__link__content"&gt;
    &lt;div class="missing"&gt;
      &lt;h2&gt;Article No Longer Available&lt;/h2&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html"&gt;DynamoDB JavaScript Docs&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Transcripts:
&lt;/h2&gt;

&lt;p&gt;Transcripts coming soon. Moving to a new service.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>amplify</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Everything Serverless Functions in AWS Amplify - Part 2</title>
      <dc:creator>Kurt Kemple</dc:creator>
      <pubDate>Thu, 05 Sep 2019 23:33:19 +0000</pubDate>
      <link>https://forem.com/theworstdev/everything-serverless-functions-in-aws-amplify-part-2-18f2</link>
      <guid>https://forem.com/theworstdev/everything-serverless-functions-in-aws-amplify-part-2-18f2</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/X-DtDvtQIsc"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In the second video we go deeper with serverless functions being used as resolvers in AppSync. We take a look at accessing arguments being passed to the function, as well as how to access sibling data in the resolver and how to handle pagination. We did all using the "amplify mock" command and running the environment locally.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Links from video:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/kkemple/everything-serverless-functions-in-aws-amplify-part-1-26e3"&gt;Everything Serverless Functions in AWS Amplify - Part 1&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Transcripts:
&lt;/h2&gt;

&lt;p&gt;0:09&lt;br&gt;&lt;br&gt;
Hello, everyone, and welcome back to everything service functions in AWS amplify. Yeah. So last week, where we left off, we had created a react app added amplify to it, set up a very basic graph QL API using App sync. And here's the schema. We just made a Hello World function, which we connected to a server list function. And yeah, so that returned, essentially. So it actually looked a little bit more like this.&lt;/p&gt;

&lt;p&gt;0:46&lt;br&gt;&lt;br&gt;
Yeah, just like that. And yeah, so we just made a function that could return hello world, and we checked it in the browser, and everything was great or great. So if you haven't actually seen that, there'll be a link o the first one, so I definitely recommend checking it out. But where we're going to pick up today is we're going to work with this function.&lt;/p&gt;

&lt;p&gt;1:09&lt;br&gt;&lt;br&gt;
And we're going to extend the capabilities of it. And then we're going to change, we're going to add another function and pull some data in from an API. And so maybe, you know, we'll see how far we get and when it feels like a good stopping point. But yeah, so basically, now that we know how to set up a service function, like we did in part one, we're going to see all the different type of things that you can do with it. So should be pretty interesting.&lt;/p&gt;

&lt;p&gt;1:37&lt;br&gt;&lt;br&gt;
And, yeah, let's go ahead and dive in. So the first thing that I'm actually going to do is we don't really need the UI at this point. So we're deciding what the schema is going to look like, you know, the data structures and at this point, you know, checking that in the UI seems like a lot like a pretty slow feedback loop.&lt;/p&gt;

&lt;p&gt;2:00&lt;br&gt;&lt;br&gt;
We also don't want to be deploying things out to AWS. And what I mentioned in the last episode is that we would use something called mock to go ahead and mock out the API, and data storage and all that fun stuff. And that's exactly what we are going to do. So first thing I'm going to do is run, amplify my.&lt;/p&gt;

&lt;p&gt;2:21&lt;br&gt;&lt;br&gt;
And so this is going to spin up a server, but it's going to be local, but you can interact with it, and it will behave exactly as if it was deployed on AWS. So the cool thing is, you can see that there's mock endpoint running, which is just the IP from my machine, so localhost:20002. So I'm going to go ahead and open that up, and I've just configured browser preview to have that as the default. So now I can just slide this over a little bit. You know, we can hide and show the Explorer for more room. But now we have graphical rights.&lt;/p&gt;

&lt;p&gt;3:00&lt;br&gt;&lt;br&gt;
So we can, we can see our query here. And then we have the server list function that it's connected to called hello world. So given this schema, it should return a string. And then that string should come from the function. So this should return hello world. So I'm just going to close the Explorer here and get rid of this. And oops, let's run the query. &lt;/p&gt;

&lt;p&gt;Hello, world.&lt;/p&gt;

&lt;p&gt;3:35&lt;br&gt;&lt;br&gt;
So we run it and we get data back and hello world. And sure enough, it's hello world. And so this is just local running on my machine. And so it's pretty cool. So to test this to see it's like essentially doing like, a hot reloading thing. We could change this to Hello universe. We save it, we rerun the query, and look at that Hello universe. So it's pretty cool. You can work with&lt;/p&gt;

&lt;p&gt;4:00&lt;br&gt;&lt;br&gt;
These lambda functions locally and you know, just spin up graphical. And you get this kind of really quick feedback loop that's, you know, just allows you to essentially work a lot quicker, right, which is awesome. So one thing though is like if we want to change the schema, because graphical is doing schema introspection to figure out what's available, then in that case, we have to reload graphical, but I think I can live with that, right? So let's add a parameter for message will make it optional, and will make it a string. And so will still return a string, and we'll still call this function. So now we're passing an argument to this query, right? We want to do something specific based on a bit of data.&lt;/p&gt;

&lt;p&gt;4:46&lt;br&gt;&lt;br&gt;
So how do we handle that in our lambda functions? So the way lambda functions get is it gets something called an event. And so essentially, what's happening is because it's in a pipeline, it's connected to App sync, this event gets populated for you. And everything is, you know, mapped to the event from things so like with when it's attached to this lambda function, it's attached to sorry, like a field in your graph QL schema, it knows like, okay, so if any arguments come through all attach those, and we'll take a look at how you can also access like the sibling data, just like you would in any other graph. QL project, right? Like sometimes maybe you want to grab, you know, related data, to then do something more augmented, like, take latitude and longitude and return in a dress or vice versa, right, you have a full address. So you take that and you return a latitude or longitude.&lt;/p&gt;

&lt;p&gt;5:32&lt;br&gt;
There's a multitude of use cases. So okay, so we have our event. So what we can say here is everything comes in here. Use the event and event data to see what our arguments are and so everything comes off under event arguments, right. So this is like would store any type of argument that's passed. So here we have message so we can expect event to argument stop message. Well, we can't expect it because not required, but it should be there should be something available if it is passed in.&lt;/p&gt;

&lt;p&gt;6:24&lt;br&gt;&lt;br&gt;
So we can say message equals event arguments. That message or you know, you could do structure you can do whatever you want. And then here we'll just say, message. If not, hello, universe actually will leave that Hello universe. Okay, so we'll save this but now remember, we change the schema. So if I just come over here and I'm like, ah, message, ah, see, it's gonna yell at us and say, Hey, we don't know what messages right say. So we got this unknown argument. So we got&lt;/p&gt;

&lt;p&gt;7:00&lt;br&gt;&lt;br&gt;
And essentially, we run our query. So we could have copied it out. But it's pretty small. But now we've got message. So it should return Hello universal, let's do hello world. It will run this a hello world. So let's remove that, right. And so if we go back and we look at this function, it should return Hello universe. So let's run it. And we get Hello universe. So that's how you can handle arguments. So pretty cool.&lt;/p&gt;

&lt;p&gt;7:40&lt;br&gt;&lt;br&gt;
Okay, so we've taken a look at how we can now use arguments and pass data. So we're going to set up a new function, and we're going to use that function to call an API, and we're going to look at using some arguments to handle pagination. So I'm going to add a new property here.&lt;/p&gt;

&lt;p&gt;8:00&lt;br&gt;&lt;br&gt;
So, in our list Pokemon, we are going to want to be able to set a limit. It's not required though. And also were to pick up from when we left off. And so we're going to call this next token. and in this situation, next token will be an int.&lt;/p&gt;

&lt;p&gt;8:33&lt;br&gt;&lt;br&gt;
And this is going to return a oops, sorry, it's not gonna it's going to return a Pokemon connection.&lt;/p&gt;

&lt;p&gt;8:46&lt;br&gt;&lt;br&gt;
And so what that means is because when we return it, because it's a list and we want pagination, we need a way to identify Hey, what was the last item that was given?&lt;/p&gt;

&lt;p&gt;9:00&lt;br&gt;&lt;br&gt;
Like, or, you know, or where am I in this list of Pokemon. So when you get a response from this, what you really want is the items, the actual Pokemon, but as well as that token that next token, so it's kind of like an intermediary layer, instead of just returning the array of Pokemon. We also want that next token. So we have a type Pokemon connection, which has a next token, which is a string, and it's not, or sorry, in this case, it's an event. And it's not required because it could be not. And if it's no, that means Hey, you're at the end, there is no next token, you've hit the end. And then we want items. And so items and for brevity sake, it's not going to be too much, but it will be Pokemon.&lt;/p&gt;

&lt;p&gt;9:46&lt;br&gt;&lt;br&gt;
But we have to create a type for that. So I am going to fast forward through the creation of this pokemon type, and then we'll pick back up&lt;/p&gt;

&lt;p&gt;10:04&lt;br&gt;&lt;br&gt;
Okay, we've created a Pokemon connection, a Pokemon type and a Pokemon move. So the first thing that we want to do is set up a function to do the listing of the Pokemon. So say function name. And we'll have to name this will call this ES for everything server lists.&lt;/p&gt;

&lt;p&gt;10:34&lt;br&gt;&lt;br&gt;
Actually no dashes just Pokemon. And then of course, we want to do dash environment. So that one is created for any environment that we have, it can be in. Okay, so we're just we're going to stick for this now, and Pokemon moves are not required just yet. So we're not going to worry about these at the moment but we are going to worry about listing the Pokemon&lt;/p&gt;

&lt;p&gt;11:01&lt;br&gt;&lt;br&gt;
So what we're going to do here is run amplified function. So if you look down here in the terminal, it says, actually, let me pull that up one, just that go. Well, okay, so it says, please run amplify add function. So it's already telling us like, Hey, you added a function, but it does not exist. So let's make that exist. So we're going to say, amplify add function.&lt;/p&gt;

&lt;p&gt;11:33&lt;br&gt;&lt;br&gt;
Okay, and for a name, we will call this the same thing. Yes, lyst Pokemon, or for the label, and then for the lambda function name will keep it the same. We want a Hello World function. So I'm going to pick that.&lt;/p&gt;

&lt;p&gt;11:51&lt;br&gt;&lt;br&gt;
In this case, we do not want to access any other resources. We're going to access a third party API&lt;/p&gt;

&lt;p&gt;11:59&lt;br&gt;&lt;br&gt;
Want to edit the local lambda function now? Yeah, we definitely do. So we're going to hit yes.&lt;/p&gt;

&lt;p&gt;12:07&lt;br&gt;&lt;br&gt;
Okay, so here we have shiny function, but we are going to want to fetch some data, right we want to get we want to get some Pokemon, and we need to take into account that we might get a limit. So we need to pay attention to that. And we might also receive a next token. So&lt;/p&gt;

&lt;p&gt;12:31&lt;br&gt;&lt;br&gt;
I'm going to go and get the URL for Pokemon. Okay, so coming back in here, yeah, build Pokemon URL, it's going to be a function that takes a limit and the next token and it going to return a string. And so this is the base URL for Pokemon and already know that it takes two parameters that are important. And that is limit. And next token, or sorry, the API takes limit and offset. And that's how you could do pagination. So for us, this is a pretty easy conversion. So we just say limit. And that's going to be equal to what is passed in his love it, and then we're going to have offset. And that is going to be equal to whatever is passed in as next token. So that's as easy as it is to kind of get this pagination going.&lt;/p&gt;

&lt;p&gt;13:44&lt;br&gt;&lt;br&gt;
Okay, so we know that we want this URL. Now we need a limit. And we need a next token. So let's go ahead and get those. So we're going to say const limit. And we're going to say equals here and we'll do 20. It's going to be a default, because we might not get it. And then we're going to look for next token, and that's also going to be are going to have a default of zero. So that's our offset, so we don't get an X token we're starting from the beginning. And if we don't get a limit, then we're doing 20 at a time increments and that's going to be equal to event arguments.&lt;/p&gt;

&lt;p&gt;14:38&lt;br&gt;&lt;br&gt;
Okay, so now we have that and we have a URL. So what we want to do, I'm just going to give this a little bit more room. We need to like fetch this data, we need to get it some way so I'm familiar with x iOS, which is not installed yet. We will install it and we're going to say get URL. And so now we're doing some basic stuff. So this is pretty cool. Let's g is equal to x Yes Get URL because that returns us promise. And we'll do a try catch here in a second.&lt;/p&gt;

&lt;p&gt;15:26&lt;br&gt;&lt;br&gt;
So now we have the result. So what we want to return So remember, this is listing Pokemon. But if we come back to the schema, it's a connection. So we need to form a connection, not just return the items themselves, and we want an ID and a name. So we have to get that. So let's do this. We will say that the response is equal to. So first, let's take care of our next token, which will, we would want to check our result list and see if we're at the end. But for now, let's just do it as limit plus.&lt;/p&gt;

&lt;p&gt;16:21&lt;br&gt;&lt;br&gt;
Next token, right? So wherever we started from plus what we fetched, we'll just treat that as the default, just for now to return something. And then we will say, items, is equal to I want to say result data. I think that's correct. I'm going to check the API docs and I'll be right back.&lt;/p&gt;

&lt;p&gt;16:51&lt;br&gt;&lt;br&gt;
Okay, so I checked the docs and it looks like it's going to be result data results and&lt;/p&gt;

&lt;p&gt;17:00&lt;br&gt;&lt;br&gt;
For our next token, so remember, we want to return this if we have more results. But what if we don't? What if this is the end so we can say, result data. Next, because that is returned if as a URL if there is more, if you can fetch more. So if we want that, if we if we know there's a next than we can just assume that will get more.&lt;/p&gt;

&lt;p&gt;17:27&lt;br&gt;&lt;br&gt;
Otherwise, there's no next that we return no for a token.&lt;/p&gt;

&lt;p&gt;17:32&lt;br&gt;&lt;br&gt;
So now in this function, we don't want to return this. We want to return our response that is formatted in the data structure of a connection. But right now, we are handling Oh, look, I'm person missing, in a way. I wonder how many of you saw this and we're like, oh, you're missing away. It's kind of break.&lt;/p&gt;

&lt;p&gt;17:53&lt;br&gt;&lt;br&gt;
Yeah, so Okay, so we have some a sickness going on, but we're not catching any errors. So&lt;/p&gt;

&lt;p&gt;18:00&lt;br&gt;&lt;br&gt;
Let's try and catch them.&lt;/p&gt;

&lt;p&gt;18:04&lt;br&gt;&lt;br&gt;
I should just let prettier do that.&lt;/p&gt;

&lt;p&gt;18:07&lt;br&gt;&lt;br&gt;
All right, catch. error&lt;/p&gt;

&lt;p&gt;18:11&lt;br&gt;&lt;br&gt;
we will first will console log it&lt;/p&gt;

&lt;p&gt;18:18&lt;br&gt;&lt;br&gt;
for funsies, but also console.log it. Oh, and we didn't return our response. So we will I context done that error. So if you hit an error, that's kind of the first parameter, this up here because used to be in that, that's looking a lot better. Okay, so we get our limits. All that looks good. So should should be good. We should be good to go here. So we're gonna hit Continue. All right, let's, uh, let's spin it up.&lt;/p&gt;

&lt;p&gt;18:52&lt;br&gt;&lt;br&gt;
Okay, so because of the way the API is structured, we can't actually get back the ID that doesn't come back with the results. So when you list the resources, all it really gives you is the name and the URL to actually fetch that Pokemon. So what we're going to do is we're going to fetch them real quick. So we'll say cause.&lt;/p&gt;

&lt;p&gt;19:35&lt;br&gt;&lt;br&gt;
So let's actually, so we have the name. So let's add back those, those properties.&lt;/p&gt;

&lt;p&gt;19:42&lt;br&gt;&lt;br&gt;
Let's add ID back and see if this in fact, is working, which is I believe an event.&lt;/p&gt;

&lt;p&gt;19:51&lt;br&gt;&lt;br&gt;
Save that. We want the items ID and Name and let's run it. So there we have everything.&lt;/p&gt;

&lt;p&gt;20:00&lt;br&gt;&lt;br&gt;
And now the Pokemon API, I would imagine their caches pretty warmed up, but we get the ID of the the Pokemon were before we could not. So now we have the moves, which is a Pokemon move. And so we have a name, property and power, accuracy and priority. So what I'm actually going to do is create a new property called stats. And this is going to return Pokemon stats.&lt;/p&gt;

&lt;p&gt;20:30&lt;br&gt;&lt;br&gt;
But it's going to be powered by a function.&lt;/p&gt;

&lt;p&gt;20:34&lt;br&gt;&lt;br&gt;
And this function, its name will be will call it ES.&lt;/p&gt;

&lt;p&gt;20:40&lt;br&gt;&lt;br&gt;
Pokemon stats. And again, we need to specify for the environment. So&lt;/p&gt;

&lt;p&gt;20:49&lt;br&gt;&lt;br&gt;
what we're actually going to do here is take these out.&lt;/p&gt;

&lt;p&gt;20:52&lt;br&gt;&lt;br&gt;
We're going to create a new type&lt;/p&gt;

&lt;p&gt;20:57&lt;br&gt;&lt;br&gt;
and we'll call this pokemon stats.&lt;/p&gt;

&lt;p&gt;21:04&lt;br&gt;&lt;br&gt;
Okay, so we have to do two things in order to make this work first right now, we are not as well, we have to add a function. So technically we have to do three things. But the The first thing, let's actually just remove this declaration for right now. don't even need that. Okay, sorry. Yeah, so we'll do this. So we don't have to create a new function&lt;/p&gt;

&lt;p&gt;21:24&lt;br&gt;&lt;br&gt;
just yet, but still, we can't get the name. So right now we're not returning any moves. We're not doing any anything deep. we fetch the Pokemon, but we don't have the moves.&lt;/p&gt;

&lt;p&gt;21:44&lt;br&gt;&lt;br&gt;
Hey, cool. All right. Thanks for sticking with me. So we got the name. So now, we want the deets, right, like whenever. Maybe we want to access stats about this. So we need Pokemon stats and we&lt;/p&gt;

&lt;p&gt;22:00&lt;br&gt;&lt;br&gt;
We need this to be&lt;/p&gt;

&lt;p&gt;22:03&lt;br&gt;&lt;br&gt;
function, right? Like we need to get that and also how we're going to get it. We're going to query the API using the name or a source property, like a sibling property to stats. So we'll see how not only can you pull data in as an argument, but you can also access the sibling data of the field that the lambda function is resolving to. Okay, so we'll save that and then we're going to get notified, it's gonna say, hey, you need a function. So let's go ahead and create that function. So here we're going  back up to the root, I got it. And we're going to say amplify add function.&lt;/p&gt;

&lt;p&gt;22:48&lt;br&gt;&lt;br&gt;
Okay, for the name of it, we will call it espokemonstats&lt;/p&gt;

&lt;p&gt;23:01&lt;br&gt;&lt;br&gt;
Hello World function, we do not want to access other resources. And we'll get into that in a later episode.&lt;/p&gt;

&lt;p&gt;23:08&lt;br&gt;&lt;br&gt;
Yeah, we definitely want to edit it now, though.&lt;/p&gt;

&lt;p&gt;23:13&lt;br&gt;&lt;br&gt;
Cool. So what I'm actually going to do is we're going to use&lt;/p&gt;

&lt;p&gt;23:19&lt;br&gt;&lt;br&gt;
decent amount of this stuff. So we're going to just bring it all over into our new function.&lt;/p&gt;

&lt;p&gt;23:27&lt;br&gt;&lt;br&gt;
And we're going to change the thing. So first,&lt;/p&gt;

&lt;p&gt;23:30&lt;br&gt;&lt;br&gt;
this won't be here. So what will be here will be name and that won't come off of that the arguments it will come off of event source. And so the source is&lt;/p&gt;

&lt;p&gt;23:47&lt;br&gt;&lt;br&gt;
the sources is the sibling data, right? So, in this case for moves, next that will have stats it's the name right we want the name. So now we'll say we'll just keep it build Pokemon&lt;/p&gt;

&lt;p&gt;24:00&lt;br&gt;&lt;br&gt;
URL, but instead it's going to take a name. And so appear it's going to take a name.&lt;/p&gt;

&lt;p&gt;24:07&lt;br&gt;&lt;br&gt;
And we're not going to be calling Pokemon, we're going to be calling&lt;/p&gt;

&lt;p&gt;24:12&lt;br&gt;&lt;br&gt;
moves. And I believe instead of having any of this, we just do slash and then name.&lt;/p&gt;

&lt;p&gt;24:24&lt;br&gt;&lt;br&gt;
So I'm going to verify that really quick. On the docs.&lt;/p&gt;

&lt;p&gt;24:29&lt;br&gt;&lt;br&gt;
Move. This is not news. It's move. That make sense. Okay, so now we have that we have our URL. So we're going to build our results. We won't need&lt;/p&gt;

&lt;p&gt;24:40&lt;br&gt;&lt;br&gt;
all of this data and our response doesn't need a next token, and the three properties that were accessing priority, let's go to actually see what those are.&lt;/p&gt;

&lt;p&gt;24:54&lt;br&gt;&lt;br&gt;
Yeah, so we have power, accuracy and priority those are root properties on the&lt;/p&gt;

&lt;p&gt;25:00&lt;br&gt;&lt;br&gt;
But just so that we can see will say contest,&lt;/p&gt;

&lt;p&gt;25:06&lt;br&gt;&lt;br&gt;
power,&lt;/p&gt;

&lt;p&gt;25:08&lt;br&gt;&lt;br&gt;
accuracy,&lt;/p&gt;

&lt;p&gt;25:10&lt;br&gt;&lt;br&gt;
and the other one&lt;/p&gt;

&lt;p&gt;25:12&lt;br&gt;&lt;br&gt;
priority.&lt;/p&gt;

&lt;p&gt;25:15&lt;br&gt;&lt;br&gt;
And those are going to be equal to result data.&lt;/p&gt;

&lt;p&gt;25:23&lt;br&gt;&lt;br&gt;
And that's what we're going to respond with.&lt;/p&gt;

&lt;p&gt;25:29&lt;br&gt;&lt;br&gt;
So we could just pass result data, but I just want to show that these properties do in fact, come off of there. And we're returning them exactly because it's graph QL. And since the only three data fields that we say are available, are those three it would only like return those three to the end user. But we're just going to explicitly spread it out so that you can see,&lt;/p&gt;

&lt;p&gt;25:53&lt;br&gt;&lt;br&gt;
I said our limit to five&lt;/p&gt;

&lt;p&gt;25:57&lt;br&gt;&lt;br&gt;
the name moves the&lt;/p&gt;

&lt;p&gt;26:00&lt;br&gt;&lt;br&gt;
Name and all the stats. All right.&lt;/p&gt;

&lt;p&gt;26:07&lt;br&gt;&lt;br&gt;
Okay, so if we close this up, we can see, for sword dance, we got no, which is interesting. Maybe we hit a four or four&lt;/p&gt;

&lt;p&gt;26:18&lt;br&gt;&lt;br&gt;
on there, but we can see that we are getting the stats back for most of these moves. But that's interesting. So here is another one. I guess it's another evolution of the same one. But yeah, so that's that just seems to be missing. But yeah, so we've got our data coming back. So now we have, if we go back to our schema, we have three functions.&lt;/p&gt;

&lt;p&gt;26:42&lt;br&gt;&lt;br&gt;
And we've done a lot of things. So first, we've allowed to pass arguments. We've set up how to deal with pagination based on arguments. And lastly, how to access the sibling data on on service functions that might be buried within&lt;/p&gt;

&lt;p&gt;27:00&lt;br&gt;&lt;br&gt;
Your schema and aren't at the root of query. So I hope this was fun and enjoyable and I will see you in the next one.&lt;/p&gt;

&lt;p&gt;Transcribed by &lt;a href="https://otter.ai"&gt;https://otter.ai&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>amplify</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Introducing Pokedex</title>
      <dc:creator>Kurt Kemple</dc:creator>
      <pubDate>Sat, 31 Aug 2019 20:41:02 +0000</pubDate>
      <link>https://forem.com/theworstdev/introducing-pokedex-4976</link>
      <guid>https://forem.com/theworstdev/introducing-pokedex-4976</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5cOLO2Q_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/3ipt518c0ngfkgy0r4j7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5cOLO2Q_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/3ipt518c0ngfkgy0r4j7.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deploy a full stack Pokédex app backed by AWS AppSync and AWS Lambda in minutes.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I recently asked what examples people would like to see next and the biggest request by far was how to handle pagination in AWS Amplify and AWS AppSync and what better way to showcase that than with Pokémon!&lt;/p&gt;

&lt;h2&gt;
  
  
  What It Does
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🦊 Scroll through 100s of Pokemon&lt;/li&gt;
&lt;li&gt;💅 Animations&lt;/li&gt;
&lt;li&gt;📄 Pagination&lt;/li&gt;
&lt;li&gt;🔥 Serverless back end&lt;/li&gt;
&lt;li&gt;🚀 GraphQL&lt;/li&gt;
&lt;li&gt;💻 Deploy back end in minutes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;The code for the app is located &lt;a href="https://github.com/kkemple/pokedex"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This project uses AWS AppSync to provide a serverless GraphQL API that is backed by serverless functions. These functions are used to interact with the &lt;a href="https://pokeapi.co"&gt;Pokemon API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the project, you'll notice a folder named &lt;code&gt;amplify&lt;/code&gt;. This folder contains the back end for the app that can be redeployed in anyone's account. In the &lt;code&gt;amplify&lt;/code&gt; folder you'll see a &lt;code&gt;backend&lt;/code&gt; folder. In this folder you'll see the configuration for the three main features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GraphQL API (built with AWS AppSync)&lt;/li&gt;
&lt;li&gt;Function (built with AWS Lambda)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the &lt;code&gt;backend/api&lt;/code&gt; folder you'll see the GraphQL API configuration as well as the base &lt;a href="https://github.com/kkemple/pokedex/blob/master/amplify/backend/api/pokedex/schema.graphql"&gt;GraphQL Schema&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is the base GraphQL Schema. You'll see that the base schema looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;listPokemon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nextToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PokemonConnection&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;listpokemon&lt;/span&gt;&lt;span class="err"&gt;-${&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="err"&gt;}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;pokemon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Pokemon&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;getpokemon&lt;/span&gt;&lt;span class="err"&gt;-${&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="err"&gt;}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PokemonConnection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;nextToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Pokemon&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Pokemon&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;abilities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PokemonAbility&lt;/span&gt;&lt;span class="p"&gt;]!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;baseExp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;moves&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PokemonMove&lt;/span&gt;&lt;span class="p"&gt;]!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PokemonMove&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PokemonMoveDetails&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;pokemonmovedetails&lt;/span&gt;&lt;span class="err"&gt;-${&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="err"&gt;}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PokemonAbility&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PokemonAbilityDetails&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;pokemonabilitydetails&lt;/span&gt;&lt;span class="err"&gt;-${&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="err"&gt;}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PokemonMoveDetails&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;flavorText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;effect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PokemonAbilityDetails&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;effect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you've never worked with Amplify before you may not be aware of the &lt;code&gt;@function&lt;/code&gt; directive. This is part of the &lt;a href="https://aws-amplify.github.io/docs/cli-toolchain/graphql"&gt;GraphQL Transform&lt;/a&gt; library of the Amplify CLI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;@function&lt;/strong&gt; - Decorate any field with this directive to use a serverless function as an AppSync resolver. These map to the functions configured via the Amplify CLI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy the App
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Deploy the back end and run the app
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Clone the repo &amp;amp; install the dependencies
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~ git clone https://github.com/kkemple/pokedex.git
~ &lt;span class="nb"&gt;cd &lt;/span&gt;pokedex
~ npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Initialize the Amplify project
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~ amplify init
? Enter a name &lt;span class="k"&gt;for &lt;/span&gt;the environment: dev &lt;span class="o"&gt;(&lt;/span&gt;or whatever you would like to call this &lt;span class="nb"&gt;env&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
? Choose your default editor: &amp;lt;YOUR_EDITOR_OF_CHOICE&amp;gt;
? Do you want to use an AWS profile? Y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Mock the backend to ensure app is working properly
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Start the app and verify UI is working properly
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~ expo start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Push to AWS
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~ amplify push
? Are you sure you want to &lt;span class="k"&gt;continue&lt;/span&gt;? Y
? Do you want to generate code &lt;span class="k"&gt;for &lt;/span&gt;your newly created GraphQL API? N
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; We already have the GraphQL code generated &lt;span class="k"&gt;for &lt;/span&gt;this project, so generating it here is not necessary.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Customizing the GraphQL schema
&lt;/h2&gt;

&lt;p&gt;This schema can be edited. If you need additional fields or base types, you can update the backend by doing the following:&lt;/p&gt;

&lt;p&gt;Update the schema (located at amplify/backend/api/gweatherapp/schema.graphql).&lt;/p&gt;

&lt;p&gt;Redeploy the back end&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;There is a settings page in the app, a fun challenge would be to allow users to store locations and set one for the forecast!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you or anyone you know needs help getting up and running with this app, reach out to me on &lt;a href="https://twitter.com/kurtiskemple"&gt;Twitter&lt;/a&gt;, I'd be happy to help!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>amplify</category>
      <category>react</category>
      <category>expo</category>
    </item>
    <item>
      <title>Introducing Gweather - A Micro Weather App with Gifs!</title>
      <dc:creator>Kurt Kemple</dc:creator>
      <pubDate>Fri, 30 Aug 2019 13:10:51 +0000</pubDate>
      <link>https://forem.com/theworstdev/introducing-gweather-a-micro-weather-app-with-gifs-5704</link>
      <guid>https://forem.com/theworstdev/introducing-gweather-a-micro-weather-app-with-gifs-5704</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--19YHogfx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/s4ad3yoczy7wpcc1goz7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--19YHogfx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/s4ad3yoczy7wpcc1goz7.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deploy a full stack app that gives you realtime weather updates with style.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I've received a lot of feedback about how the previous app examples I built were great for learning AWS Amplify because it shows how all the pieces come together to make an actual app. With that in mind I decided to show off one of my favorite features of Amplify which is backing your GraphQL resolvers with serverless functions. This allows you to use just about anything as a data source and is a such a powerful feature!&lt;/p&gt;

&lt;h2&gt;
  
  
  What It Does
&lt;/h2&gt;

&lt;p&gt;Gweather is a micro weather app and provides features like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🌎 Uses geolocation to get weather data&lt;/li&gt;
&lt;li&gt;⛈ Micro weather updates&lt;/li&gt;
&lt;li&gt;🌠 Weather related Giphy images&lt;/li&gt;
&lt;li&gt;👮‍ Authenticated&lt;/li&gt;
&lt;li&gt;🔥 Serverless back end&lt;/li&gt;
&lt;li&gt;🚀 GraphQL&lt;/li&gt;
&lt;li&gt;💻 Deploy back end in minutes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;The code for the app is located &lt;a href="https://github.com/kkemple/gweather"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This project uses AWS AppSync to provide a serverless GraphQL api that is backed by a serverless function that fetches the weather and gif data.&lt;/p&gt;

&lt;p&gt;In the project, you'll notice a folder named &lt;code&gt;amplify&lt;/code&gt;. This folder contains the back end for the app that can be redeployed in anyone's account. In the &lt;code&gt;amplify&lt;/code&gt; folder you'll see a &lt;code&gt;backend&lt;/code&gt; folder. In this folder you'll see the configuration for the three main features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication service (powered by Amazon Cognito)&lt;/li&gt;
&lt;li&gt;GraphQL API (built with AWS AppSync)&lt;/li&gt;
&lt;li&gt;Function (built with AWS Lambda)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the &lt;code&gt;backend/api&lt;/code&gt; folder you'll see the GraphQL API configuration as well as the base &lt;a href="https://github.com/kkemple/gweather/blob/master/amplify/backend/api/gweatherapp/schema.graphql"&gt;GraphQL Schema&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is the base GraphQL Schema. You'll see that the base schema looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;weather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;!,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;!):&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Weather&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;getweather&lt;/span&gt;&lt;span class="err"&gt;-${&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="err"&gt;}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Weather&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;timezone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WeatherSummary&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;hourly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WeatherSummary&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;weekly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WeatherSummary&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;feelsLike&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;gif&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WeatherSummary&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you've never worked with Amplify before you may not be aware of the &lt;code&gt;@function&lt;/code&gt; directive. This is part of the &lt;a href="https://aws-amplify.github.io/docs/cli-toolchain/graphql"&gt;GraphQL Transform&lt;/a&gt; library of the Amplify CLI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;@function&lt;/strong&gt; - Decorate any field with this directive to use a serverless function as an AppSync resolver.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy the App
&lt;/h2&gt;

&lt;p&gt;In order to run the app you will need an API key for both the &lt;a href="https://developers.giphy.com/"&gt;Giphy API&lt;/a&gt; and the &lt;a href="https://darksky.net/dev"&gt;Dark Sky API&lt;/a&gt;. Both have a free plan that should be more than enough to run this app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploy the back end and run the app
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Clone the repo &amp;amp; install the dependencies
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~ git clone https://github.com/kkemple/qweather.git
~ &lt;span class="nb"&gt;cd &lt;/span&gt;gweather
~ npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Update the serverless function with your Dark Sky API and Giphy API keys in &lt;code&gt;amplify/backend/function/getweather/src/index.js&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buildDarkSkyUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lon&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="s2"&gt;`https://api.darksky.net/forecast/[key]/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lat&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lon&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buildGiphyUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tag&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nb"&gt;encodeURI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`https://api.giphy.com/v1/gifs/random?api_key=[key]S&amp;amp;tag=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;rating=G`&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Initialize the Amplify project
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~ amplify init
? Enter a name &lt;span class="k"&gt;for &lt;/span&gt;the environment: dev &lt;span class="o"&gt;(&lt;/span&gt;or whatever you would like to call this &lt;span class="nb"&gt;env&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
? Choose your default editor: &amp;lt;YOUR_EDITOR_OF_CHOICE&amp;gt;
? Do you want to use an AWS profile? Y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Mock the backend to ensure app is working properly
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Start the app
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~ expo start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Push to AWS
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~ amplify push
? Are you sure you want to &lt;span class="k"&gt;continue&lt;/span&gt;? Y
? Do you want to generate code &lt;span class="k"&gt;for &lt;/span&gt;your newly created GraphQL API? N
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; We already have the GraphQL code generated &lt;span class="k"&gt;for &lt;/span&gt;this project, so generating it here is not necessary.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Customizing the GraphQL schema
&lt;/h2&gt;

&lt;p&gt;This schema can be edited. If you need additional fields or base types, you can update the backend by doing the following:&lt;/p&gt;

&lt;p&gt;Update the schema (located at amplify/backend/api/gweatherapp/schema.graphql).&lt;/p&gt;

&lt;p&gt;Redeploy the back end&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;There is a settings page in the app, a fun challenge would be to allow users to store locations and set one for the forecast!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you or anyone you know needs help getting up and running with this app, reach out to me on &lt;a href="https://twitter.com/kurtiskemple"&gt;Twitter&lt;/a&gt;, I'd be happy to help!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>amplify</category>
      <category>react</category>
      <category>expo</category>
    </item>
    <item>
      <title>Everything Serverless Functions in AWS Amplify - Part 1</title>
      <dc:creator>Kurt Kemple</dc:creator>
      <pubDate>Thu, 29 Aug 2019 23:33:10 +0000</pubDate>
      <link>https://forem.com/theworstdev/everything-serverless-functions-in-aws-amplify-part-1-26e3</link>
      <guid>https://forem.com/theworstdev/everything-serverless-functions-in-aws-amplify-part-1-26e3</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/d0Dqsfql6os"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In this intro to the series I set up a new React project with create-react-app, configure AWS Amplify. Then I create a serverless function and access it via GraphQL with AWS AppSync.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Links from video:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=fWbM5DLh25U"&gt;Nader's video on configuring Amplify CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws-amplify.github.io/docs/js/react"&gt;Amplify getting started docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Transcriptions:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Kurt Kemple  0:01&lt;/strong&gt;&lt;br&gt;
Hello, everyone, and thank you for joining me on the first episode of everything service functions with AWS amplify. Today we're going to take a look at setting up a basic server list function that says hello world, and putting it behind graph kill API with epic. And we won't do all this without leaving VS code. To do this, I'll just CD into my projects directory, and run and PEX create react. And we'll just call this Hello, world. Okay, so this is going to create the project install the dependencies I'm going to fast forward, I'll see you when it's done. Okay, so the project has completed, I've opened up the project in VS code, and I'm going to bring the terminal back up. Now that we have our project, our basic react app, the first thing that we're going to do is we're going to knit this as an amplify project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kurt Kemple  1:24&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
For the name will choose hello world. For the environment, I'll choose Dev. I will choose Visual Studio code editor, JavaScript for the project react. And it knows that this is a create reactor project. So it's just going to go ahead and give me those smart defaults. And lastly, is I have to use a profile. So if this is your first time using amplify, you may have been greeted with a request to configure amplify CLI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kurt Kemple  2:00&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
I'm going to put up an image of Nader Dabit's YouTube video that you can go and check out and here's the link as well. And this will walk you through configuration. It's also in the very beginning of the docs if you go to the Amplified docs here. But yeah, so now I'm going to fast forward while this runs, and I'll see you when it's done. Okay, so now that that's completed, let's go ahead and add an API.&lt;/p&gt;

&lt;p&gt;For the type will choose graph QL, for the API name will stick with hello world will choose the API key, we're not going to require authentication to use the app, we do not have an annotated schema, so we're going to go ahead and create one. So we'll choose Yes. And here I'm going to do single object. And yes, we want to edit it now. So it opens up the schema. And what I'm going to do is I'm going to get rid of this to do model. And if you're unfamiliar, these directives, or graph QL, transforms, basically are what allow you to customize and create app sync graphical API's, but doing it through this schema, and then that gets deployed and it knows what you're trying to build. So we're actually going to get rid of this because we just want to do our hello world right now through a surplus function.&lt;/p&gt;

&lt;p&gt;So we're actually going to say type of query. And hello world is going to be our query right? Now it's not going to take any arguments, it's going to return a string, that is a must. And then here, we're going to say function, because it's going to be backed by a function. We haven't created that yet. But we will next. So for name, we're going to say hello world, it's a lot of hello world stuff, right? But here's the thing. So because we're creating this with amplify, amplify supports multiple environments, meaning, if I created, we created Dev, but if I wanted something called like production or staging, we wouldn't want to necessarily use the same service function. So we can use this kind of variable here as to say, do one for Dev and one for production and one for each environment that we happen to create. So that's it. So this is our schema, we just use this one directive, you know, there's nothing else really crazy going on here. Yeah, and so we save that, and then we're going to press Continue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kurt Kemple  4:45&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Okay, so what we missed here, essentially, is that the schema was created. So some of the next steps would be to push it or we're actually going to take a look at mocking, but first, we have to add our function.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kurt Kemple  5:03&lt;/strong&gt; &lt;br&gt;
So we run amplify add function.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kurt Kemple  5:12&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
So for the name, we said, it's going to be hello world, in our schema, so let's make sure we call it hello world. And here, we'll call that hello world. And this is going to just be a simple Hello World function. So we have some other options, right. So if we had storage setup, we could also do a credit function and access Dynamo DB table that we've created within this amplify project. Or if we just like, we're going to know we're going to build out maybe a couple different routes, or something like that, we could actually basically recreate a REST API full on REST API, but it would be service and backed by API gateway, and use Express. So like, you just be able to write you know, API doc get path and then handle those requests, like you were in an express up. For right now, we don't need all that.&lt;/p&gt;

&lt;p&gt;So we're just going to stick with the Hello World function. Technically, no, we don't want to access other resources, graph QL will access it. But we don't need to like access graph QL from within the function or the user or anything like that. So we can hit know for now. And later in the series, we'll we'll take a look deeper into some of these options, because you can do some pretty powerful stuff. Yeah, let's let's edit it now, just so that we can kind of see what it looks like.&lt;/p&gt;

&lt;p&gt;So you see here, we get lambda function. And it's just going to output hello world. Perfect. That's essentially exactly what we want. When it's console logging out here, is key. So like, if you look here, we have this event, JSON, and it has keys. So if this lambda function was to receive events like and not be being used through graph QL, you could receive leave it like that. And so that just means like that data to be there, we don't need this. So we're going to get rid of it. And that's it. This is our service function, so we can hit Continue. Alright, so that's all done. So now that we have it set up, let's run amplify mock, so we can test it out. So while this is spinning up, I'm going to go ahead and fast forward so that we can move on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kurt Kemple  7:27&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
So a graph QL code generation gets done for us, if we want to like this will generate all the query subscriptions, and mutations in our case, we just have a single query. So not much will be generated. But you can get it you know, just vanilla JS, you can get with TypeScript definitions. And with flow, so if you prefer types you can do that will stick with JavaScript for simplicity. So for the files, yeah, sure, it's just going to put it in a folder called craft QL, inside of directory where the rest of our code is. And you know, we want to generate all the mutation subscriptions. So here, you could specify and break down what you want to generate for, but we can just say yes, and then so this is the depth like, so if you've worked with graph QL, maybe a lot before you know that it can get expensive to access multiple layers, like say you have blog posts that have comments, you know, and then from like, comments, you have their authors, and you can get their blog posts and get those comments and like, so on and so forth. So you could just get like very expensive. So this just limits the amount of depth. So in this case, you can only go down two levels.&lt;/p&gt;

&lt;p&gt;Okay, so our graphQL endpoints has been successfully set up and we are mocked. So theoretically, at this point, we can start querying, but we need to do this with the API key because we said to do that, so first, we're going to set up our client. And then we'll go ahead and update the React app to call the directory and or the the function and we'll take a look at that the result. So first, we're going to add the dependencies, which is AWS amplify, this holds the main amplify like object in all of the classes for the different categories.&lt;/p&gt;

&lt;p&gt;So like for API, analytics, predictions, things like that. And then we're also going to add AWS amplify react. And this actually, we don't, we don't need this one yet, because we're not doing any off like that has like a bunch of pre built components. So if we were adding off, I like to use the pre built like authenticator, which gives you the whole sign in flow. completely done. You don't have to do anything, but we're just doing API key, so we won't need it. So we're just going to add amplify. And while that is installing, we're going to open up source. And there's two things I want to point out. One is this AWS exports file. And so this is actually where the base configuration is stored. And yeah, so what we need to do is configure amplify, and so the way that we do that, is we import amplify, from AWS amplify, and then we import the configs, it will call it Apple fi, config.&lt;/p&gt;

&lt;p&gt;And that's going to come from that AWS exports file. And then we're going to configure will give it to amplify config. And that's all that it takes to actually configure it. And now, we actually want to use it right, we want to call this function. So today do that we're actually going to go into app JS. And we're going to do a few things. We're going to state and use effects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kurt Kemple  11:14&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
And we're also going to import API and graph QL operation from AWS amplify. So what we'll do here is we'll create state to store our message will just make it No, by default. And then we'll use an effect to go ahead and fetch that message.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kurt Kemple  11:57&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
So now this would set our message. So let's come down here. And we'll say if a message, show message, otherwise, the default that was already there. So now we have this all set up. So we're going to go ahead. And actually, I need to open up the browser. And I'm going to do it within VS code. But I don't have that extension installed yet. So we're going to pause right here, I'm going to get that installed. And then we'll open up this project and run it.&lt;/p&gt;

&lt;p&gt;And if everything is working, we'll have a serverless function. Okay, I've gotten browser preview installed. And I'm ready to open the project. But I've realized that we've used our query hello world, but we haven't actually defined it. So I want to take that opportunity to look over here into the folder and we see that we have source graph QL queries, and we open that up, we get hello world. So that was automatically generated for us, we didn't have to do it. So let's go ahead and import that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kurt Kemple  14:14&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Okay, so now we're ready to run the project. Okay, so we've got our build. So let's do open preview and we get hello world. So our function was called. And we are now able to access this function through a graphical API. So once again, what we did was we use the API SDK essentially off of API, in random craft kill operation that was automatically generated for us, we set up a server list function. So since we we're mocking this, we can actually make changes in real time. So let's go ahead and change that. Let's say hello universe. Right. So we change that reload the page, hello universe. So now we can work with this locally change, get get the function working like we want just like as if we had pushed it had it hundred percent ready to go, and then deploy it to AWS. So it's just a much improved workflow. And so let's take a look.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kurt Kemple  15:34&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
So to do that, we just control See, the next thing that we would want to do is run amplify, push, this would put the resources in AWS. And then if we restarted the app, we would actually be talking to production service. Instead, I'm not going to push it out yet, because even though we're doing this video, we're not done building out this this function or this graph kill API. So in the next video will take a look at adding dependencies to this lambda function, like using other MPM packages, and how we can handle parameters. And maybe we'll add something fun and fetch some actual data. Alright, thank you for joining me. I hope you enjoyed this, and I'll see you next week. Bye now.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>amplify</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Should interviewees be allowed to search for answers?</title>
      <dc:creator>Kurt Kemple</dc:creator>
      <pubDate>Wed, 28 Aug 2019 18:08:51 +0000</pubDate>
      <link>https://forem.com/theworstdev/should-interviewees-be-allowed-to-search-for-answers-42kn</link>
      <guid>https://forem.com/theworstdev/should-interviewees-be-allowed-to-search-for-answers-42kn</guid>
      <description>&lt;p&gt;I spoke with a colleague today about interviewing and we were both in agreement that not being able to look up answers/solutions to problems is not a good way to interview. Really takes away from the real-world experience of a developer. I wear out that Google search bar on a daily basis so why would we expect others to be able to recall information from their heads when it can easily be searched for.&lt;/p&gt;

&lt;p&gt;On another note, should they be able to use pre-built solutions like libraries or frameworks to solve problems. Again, I'm of the yes attitude. Providing an existing solution is something we do all the time in our day-to-day jobs.&lt;/p&gt;

&lt;p&gt;Can't wait to hear what you think!&lt;/p&gt;

</description>
      <category>discuss</category>
    </item>
    <item>
      <title>Introducing Quick Notes</title>
      <dc:creator>Kurt Kemple</dc:creator>
      <pubDate>Tue, 27 Aug 2019 22:50:48 +0000</pubDate>
      <link>https://forem.com/theworstdev/introducing-quick-notes-9kc</link>
      <guid>https://forem.com/theworstdev/introducing-quick-notes-9kc</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F2ja8yzlgstr2vc95a3ej.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F2ja8yzlgstr2vc95a3ej.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deploy a full stack web app to help you organize your notes when you're on the go.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The other day I released Journey, a bite sized app that helps you track your job listings when on the job hunt. I received a lot of positive feedback and figured I would put together some more examples of the types of things you can do with AWS Amplify and backing Amazon services.&lt;/p&gt;

&lt;p&gt;That's why I built Quick Notes. It's a small enough app that it can be figured out relatively easily and it also serves a purpose that hopefully many will find useful, just like Journey.&lt;/p&gt;

&lt;h2&gt;
  
  
  What It Does
&lt;/h2&gt;

&lt;p&gt;Quick notes allows you to quickly take down and access notes and provides features like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🎙 Record notes&lt;/li&gt;
&lt;li&gt;🔈 Play notes back&lt;/li&gt;
&lt;li&gt;📖 Read notes&lt;/li&gt;
&lt;li&gt;👮‍ Authenticated&lt;/li&gt;
&lt;li&gt;🔥 Serverless back end&lt;/li&gt;
&lt;li&gt;🚀 GraphQL&lt;/li&gt;
&lt;li&gt;💻 Deploy back end in minutes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;The code for the app is located &lt;a href="https://github.com/kkemple/quick-notes" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This project uses Amazon ML services (Amazon Polly and Amazon Transcribe) and the Amplify &lt;code&gt;Predictions&lt;/code&gt; category to &lt;a href="https://github.com/kkemple/quick-notes/blob/master/src/components/Note.js#L68" rel="noopener noreferrer"&gt;convert text to speech&lt;/a&gt; for playing notes, and for &lt;a href="https://github.com/kkemple/quick-notes/blob/master/src/components/Record.js#L96" rel="noopener noreferrer"&gt;converting recorded notes to text&lt;/a&gt; to store in AWS AppSync (GraphQL service).&lt;/p&gt;

&lt;p&gt;In the project, you'll notice a folder named &lt;code&gt;amplify&lt;/code&gt;. This folder contains the back end for the app that can be redeployed in anyone's account. In the &lt;code&gt;amplify&lt;/code&gt; folder you'll see a &lt;code&gt;backend&lt;/code&gt; folder. In this folder you'll see the configuration for the four main features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication service (powered by Amazon Cognito)&lt;/li&gt;
&lt;li&gt;GraphQL API (built with AWS AppSync)&lt;/li&gt;
&lt;li&gt;Speech To Text Generation (built with Amazon Transcribe)&lt;/li&gt;
&lt;li&gt;Text to Speech Generation (built with Amazon Polly)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the &lt;code&gt;backend/api&lt;/code&gt; folder you'll see the GraphQL API configuration as well as the base &lt;a href="https://github.com/kkemple/quick-notes/blob/master/amplify/backend/api/quicknotes/schema.graphql" rel="noopener noreferrer"&gt;GraphQL Schema&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is the base GraphQL Schema. You'll see that the base schema looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Note&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;allow&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;updatedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you've never worked with Amplify before you may not be aware of the &lt;code&gt;@model&lt;/code&gt; and &lt;code&gt;@auth&lt;/code&gt; directive. These are part of the &lt;a href="https://aws-amplify.github.io/docs/cli-toolchain/graphql" rel="noopener noreferrer"&gt;GraphQL Transform&lt;/a&gt; library of the Amplify CLI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;@model&lt;/strong&gt; - Decorate any base type with this directive to get CRUD and list query and mutation definitions, a DynamoDB table, and resolvers created for the GraphQL operations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a class="mentioned-user" href="https://dev.to/auth"&gt;@auth&lt;/a&gt;&lt;/strong&gt; - Decorate any base type or field with this directive to get granular authentication and authorization set up for protected data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying the App
&lt;/h2&gt;

&lt;p&gt;To automatically deploy the app, click the big orange button 👇&lt;/p&gt;

&lt;p&gt;&lt;a href="https://console.aws.amazon.com/amplify/home#/deploy?repo=https://github.com/kkemple/quick-notes" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Foneclick.amplifyapp.com%2Fbutton.svg" alt="amplifybutton"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you wish to manually deploy the app, follow the instructions below.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Deploy the back end and run the app
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Clone the repo &amp;amp; install the dependencies
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~ git clone https://github.com/kkemple/quick-notes.git
~ &lt;span class="nb"&gt;cd &lt;/span&gt;quick-notes
~ npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Initialize and deploy the Amplify project
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~ amplify init
? Enter a name &lt;span class="k"&gt;for &lt;/span&gt;the environment: dev &lt;span class="o"&gt;(&lt;/span&gt;or whatever you would like to call this &lt;span class="nb"&gt;env&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
? Choose your default editor: &amp;lt;YOUR_EDITOR_OF_CHOICE&amp;gt;
? Do you want to use an AWS profile? Y

~ amplify push
? Are you sure you want to &lt;span class="k"&gt;continue&lt;/span&gt;? Y
? Do you want to generate code &lt;span class="k"&gt;for &lt;/span&gt;your newly created GraphQL API? N
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; We already have the GraphQL code generated &lt;span class="k"&gt;for &lt;/span&gt;this project, so generating it here is not necessary.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Start the app and register a new user
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~ yarn start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deploy the front end
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create a new repository with your git service of choice&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Push the project to your new repository&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~ git remote add origin &amp;lt;your_new_repository&amp;gt;
~ git push &lt;span class="nt"&gt;--set-upstream&lt;/span&gt; master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Connect to &lt;a href="https://console.aws.amazon.com/amplify/home" rel="noopener noreferrer"&gt;AWS Amplify Console&lt;/a&gt; and wait for build to start. You will be given a production URL and you are ready to take some notes!&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Customizing the GraphQL schema
&lt;/h2&gt;

&lt;p&gt;This schema can be edited. If you need additional fields, you can update the backend by doing the following:&lt;/p&gt;

&lt;p&gt;Update the schema (located at amplify/backend/api/quicknotes/schema.graphql).&lt;/p&gt;

&lt;p&gt;Redeploy the back end&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;If you or anyone you know needs help getting up and running with this app, reach out to me on &lt;a href="https://twitter.com/kurtiskemple" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, I'd be happy to help!&lt;/p&gt;

</description>
      <category>react</category>
      <category>aws</category>
      <category>amplify</category>
      <category>graphql</category>
    </item>
  </channel>
</rss>
