<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Andy Haskell</title>
    <description>The latest articles on DEV Community by Andy Haskell (@andyhaskell).</description>
    <link>https://dev.to/andyhaskell</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%2F140671%2Fe64aac4c-d5e1-49ac-8d17-1405ab8f12a4.jpg</url>
      <title>DEV Community: Andy Haskell</title>
      <link>https://dev.to/andyhaskell</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/andyhaskell"/>
    <language>en</language>
    <item>
      <title>Conferencing tips as an autistic + ADHD conference-goer</title>
      <dc:creator>Andy Haskell</dc:creator>
      <pubDate>Thu, 27 Feb 2025 06:23:21 +0000</pubDate>
      <link>https://dev.to/andyhaskell/conferencing-tips-as-an-autistic-adhd-conference-goer-8pk</link>
      <guid>https://dev.to/andyhaskell/conferencing-tips-as-an-autistic-adhd-conference-goer-8pk</guid>
      <description>&lt;p&gt;I'm an AuDHD (autistic+ADHD) software engineer, and I've been going to tech conferences since OWASP Boston Application Security Conference 2010 when I was in college. I've gone as an attendee, a speaker, helping run a booth, and volunteering in conference programs like GopherCon Guides and GopherCon's Neurospicy Meetup.&lt;/p&gt;

&lt;p&gt;In addition to the career benefits of conferencing, such as growing your professional network and seeing more perspectives on the tech you build with, they are also a great way to meet people you know from your favorite online communities. I love the tech conference greeting "Oh hey! I {App}-know you!". Some of my favorite memories in tech have happened at conferences, like hundreds of Gophers exploring New York City on a scavenger hunt at GothamGo, taking an impromptu trip to Red Rocks after meeting a new group of friends on Community Day at GopherCon Denver, and giving my very first tech conference talk at DevFest Albany with several new tech friends in the audience.&lt;/p&gt;

&lt;p&gt;However, conferences can be challenging for neurodivergent conference-goers. It's easy to get overwhelmed with too much socializing, or with figuring out which events on the agenda to go to. And packing for a trip with ADHD - well, there's a reason there's so many memes about that in online neurodivergent communities. So I would like to share some of my tips for getting the most out of going to tech conferences while neurodivergnt.&lt;/p&gt;

&lt;p&gt;⚠️ Before we start, just one thing to keep in mind, the advice I'm giving is not a definitive one-size-fits-all guide to conferencing while neurodivergent. There's no such guide since even people of the same neurotype can be very different from each other, including having different needs and priorities while conferencing. So instead, treat these tips more like building blocks you can use for building &lt;strong&gt;your&lt;/strong&gt; guide to conferencing, and only use the ones that you find relevant.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requesting and finding accommodations
&lt;/h2&gt;

&lt;p&gt;Although I haven't formally requested accommodations for a tech conference, I do know that if there are accommodations you need, emailing the organizing team is a good way to request them. Often conferences have contact information for reaching out to organizers on their websites.&lt;/p&gt;

&lt;p&gt;You can ask the organizers for details about the venue like its layout, ask about what accommodations are available for neurodivergent attendees, and specifically request accommodations that they might need more advance notice to get. In addition, some conferences put a field in their registration form for attendees to request accommodations you might need.&lt;/p&gt;

&lt;p&gt;A few of the accommodations I've seen at conferences that an attendee might ask organizers about are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Food at conference lunches that's compatible with dietary restrictions if you have any. Often the online registration form has an area for submitting information about dietary restrictions so that organizers can take that into account placing catering orders.&lt;/li&gt;
&lt;li&gt;Live-captioning on the big screens for talks, which helps both people with hearing disabilities, and people who have challenges with auditory processing, which is a common issue for autistic people.&lt;/li&gt;
&lt;li&gt;Some conferences have chillout areas set up for getting away from the action if you're overwhelmed. I've even heard of conferences that bring in therapy dogs in one area for conference-goers to play with.

&lt;ul&gt;
&lt;li&gt;But even if a conference doesn't have a designated chillout area, the organizers could probably tell you where some good spots are in and near the venue to get a break from the action.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Reserved seats, such as closer to the stage for attendees with vision or hearing disabilities, or have another reason to need to be at the front.&lt;/li&gt;

&lt;li&gt;The &lt;a href="https://hdsunflower.com/us/" rel="noopener noreferrer"&gt;hidden disabilities sunflower lanyard&lt;/a&gt; is becoming an increasingly well-known symbol for someone to convey they have a non-visible disability, making it easier to ask for support as the symbol becomes more widely recognized. Besides at conferences, it's also being recognized at a lot of airports.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;And remember there is &lt;strong&gt;no shame&lt;/strong&gt; in needing accommodations, just like there is no shame in being neurodivergent or having a disability. So if you need accommodations, don't be ashamed about asking! And it's a good sign about the conference itself if the organizers make the process streamlined for getting accommodations or take the time to understand your needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  A bag of tips on packing for the event
&lt;/h2&gt;

&lt;p&gt;Packing for a trip while having ADHD can be challenging, since doing laundry and folding it is so stop-and-go, and it's easy to end up switching between categories of things to pack.&lt;/p&gt;

&lt;p&gt;In order to make this more manageable, I wouldn't say I have a perfected technique, but some tips that have helped me with my packing, are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Having dedicated pouches in my backpack for each category of things I'm packing. My bag has four major pouches and they are:

&lt;ul&gt;
&lt;li&gt;Large electronics. I've found this dedicated pocket particularly makes it easier at airport security, so I only need to open one pouch in my bag to find all the electronics I need to put in their own bins.&lt;/li&gt;
&lt;li&gt;A dedicated pouch in the most secure part of the bag for all can't-lose items, such as my passport for international conferences. That way, once I show my passport at customs, I can put it there and know that that's the only place it could be until I need it again coming home.&lt;/li&gt;
&lt;li&gt;A pouch for TSA-approved travel-size personal hygiene.&lt;/li&gt;
&lt;li&gt;A pouch for notebooks, pens and pencils, and entertainment.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Leaving those dedicated backpack pouches open until everything for a given pouch is packed, so that the items inside remain visible, which helps with ADHD object-permanence.&lt;/li&gt;

&lt;li&gt;Listing out absolute-must-have items. For example, prescription medications if you are taking any, your passport if you are travelling internationally for this conference, and items that your job required you to bring if you're going to the conference as part of work.&lt;/li&gt;

&lt;li&gt;Laying out clothes by outfit, rather than by category. I've found that has helped me get a visualization of how many complete outfits (daytime outfits, pajamas, workout clothes, slightly-fancy attire for night events, clothes for any outdoor events) I have so far, and how much more laundry is left to do for my clothes to be completely packed.&lt;/li&gt;

&lt;li&gt;Also when it comes to clothes, having a dedicated packing area in my apartment where I lay out those clothes, so that while remaining laundry is in progress, I don't mistakenly re-wear some of the clothes I wanted to pack&lt;/li&gt;

&lt;li&gt;Bringing a dedicated reusable bag and saving for swag (the T-shirts, laptop stickers, and trinkets they give away at booths). At bigger conferences, there's a lot of swag you'll get, and that bag makes it easier to keep track of it all.&lt;/li&gt;

&lt;li&gt;Speaking of swag, I recommend packing a couple fewer graphic T-shirts than you normally would for a trip, since it's common for companies to give out T-shirts as swag at their booths&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Additionally, one other thing I plan on trying for next time I go to a conference is setting up a &lt;code&gt;travel&lt;/code&gt; directory on my laptop with templates for packing checklists. That way, packing checklists can be reused and printed out with just small tweaks. I'm planning on making my own template, but searching "packing list template", I am finding a lot of pre-made templates online.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prioritizing events to go to
&lt;/h2&gt;

&lt;p&gt;Conferences can be overwhelming for neurodivergent attendees. They have a lot of socializing and being in crowds, with the main convention center events often going eight hours or more a day, plus all the afterparties. But one helpful thing I've found from going to so many conferences, is that &lt;strong&gt;you don't need to go to everything!&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;I find it useful to check the agenda once am considering getting my ticket to the conference, so I can pick out the events I really want to focus on being at. By doing that, it's possible to also pick times in the conference that I want to allocate as breaks to decompress. To pick out events, I keep track of three main categories of time blocks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Time blocks where I committed to being at an event. This would be things like when I am on stage / at mic check if I'm a speaker, being at an event I signed up for as a volunteer, or being at the exhibitors' hall if I signed up for booth duty with work. It also includes workshops I had paid extra to attend, or meeting up with friends I made plans with.

&lt;ul&gt;
&lt;li&gt;This also includes scheduling windows of time to eat and decompress.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Talks and or free workshops I really want to see. For me, that's primarily talks on areas of tech I want to learn more about, talks I could see directly benefitting my career, and talks where I'm friends with the speaker and want to hear them.

&lt;ul&gt;
&lt;li&gt;I also like to allocate certain hours in this category to participate in the "hallway track" (tech slang for all the networking that happens in the convention center in between talks). That's a good way both to see friends I know from online tech communities like the Gophers and #CodeNewbie, as well as to grow my professional network by visiting the booths and social events like afterparties.&lt;/li&gt;
&lt;li&gt;This also can include seeing things in the area you really want to see. If I've got a conference in San Diego to go to, as an autistic guy with a lifelong Special Interest in animals, you'll definitely find me at the San Diego Zoo (namely at the red panda exhibit).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;A remaining category, for if you have left-over social energy, you can also pick some "nice to see" events. For example I like learning in tech about topics that have nothing to do with my current job, so that I can learn about the tech I'd be interested in trying for a side project. So I make a point of going to talks on new areas of tech if I have the social energy, but if I don't, no sweat and no guilt.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;If phone reminders help you, then you can put the events you're prioritizing into your phone's reminder app, and from those apps utilize 30-minute warnings. I find that to particularly come in handy for my most important events, and knowing when I need to get back to the convention center if I am seeing friends in town.&lt;/p&gt;

&lt;h2&gt;
  
  
  Staying regulated and doing self-care at the event
&lt;/h2&gt;

&lt;p&gt;Conferences can be overwhelming for neurodivergent attendees with a lot of socializing and being in crowds, at an event that goes eight hours or more a day, plus going to afterparties. So make sure to do whatever you need to in order to prevent getting overstimulated, so have enough energy for the stuff you really want to see and do.&lt;/p&gt;

&lt;p&gt;I particularly make a point of getting outdoors each day at the conference so that I can get some fresh air, as well as time to decompress by not having tech stuff on my mind. Sometimes that's going to things I wanted to see in the city, and other times it's just going exploring on a long lunch walk or eating on my hotel's rooftop when it's warm out.&lt;/p&gt;

&lt;p&gt;And as I mentioned in the last section, you can actively allocate time in your go-to calendar app specifically for taking care of yourself and decompressing. And if you do need to exit a social event early because you ran out of social energy, that is completely an option. In my experience, people haven't cared if I've decided to dip from an event early.&lt;/p&gt;

&lt;p&gt;If stimming helps you stay regulated, which it does for many autistic people, bring a stim toy. One I use is beaded lava rock bracelets; they're discreet since they're a fashion item, but rolling the beads makes them double as a good stim toy. They also make a cool way to represent your tech stack, by getting a stack of bracelets in the colors for the tech you use or tech communities you're involved in, such as blue for Go, green for Vue, yellow for Python, or purple for the #CodeNewbie community. And there are other discreet stim toys you can find as well online.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decide for yourself how much you feel willing/safe to "be yourself" at a conference
&lt;/h2&gt;

&lt;p&gt;In many neurodivergent communities, the term "masking" is used to refer to neurodivergent people avoiding expressing neurodivergent traits in order to blend in with their surroundings. This can be things like hiding stims (or making them more discreet as I mentioned before), trying to make more eye contact than normal if eye contact is expected, making small talk which many neurodivergent people find unnatural, or staying longer than you actually want to at an event. Masking may facilitate blending in, but it is stressful to mask for a long time, and it burns through social capacity.&lt;/p&gt;

&lt;p&gt;Some reasons someone might mask at a conference are that they are on booth duty or in some customer-facing role at the event for work, or because they are networking on a job search and trying to maximize the odds that their first impression with the company they're talking to "lands" with them (and by the way, if you are a tech employer who wants to hire talented people of all neurotypes, working on making your hiring process neuroinclusive means you're not overlooking talented neurodivergent innovators). It is unfortunate, but there is still a lot of stigma around being neurodivergent, so there is some risk to showing neurodivergent traits.&lt;/p&gt;

&lt;p&gt;However, many neurodivergent conference attendees choose to not mask, and sometimes even be vocally neurodivergent in conferences and other professional spaces. For example, they might choose not to suppress their stims because they want to regulate their energy levels to not get overstimulated. They might express their neurodivergent traits to make it easier for other neurodivergent people to find them, and help them "feel normal" expressing traits they might be masking.&lt;/p&gt;

&lt;p&gt;Even when it comes to networking though, I have found that for my entire career, I've been able to use some of my neurodivergent traits to build my personal brand as well as make a lot of great friends in tech. Probably my own most well-known example is how I like to work references to sloths, an autistic Special Interest I've had since 2011, into tutorials that I write and on my posts in tech social media communities. And I'll let you in on a secret about non-tech Special Interests at tech conferences, after a few hours into the convention, it's refreshing to hear people at the hallway track talk about something that isn't tech, or bring up an angle to the tech that they haven't considered. So networking doesn't necessarily have to mean completely masking.&lt;/p&gt;

&lt;p&gt;Whether and how much for you to mask though, is a decision that is &lt;strong&gt;yours&lt;/strong&gt; to make. As an example, for myself one big reason I like to be overtly autistic and ADHD at conferences when I feel safe to, is to de-stigmatize neurodivergence by making it so more people hear about it from our actual perspectives, rather than from the many harmful stereotypes spread about us. However, in more formal settings, I still have some degree of masking to blend in and follow professional etiquette, and to make what I am saying clearer for neurotypicals to understand. So &lt;strong&gt;only mask as much or as little as you are willing and feel safe to&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Another tip, at tech conferences, check the program because you might be able to find events where you can be yourself more. For example, outings related to doing something you really like. And you may even find that there is a neurodiversity-focused event at your conference! For example, since 2023, GopherCon has had a Neurospicy meetup for neurodivergent people, people questioning their neurotypes, and neurotypical allies. They rent out a bar, the music is turned down to prevent auditory overstimulation, and people hang out and talk over catered free food, trading Special Interests. I've been there twice, and it was a highlight both times!&lt;/p&gt;

&lt;p&gt;Regardless of your neurotype, I hope at some of my tips help you with having a memorable time at tech conferences, and with growing your tech career from conferencing, and if you learned something new about neurodiversity, I would love to hear about it! 🌈♾️&lt;/p&gt;

</description>
      <category>neurodiversity</category>
      <category>codenewbie</category>
      <category>career</category>
      <category>devrel</category>
    </item>
    <item>
      <title>How AuDHD traits have helped me get good at devrel</title>
      <dc:creator>Andy Haskell</dc:creator>
      <pubDate>Sun, 14 Apr 2024 18:50:44 +0000</pubDate>
      <link>https://dev.to/andyhaskell/how-audhd-traits-have-helped-me-get-good-at-devrel-1ml7</link>
      <guid>https://dev.to/andyhaskell/how-audhd-traits-have-helped-me-get-good-at-devrel-1ml7</guid>
      <description>&lt;p&gt;Developer relations (devrel) might not be front of everyone's mind as a career that a neurodivergent person would excel in. However, not only are there many neurodivergent people already succeeding and trailblazing in this field, many neurodivergent traits can actually be conducive to great devrel.&lt;/p&gt;

&lt;p&gt;To demonstrate what I mean, I'd like to talk about some of my own neurodivergent traits that have helped me get good at devrel in the Go, JavaScript, and #CodeNewbie communities. I am AuDHD (autistic + ADHD) and although I haven't formally worked in a devrel role, I'd still call myself devrel-adjacent. I have done a lot of devrel work through tutorial-writing, event organizing, open-source contributions, and participating in social media tech communities, and my neurodivergent traits have been integral to my devrel style.&lt;/p&gt;

&lt;p&gt;⚠️ Two things before we begin:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;While I am talking about my own AuDHD traits, please note that I am just one AuDHD person, and that even people who are neurodivergent in the same way don't all have identical traits and skills. So please do not treat me as representative of all AuDHD people. A common adage in the autistic community is "if you meet one autistic person, you've met one autistic person".&lt;/li&gt;
&lt;li&gt;As I will talk about in more detail at the end of this blog post, please &lt;strong&gt;do not&lt;/strong&gt; take away from this "neurodivergence is a super power". While neurodivergent traits can help someone in some aspects of life, they can be disabling in others. Therefore, &lt;strong&gt;accommodations still matter&lt;/strong&gt; for neurodivergent tech workers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Special Interests
&lt;/h2&gt;

&lt;p&gt;One of the most well-known common autistic traits is &lt;strong&gt;Special Interests&lt;/strong&gt;. It's where an autistic person gets intensely focused on some topic. The one that's become an autistic stereotype is a Special Interest in trains (some of us do have that Special Interest, some don't), but really any topic can be a Special Interest. For example I've been a bio guy basically since I found out nature documentaries were a thing!&lt;/p&gt;

&lt;p&gt;Special Interests have helped me do devrel work in three ways. First, they get me motivated to understand a tech stack in-depth. Second, it makes me want to teach others everything I've learned (this is another common autistic trait, &lt;strong&gt;infodumping&lt;/strong&gt;). And third, the most devrel-relevant part, it makes me excited to participate in communities around the tech that I work with.&lt;/p&gt;

&lt;p&gt;Probably the most salient example of this in my devrel, was getting a Special Interest in Go in 2014. Soon after getting the hang of Go's &lt;code&gt;net/http&lt;/code&gt; package, I started tweeting about it and writing Go tutorials. This led to me making friends with a lot of other Gophers (people who code in Go), and when the &lt;a href="//meetup.com/bostongo"&gt;Boston Go&lt;/a&gt; meetup launched, I quickly became an enthusiastic regular at the meetup, and I've participated in the Go community through tutorial-writing, public speaking, and working on the organizing team for Boston Go.&lt;/p&gt;

&lt;p&gt;Besides Special Interests directly in tech though, Special Interests can also be used to add a personal touch to your devrel. I got a Special Interest in sloths through a friend in college, and since then sloth facts have been a signature part of the examples I use in my blog posts and talks. 🦥&lt;/p&gt;

&lt;h2&gt;
  
  
  ADHD novelty-seeking
&lt;/h2&gt;

&lt;p&gt;A common ADHD trait is novelty-seeking - seeking out new things and new experiences. It's why growing up I went through so many video games. It's also why in my tech career, even though for my actual jobs I've primarily done backend web engineering in Go, outside of work, I've accumulated a lot of other tech skills like the JavaScript frontend ecosystem, terminal UIs, accessibility, and Ruby.&lt;/p&gt;

&lt;p&gt;This ADHD novelty-seeking, and autistic Special Interests, make a potent combination in devrel, because novelty-seeking in a tech stack someone knows in-depth leads to helping developers see how that tech can solve real-world problems, which can lead to really practical tutorials (with some Special Interest-driven fun mixed in!). And meeting developers where they are, whether they're hobby developers or they use your tech at work, is a key part of an impactful devrel program, since that gets more people using your tech and participating in its community!&lt;/p&gt;

&lt;p&gt;Likewise, since using a lot of different tech means spending a lot of my time being a newcomer in it, that leads to finding aspects of "getting stuff done" with a tool that aren't talked about enough in a newcomer-friendly way. My first blog post to get more than 10,000 views was &lt;a href="https://itnext.io/webpack-from-0-to-automated-testing-4634844d5c3c"&gt;this tutorial on webpack&lt;/a&gt;, which came out of spending A LOT of time getting tangled up in the frontend JavaScript ecosystem. The webpack resources I found were well-written for experienced frontend developers, but I found them challenging to follow as a newcomer and I felt like I was missing some core concepts. So after cobbling together a webpack build that gave me what I needed, I worked backwards to write a from-the-ground-up webpack tutorial (also, 14-minute read, talk about infodumping! 😅).&lt;/p&gt;

&lt;h2&gt;
  
  
  Attention to detail
&lt;/h2&gt;

&lt;p&gt;One more AuDHD trait I would like to talk about is autistic precision. Many autistic people prefer to do things precisely and give precise answers to questions. This often can make an autistic person come off as pedantic, but when you're writing documentation, a from-the-ground-up tutorial, or in general giving instructions, this can be advantageous.&lt;/p&gt;

&lt;p&gt;In coding in general, not just devrel, this attention to detail can lead to sniffing out bugs that are easy to overlook, or detecting the potential for a bug or technical debt before the coding on an assignment has even started. And for me, because my devrel comes out of a "learning by doing" approach, when I learn a new framework, I find myself spending a lot of time pondering "would this approach still work in [this scenario I'm eventually gonna run into on this project]?" And that sort of attention to detail in devrel leads to laser-carved documentation that lets developers know about edge cases, give realistic examples of how the code is used, and clarify differences between similar pieces of functionality.&lt;/p&gt;

&lt;p&gt;This attention to detail also can mean that for key abstractions in a tool or framework, what concretely goes on doesn't go unexplained. For example, when I was learning Go for web development, my first stumbling block was understanding how interfaces worked, particularly &lt;code&gt;http.Handler&lt;/code&gt;, which is key to doing web development with Go's powerful &lt;code&gt;net/http&lt;/code&gt; package and the fits-like-a-glove package built on top of it, the &lt;a href="https://github.com/gorilla/mux"&gt;Gorilla Mux&lt;/a&gt; router. My way of finding out how that worked, and seeing the elegance of that interface, was pretty unorthodox - I figured out how Handlers worked by looking directly at Go's source code (which also is a demonstration of Go's readability, if you're interested in joining the Gophers!). And coming out of that was my very first tech talk at in 2015, on learning Gorilla from its Node.js counterpart, Express.js!&lt;/p&gt;

&lt;h2&gt;
  
  
  Accommodations still matter
&lt;/h2&gt;

&lt;p&gt;While in this post I talked about how my AuDHD traits have shaped my devrel work, one thing you shouldn't take away from this talk, especially if you run a devrel program, is the common cliche "neurodivergence is a super power". While neurodivergent traits often can be strengths in some areas as I've shown, they can be disabling in other areas. This is why it is still important in devrel, like in all workplaces, disability accommodations are still important.&lt;/p&gt;

&lt;p&gt;For example, one flip side to my eye for detail, is perfectionism in my work. So as a software engineer, whenever I'm working on a team and there are time constraints to work around, I find it really helpful coordinating with a teammate to determine which things to prioritize and make a plan for &lt;strong&gt;when&lt;/strong&gt; to address a concern I noticed from a low-level detail. Also, with ADHD, I find it really helpful to allocate dedicated distraction-free focus time. And while I don't use this accommodation myself, one accommodation I have heard of people using is AI transcriptions of major meetings so that people can go through the discussion of a meeting at their own pace.&lt;/p&gt;

&lt;p&gt;Many accommodations, by the way, can have benefits for your whole team. For example, if it's the norm on a team for people to respect each other's focus time, that can lead to the whole team, including neurotypical (non-neurodivergent) employees, being able to do distraction-free work. Meeting recordings and transcripts have a side benefit also mean someone can watch a meeting even if it happened outside of work hours in their time zone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Neurodiversity strengthens devrel!
&lt;/h2&gt;

&lt;p&gt;While I didn't want you taking away from this that neurodivergence is a super power, the takeaway I do want to give is that like other forms of diversity such as racial, gender, LGBTQ, cultural, and age diversity, I firmly believe neurodiversity &lt;strong&gt;strengthens&lt;/strong&gt; devrel! Yes neuroinclusion and all forms of inclusion in the workplace take effort, but I believe putting in that groundwork sets a team up for success.&lt;/p&gt;

&lt;p&gt;On a neurodiverse team where neurodivergent and neurotypical people are supported and respected, you get perspectives of people teaching about your tech from different styles of thinking. This is incredibly impactful when you're teaching about a platform, tool, or framework, because people using your tech and participating in its community also have a wide range of problem-solving styles and questions they need answers to when they're using your tech. Additionally, on a neuroinclusive team, your neurodivergent team members don't get burnout so easily, which means they're more likely to stick around and become great mentors and leaders in your team! This is all on top of the ways I've mentioned that neurodivergent traits can be strengths for individuals doing devrel work.&lt;/p&gt;

&lt;p&gt;To end this post, since as I said in the beginning, I am only one AuDHD person, if you're neurodivergent and do devrel in any capacity (whether developer advocate is your formal job title, or you give tech talks from time to time), and you feel comfortable sharing, I'd love to hear your perspective on if/how you feel your neurodivergence shapes how you do devrel!&lt;/p&gt;

&lt;p&gt;And happy Autism Acceptance Month! 🌈♾️&lt;/p&gt;

</description>
      <category>neurodiversity</category>
      <category>devrel</category>
      <category>codenewbie</category>
      <category>career</category>
    </item>
    <item>
      <title>Write your tech talk slides rapidly with Marp</title>
      <dc:creator>Andy Haskell</dc:creator>
      <pubDate>Tue, 14 Nov 2023 05:57:21 +0000</pubDate>
      <link>https://dev.to/andyhaskell/write-your-tech-talk-slides-rapidly-with-marp-2c7g</link>
      <guid>https://dev.to/andyhaskell/write-your-tech-talk-slides-rapidly-with-marp-2c7g</guid>
      <description>&lt;p&gt;I've been doing public speaking in tech since 2015 when I presented my very first lightning talk at Boston Go, and since then, I've given talks at meetups, at work, and at a couple conferences.&lt;/p&gt;

&lt;p&gt;But while I love speaking at events to teach tech concepts I've learned, there can be some friction getting the ideas from my brain to my slides, with thinking through slide layouts and polishing the slides so my talk flows well from slide to slide.&lt;/p&gt;

&lt;p&gt;What's helped me with writing slides lately though, is a tool called Marp, which allows me to write my slide layout by typing just in my text editor &lt;strong&gt;in Markdown&lt;/strong&gt;. Which for me means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🏎️ Because Marp has sensible built-in layouts, I don't need to think about things like font size until I have a reason to; I can just type like I would for a blog post, and the slide will look good enough that I can practice with it right away, and tweak its layout later!&lt;/li&gt;
&lt;li&gt;👀 Since I'm writing slides in my editor, if I want to switch to experimenting with the code that my talk is covering, that's much less of a context-switch for me than going between a drag-and-drop slide tool and a text editor.

&lt;ul&gt;
&lt;li&gt;Speaking of preventing context switching, there's also a &lt;a href="https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode" rel="noopener noreferrer"&gt;Marp plugin for VSCode&lt;/a&gt; that you can use to see your slides side by side with the text you're writing, in real time!&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;🦕 Since my slides are made of text, that makes it easy to have different versions of my talk &lt;strong&gt;versioned in Git&lt;/strong&gt;, so as I experiment with different arrangements of slides, I can switch versions as fast as you can say &lt;code&gt;git checkout&lt;/code&gt;!&lt;/li&gt;

&lt;li&gt;🎨 You can tweak your layout either for individual slides, or all slides, using CSS!&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;And I can say that Marp is conference-ready, since it's what I used for writing and iterating on my slide deck at GopherCon this year!&lt;/p&gt;

&lt;p&gt;So I'd like to show you in this tutorial how to use Marp to write three types of slides: A title slide with an eye-catching image, an "about me" slide with an image on the left and text on the right, and a code snippet slide. I'll also show you how to add speaker notes that only the speaker can see while presenting, and how to use CSS to give your slide layout more customization.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Marp
&lt;/h2&gt;

&lt;p&gt;For getting Marp, you install its command-line interface with a package manager, like Homebrew, Scoop, or Yarn.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

yarn global add marp-cli


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

&lt;/div&gt;

&lt;p&gt;With Marp installed, let's write our slide deck!&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing our first title slide
&lt;/h2&gt;

&lt;p&gt;First, let's give our talk a title slide. Paste this Markdown into a file named &lt;code&gt;talk.md&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

---&lt;/span&gt;
marp: true
theme: uncover
&lt;span class="gh"&gt;paginate: true
---
&lt;/span&gt;
&lt;span class="gh"&gt;# What is io.Reader in Go?&lt;/span&gt;

YOUR NAME - @YOUR_SOCIAL_MEDIA&lt;span class="sb"&gt;


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

&lt;/div&gt;

&lt;p&gt;We've got two pieces of Marp syntax written now: At the top, the section full of options inside the triple dashes is called the &lt;a href="https://marpit.marp.app/directives?id=front-matter" rel="noopener noreferrer"&gt;frontmatter&lt;/a&gt;, and it contains configuration for your presentation as a whole.&lt;/p&gt;

&lt;p&gt;The rules in our frontmatter are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;marp: true&lt;/code&gt;, which indicates that this is a Marp presentation&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;theme: uncover&lt;/code&gt;, which sets your slides' theme to Uncover, one of the &lt;a href="https://github.com/marp-team/marp-core/blob/main/themes/README.md" rel="noopener noreferrer"&gt;built-in themes&lt;/a&gt; from Marp.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;paginate: true&lt;/code&gt;, which causes your slides to include a page number.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's other rules you can add in your frontmatter as well, such as &lt;code&gt;style&lt;/code&gt; for additional custom CSS styling, or &lt;code&gt;backgroundImage&lt;/code&gt; if you want your slides to all have a default background image, such as a patterned background to make your slides look more flashy.&lt;/p&gt;

&lt;p&gt;Below the frontmatter, we have our first slide written in Markdown. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;

&lt;span class="gh"&gt;# What is io.Reader in Go?&lt;/span&gt;

&lt;span class="gs"&gt;**YOUR NAME - @YOUR_SOCIAL_MEDIA**&lt;/span&gt;&lt;span class="sb"&gt;


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

&lt;/div&gt;

&lt;p&gt;Just like in standard markdown, the text represents a header for the title of your talk, and regular text in bold for your name and social media account.&lt;/p&gt;

&lt;p&gt;To see what this slide actually looks like in a presentation, run the Marp CLI we just installed:&lt;/p&gt;

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

marp &lt;span class="nt"&gt;-w&lt;/span&gt; talk.md


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

&lt;/div&gt;

&lt;p&gt;You will then get a prompt to go to a localhost URI. Navigate to there in your browser and you'll&lt;br&gt;
see your slide deck. So far, the title slide looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flx0ugtuqs09uzp0x5gib.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%2Flx0ugtuqs09uzp0x5gib.png" alt="Initial slide, with the header in bold. There is a page marker indicating that we are on the first slide"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We've got our header and name. This is a nice clean layout for a title slide, but what if we wanted a cool image to kick off the talk with? You can add that with some Markdown for an image.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding an image
&lt;/h3&gt;

&lt;p&gt;Similar to in standard Markdown, in Marp you use the &lt;code&gt;![alt text](image URL)&lt;/code&gt; format for rendering images. To try this out, we'll use a photo I got of the bright blue waters on a beautiful day at the beach.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;

&lt;span class="p"&gt;![&lt;/span&gt;&lt;span class="nv"&gt;Picture of the view at the beach; rocks are in the foreground and the water that day was bright blue&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://url/to/beach/image&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="gh"&gt;# What is io.Reader in Go?&lt;/span&gt;

YOUR NAME - @YOUR_SOCIAL_MEDIA
&lt;span class="p"&gt;
---


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

&lt;/div&gt;

&lt;p&gt;Now look at talk.html, and&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%2Fvgk5jylhvutepjgrvuay.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%2Fvgk5jylhvutepjgrvuay.png" alt="First slide now with a photo from the beach, but the image is so tall it pushes the text off of the screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Woah that's a tall image! If we want this image to fit on the slide, we're going to need to resize it, and we would do so by adding a directive to the alt text, and also making the header's text smaller by converting it from an h1 header to an h3 header.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;

&lt;span class="p"&gt;![&lt;/span&gt;&lt;span class="nv"&gt;w:800 h:480 Picture of the view at the beach; rocks are in the foreground and the water that day was aqua&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://url/to/beach/image&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="gu"&gt;### What is io.Reader in Go?&lt;/span&gt;&lt;span class="sb"&gt;


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

&lt;/div&gt;

&lt;p&gt;With the directives &lt;code&gt;w:800 h:480&lt;/code&gt;, we're having Marp set the width and height of the image to 800 pixels and 480 pixels, respectively, fitting neatly in the slide.&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%2Fd2aqyl9c99epobovxx1c.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%2Fd2aqyl9c99epobovxx1c.png" alt="First slide with the image resized so the image and text fit into the height of the slide"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or if you really want to be flashy and make an image that takes up the whole background, you can use the &lt;code&gt;bg&lt;/code&gt; directive!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;![bg Picture of the view at the beach; rocks are in the foreground and the water that day was aqua](https://url/to/beach/image)&lt;/code&gt;&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%2Fwthr2e1a6wqh0g56fcay.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%2Fwthr2e1a6wqh0g56fcay.png" alt="First slide, now with the image being used as the slide's background, the text of the slide in black. In some spots on the image, the rocks and water are darker, causing some letters to be harder to read"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But you'll want to ensure the text contrasts with the colors on the image that it might overlap with. We'll look at one way to do that using drop-shadow text in the section on CSS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding an "about me" slide
&lt;/h2&gt;

&lt;p&gt;To write a new slide, you separate each slide in Marp by adding a line containing three dashes, like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;

&lt;span class="p"&gt;![&lt;/span&gt;&lt;span class="nv"&gt;w:700 h:500 Picture of the view at the beach; rocks are in the foreground and the water that day was bright blue&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://url/to/beach/image&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="gh"&gt;# What is io.Reader in Go?&lt;/span&gt;

YOUR NAME - @YOUR_SOCIAL_MEDIA
&lt;span class="p"&gt;
---
&lt;/span&gt;
Everything from here down to
the next --- line will be
will be part of the Markdown of
the second slide of your talk,
and then you add another --- to
give your talk a third slide&lt;span class="sb"&gt;


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

&lt;/div&gt;

&lt;p&gt;We'll replace the placeholder block of text with an "about me" slide that follows a common layout for slides: An image taking up the left side of the slide, and text on the right.&lt;/p&gt;

&lt;p&gt;And we'll be doing this using a parameter of the image &lt;code&gt;bg&lt;/code&gt; directive we saw earlier, which makes the &lt;code&gt;bg&lt;/code&gt; image only be the left side of the slide: &lt;code&gt;bg left&lt;/code&gt;. For this example, let's have my dog Lola give this talk.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

---
&lt;/span&gt;
&lt;span class="p"&gt;![&lt;/span&gt;&lt;span class="nv"&gt;bg left 70% My dog Lola, an adorable black and white Havanese dog who looks like a tiny floofy panda, on the couch looking at the camera doing a blep&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://url/to/lola/image&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="gh"&gt;# About me&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; &lt;span class="gs"&gt;**Name:**&lt;/span&gt; Lola the Micropanda
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Job:**&lt;/span&gt; CFO at Micropanda Accelerator
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**IG:**&lt;/span&gt; @lolamicropanda&lt;span class="sb"&gt;


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

&lt;/div&gt;

&lt;p&gt;Open up your Marp slide deck and you'll see:&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%2Fyinuhb7f7wv7fc5fn118.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%2Fyinuhb7f7wv7fc5fn118.png" alt="The "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lola's "about me" slide! Notice in addition to the &lt;code&gt;left&lt;/code&gt; parameter on the &lt;code&gt;bg&lt;/code&gt; directive, I also decided to add a &lt;code&gt;70%&lt;/code&gt; parameter. This makes it so the image takes up the middle 70% of the left of the slide, rather than the whole left side of the slide, making the "about me" image appear as a stripe across the left of the slide.&lt;/p&gt;

&lt;p&gt;By the way, you know the technique of presenting a bulleted list where you display the bullet points one by one as you present? Like "A bit about me [show bullet point], I'm Lola the Micropanda, [show another bullet point], I'm Chief Floof Officer of Micropanda Accelerator [show one more bullet point], and you can follow me on Instagram at @lolamicropanda"?&lt;/p&gt;

&lt;p&gt;Marp supports that as well! If you change the bullet points from dashes to asterisks, like this&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

*&lt;/span&gt; &lt;span class="gs"&gt;**Name:**&lt;/span&gt; Lola the Micropanda
&lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="gs"&gt;**Job:**&lt;/span&gt; CFO at Micropanda Accelerator
&lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="gs"&gt;**IG:**&lt;/span&gt; @lolamicropanda&lt;span class="sb"&gt;


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

&lt;/div&gt;

&lt;p&gt;You get a &lt;a href="https://marpit.marp.app/fragmented-list" rel="noopener noreferrer"&gt;fragmented list&lt;/a&gt;; go through the "about me" slide in &lt;code&gt;talk.html&lt;/code&gt; and now when you present, your bullet points appear one by one!&lt;/p&gt;

&lt;h2&gt;
  
  
  Code snippets and speaker notes
&lt;/h2&gt;

&lt;p&gt;Just like how Marp supports images, headers, regular text, and lists, you're also able to have slides in Marp that contain code snippets. Just like in standard Markdown, you make a code snippet with the triple backticks (replaced with a message in brackets for the code snippets ahead because I was having trouble rendering triple backticks inside a code snippet).&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;

&lt;span class="gu"&gt;## io.Reader in Go: small interface with tons of power&lt;/span&gt;

[replace this box with triple backticks in your code]
type Reader interface {
    Read(p []byte) (n int, err error)
}
[replace this box with triple backticks in your code]
&lt;span class="p"&gt;
---


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

&lt;/div&gt;

&lt;p&gt;If you look at this slide in your &lt;code&gt;talk.html&lt;/code&gt;, you'll see:&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%2Fmfdchu5eg5tjnja2rgru.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%2Fmfdchu5eg5tjnja2rgru.png" alt="Slide displaying the code of Go's io.Reader interface"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your code on a slide, formatted to monospace! Though you might want syntax highlighting on your slides, and if you do, then there's a simple tweak you can do: before the leading backticks, type the programming language your code is in. My code is in Go, so I am leading with &lt;code&gt;go&lt;/code&gt; at the end of the triple backticks.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;

&lt;/span&gt;&lt;span class="gd"&gt;- [replace this box with triple backticks in your code]
&lt;/span&gt;&lt;span class="gi"&gt;+ [replace this box with triple backticks in your code]go
&lt;/span&gt;  type Reader interface {
      Read(p []byte) (n int, err error)
  }
&lt;span class="err"&gt;

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

&lt;/div&gt;

&lt;p&gt;Now your slide will have syntax highlighting.&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%2F74e97ue7dfy32d5scjds.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%2F74e97ue7dfy32d5scjds.png" alt="Slide displaying code, now with Go syntax highlighting"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And if I was giving this talk for real, this would be a slide where speaker notes would really come in handy, since there's several things I'd want to point out about Go's &lt;code&gt;io.Reader&lt;/code&gt; interface.&lt;/p&gt;

&lt;p&gt;Not every speaker uses notes, but if you use speaker notes or want to try them, Marp lets you give any of your slides some notes that only you'll see when you present using HTML-style &lt;code&gt;&amp;lt;!-- --&amp;gt;&lt;/code&gt; comments. I personally find them useful for the flow of my talk since it gives me reminders of concepts I want to bring up, or as timing cues such as to go to the next slide mid-sentence. Here's an example&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;

&amp;lt;!--
The io.Reader interface is a type you'll see all over the Go interface, with just one method. Let's look at that method's signature.
&lt;span class="p"&gt;
*&lt;/span&gt; In the return value n is the number of bytes read to the buffer
&lt;span class="p"&gt;*&lt;/span&gt; err can include EOF for reaching the end of the input
&lt;span class="p"&gt;*&lt;/span&gt; The part I found surprising was we don't return the bytes we read, we copy them to a buffer we pass in. And the reason why is-[CHANGE SLIDE]
--&amp;gt;
&lt;span class="p"&gt;
---


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

&lt;/div&gt;

&lt;p&gt;To use your speaker notes, open talk.html, mouse over the slides, and click the lectern icon at the right of the menu that opens. Now you're in &lt;strong&gt;presenter view&lt;/strong&gt; just like in drag-and-drop tools. So you'll have one desktop window showing the current slide, which you share to the audience, and the other showing your speaker notes, the current slide, and a thumbnail of which slide is next.&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%2Fcfblob2kj48lxde0z1qu.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%2Fcfblob2kj48lxde0z1qu.png" alt="Presenter view, showing your current slide, speaker notes, and next slide"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Using CSS in your slides
&lt;/h2&gt;

&lt;p&gt;The layout for Marp slides does have sensible defaults, but you are able to customize your slide's layout with the full power of CSS, by inserting a &lt;code&gt;&amp;lt;style scoped&amp;gt;&lt;/code&gt; HTML tag into a single slide, or a &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; HTML tag to add CSS rules that apply to all slides.&lt;/p&gt;

&lt;p&gt;First up, on our slide showing the code to Go's &lt;code&gt;io.Reader&lt;/code&gt; interface, while I like having a small amount of information on each slide in order to reduce cogntive load, with so little code on the slide, the code could use a bigger font size to take up more of the screen. Here's how we'd do that:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

---
&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;style &lt;/span&gt;&lt;span class="na"&gt;scoped&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
code {
  font-size: 40px;
}
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

&lt;span class="gu"&gt;## io.Reader in Go: small interface with tons of power&lt;/span&gt;

[replace this line with triple backticks in your code]go
type Reader interface {
    Read(p []byte) (n int, err error)
}
[replace this line with triple backticks in your code]
&lt;span class="p"&gt;
---


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

&lt;/div&gt;

&lt;p&gt;Look at this slide in &lt;code&gt;talk.html&lt;/code&gt;, and you'll see the code now takes up more of the screen.&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%2Fptknpcwowjsepznzplji.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%2Fptknpcwowjsepznzplji.png" alt="Slide with code, now the code takes up more of the screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next up, remember how I mentioned we can have our title slide be a background image with text on it using an image's &lt;code&gt;bg&lt;/code&gt; direcctive, but we'd want to use CSS to ensure our text is legible?&lt;/p&gt;

&lt;p&gt;Here's the CSS we'd add that for a title slide. Notice we're also changing the header back to an h1 since the image is now a background image so we don't need to conserve space with an h3 header.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;style &lt;/span&gt;&lt;span class="na"&gt;scoped&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#FFFFFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bold&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;text-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="m"&gt;5px&lt;/span&gt; &lt;span class="m"&gt;5px&lt;/span&gt; &lt;span class="m"&gt;3px&lt;/span&gt; &lt;span class="m"&gt;#000000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

![bg Picture of the rocks on Singing Beach; rocks are in the foreground and the water that day was bright blue](https://url/to/beach/image)

# What is the io.Reader interface in Go?

YOUR NAME - @YOUR-SOCIAL-MEDIA

---


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

&lt;/div&gt;

&lt;p&gt;The rules make all the text on that slide (a "heading 1" and a paragraph, or &lt;code&gt;h1&lt;/code&gt; and &lt;code&gt;p&lt;/code&gt; in CSS and HTML) white, bold-faced, and with black text-shadow down and to the right. Here's how that looks in &lt;code&gt;talk.html&lt;/code&gt;&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%2F445wr2c769xjpeqxng8r.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%2F445wr2c769xjpeqxng8r.png" alt="Slide with background image; the text is showing in white and in bold, with drop-shadow so the text contrasts with its surroundings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Awesome! As one last thing to look at, let's say we want to ensure the content of your slides doesn't cross into the bottom 20% of the slide. This is a scenario you might see if a conference has live captioning and wants to place the live captions in the bottom 20% of the screen, which GopherCon did.&lt;/p&gt;

&lt;p&gt;When I found that out, I was able to quickly throw in &lt;code&gt;&amp;lt;style scoped&amp;gt;&lt;/code&gt; tags to get all my slides taking up 80% of the screen, but what could have gotten that done faster, was if I had instead used a &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; tag without the &lt;code&gt;scoped&lt;/code&gt; to apply 20% padding to the bottom of all slides!&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
section {
  padding-bottom: 20%;
}
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;&lt;span class="sb"&gt;


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

&lt;/div&gt;

&lt;p&gt;This works because in the HTML that the Marp tool produces, an individual slide is a &lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt; HTML element.&lt;/p&gt;

&lt;p&gt;This does though raise up the content of all existing slides by 20%, so if you apply this to your slide layout after you've already gotten some slides written, you'll still want to look at your existing slides and make sure you don't need to further tweak any individual slides' layouts.&lt;/p&gt;

&lt;p&gt;One other thing, if your page has too much content on it or too big an image, it's still possible for a slide to go past a height cutoff, so one trick I learned at the GopherCon rehearsal (can't remember who told me that but whoever that was thank you!) was to temporarily change the background image of my slides to a 5 x 5 grid, with a red horizontal line at 80% height.&lt;/p&gt;

&lt;p&gt;You can apply that background image to all slides (except slides with their own background image, like our newly upgraded title slide) using &lt;code&gt;backgroundImage&lt;/code&gt; in the frontmatter.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

---
marp: true
theme: uncover
paginate: true
backgroundImage: url('https://url/to/cutoff/image.png')
---


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

&lt;/div&gt;

&lt;p&gt;With that background image, this is what the code slide looks like, well above the 80% mark!&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%2Fgamw3z0q7edry8k5pzek.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%2Fgamw3z0q7edry8k5pzek.png" alt="code slide with cutoff line displayed at 80% below the top"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you were interested in Marp, hopefully this helps get you started writing slides in Marp! I'd also be interested to hear about what other tools you've used for making the process of writing a tech talk more ergonomic, so if you've used any other tools, I'd love to hear about them in the comments!&lt;/p&gt;

</description>
      <category>devrel</category>
      <category>career</category>
      <category>codenewbie</category>
      <category>publicspeaking</category>
    </item>
    <item>
      <title>Using Testify Mock in web clients</title>
      <dc:creator>Andy Haskell</dc:creator>
      <pubDate>Mon, 24 Oct 2022 14:08:12 +0000</pubDate>
      <link>https://dev.to/salesforceeng/using-testify-mock-in-web-clients-5amb</link>
      <guid>https://dev.to/salesforceeng/using-testify-mock-in-web-clients-5amb</guid>
      <description>&lt;p&gt;In the last tutorial, we looked at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How Testify Mock helps us make nondeterministic code testable&lt;/li&gt;
&lt;li&gt;How to implement an interface using an embedded Testify Mock&lt;/li&gt;
&lt;li&gt;What the general flow of a Testify Mock test looks like&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We demonstrated that on random numbers first, since that's the simplest nondeterministic code to be working with.&lt;/p&gt;

&lt;p&gt;However, the use case of Testify Mock that ultimately got me learning about that package, was to use it in code that builds on top of &lt;strong&gt;clients to web APIs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The reason code using web API clients is nondeterministic to test is, you don't have total control over what you get back from a web server for a given input, for reasons such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✍️ The data you get back for a given server endpoint might change, either slightly or dramatically.&lt;/li&gt;
&lt;li&gt;🚧 The server might be down altogether.&lt;/li&gt;
&lt;li&gt;🐆 You might be being rate-limited from sending too many requests to the server.&lt;/li&gt;
&lt;li&gt;🐛 You'll want test coverage so that your code does the right thing if the server you're talking to is giving back 500s. But since a 500 by definition is an internal server error, it's not necessarily possible to &lt;strong&gt;reliably&lt;/strong&gt; get 500s, especially in the long term.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So for tests where you want the same output &lt;strong&gt;every time you run the same API client call in your test&lt;/strong&gt;, that's a great use case for Testify Mock. So for this tutorial, we'll see how Testify Mock can be used as one of your tools to write test coverage when your Go code's got some Internet to do!&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 Setting up a fake API to test against
&lt;/h2&gt;

&lt;p&gt;The code we're going to test uses a client for an API that the zoo set up to give facts about animals.&lt;/p&gt;

&lt;p&gt;The endpoint our code will be talking to is &lt;code&gt;GET /animal-facts?species={species}&amp;amp;page-token={page-token}&lt;/code&gt;, and it returns a JSON object containing a page worth of animal facts, plus a token if there's another page.&lt;/p&gt;

&lt;p&gt;If you're following along, copy the code ahead into a file named something like &lt;code&gt;client.go&lt;/code&gt;. The main takeaway is that we have a &lt;code&gt;ZooHTTPClient&lt;/code&gt; for talking to the zoo's API, and we call the &lt;code&gt;/animal-facts&lt;/code&gt; endpoint with the method &lt;code&gt;ListAnimalFacts()&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ZooHTTPClient&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;baseURL&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Serialization of error response from zoo API service&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ErrorResponse&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;StatusCode&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;    &lt;span class="s"&gt;`json:"status_code"`&lt;/span&gt;
    &lt;span class="n"&gt;Message&lt;/span&gt;    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"message"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ErrorResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"got %d error: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;AnimalFactsQuery&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;AnimalName&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;PageToken&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ZooHTTPClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ListAnimalFacts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="n"&gt;AnimalFactsQuery&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;AnimalFactsResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// HTTP implementation here; returns an&lt;/span&gt;
    &lt;span class="c"&gt;// AnimalFactsResponse if the HTTP request succeeds,&lt;/span&gt;
    &lt;span class="c"&gt;// or an error, of type ErrorResponse, if the request&lt;/span&gt;
    &lt;span class="c"&gt;// gets a non-2xx HTTP status code.&lt;/span&gt;

    &lt;span class="c"&gt;// returning nil, nil just so the code compiles&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;AnimalFactsResponse&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Facts&lt;/span&gt;         &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"facts"`&lt;/span&gt;
    &lt;span class="n"&gt;AreThereMore&lt;/span&gt;  &lt;span class="kt"&gt;bool&lt;/span&gt;     &lt;span class="s"&gt;`json:"are_there_more"`&lt;/span&gt;
    &lt;span class="n"&gt;NextPageToken&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;   &lt;span class="s"&gt;`json:"next_page_token"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here is the code we want to test, which we'll copy to a file like &lt;code&gt;main.go&lt;/code&gt;. In that code we pass the API client into &lt;code&gt;getSlothsFavoriteSnack&lt;/code&gt; so we know what snack to donate a whole bunch of to the zoo. The function returns that snack as a string on success, or if that's not mentioned in any of the facts from the API, then we return &lt;code&gt;errFactNotFound&lt;/code&gt; and dust off that library card in order to find that information.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ NOTE: There is a bug in this code. Don't spend a bunch of time looking for it now, though, we'll fix it when we find that bug using our tests!&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"errors"&lt;/span&gt;
    &lt;span class="s"&gt;"regexp"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;errFactNotFound&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"fact not found"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;favSnackMatcher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;regexp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MustCompile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"favorite snack is (.*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;getSlothsFavoriteSnack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ZooHTTPClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Until we're at the last page of facts, call ListAnimalFacts&lt;/span&gt;
    &lt;span class="c"&gt;// with the current page token to paginate through the list,&lt;/span&gt;
    &lt;span class="c"&gt;// exiting when either the response's AreThereMore field is&lt;/span&gt;
    &lt;span class="c"&gt;// false, or we find out what sloths' favorite snack is.&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pageToken&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListAnimalFacts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AnimalFactsQuery&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;AnimalName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"sloth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;PageToken&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;pageToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c"&gt;// check if any facts match the "favorite snack is"&lt;/span&gt;
        &lt;span class="c"&gt;// regex and if so, return the match&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Facts&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;favSnackMatcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FindStringSubmatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c"&gt;// check the response to see if there are any more&lt;/span&gt;
        &lt;span class="c"&gt;// pages of facts about sloths&lt;/span&gt;
        &lt;span class="n"&gt;pageToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NextPageToken&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// otherwise if the fact about sloths' favorite snack&lt;/span&gt;
    &lt;span class="c"&gt;// isn't in the zoo API, return errFactNotFound.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errFactNotFound&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since &lt;code&gt;ListAnimalFacts&lt;/code&gt; talks to the server for the zoo's API, the code is nondeterministic. So testing it in a repeatable way is a great use case for Testify Mock.&lt;/p&gt;

&lt;h2&gt;
  
  
  🥸 Basic test with mock
&lt;/h2&gt;

&lt;p&gt;If you recall from the last tutorial, the steps to doing a test with Testify Mock are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Take the nondeterministic piece of functionality and wrap it in a Go interface type.&lt;/li&gt;
&lt;li&gt;Write an implementation of the interface that uses Testify Mock.&lt;/li&gt;
&lt;li&gt;In the tests, use the mock implementation to select deterministic results of the functions your interface calls.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So to start, let's make an interface for our API client.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrapping our client in an interface
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ZooClient&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ListAnimalFacts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="n"&gt;AnimalFactsQuery&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;AnimalFactsResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&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;If we had additional client methods used in our code, such as for other endpoints on the API, we would also add those methods to the &lt;code&gt;ZooClient&lt;/code&gt; type as well, but for this tutorial we're only testing code that uses &lt;code&gt;ListAnimalFacts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, to enable using a mock in &lt;code&gt;getSlothsFavoriteSnack&lt;/code&gt;, we change that function's signature to take in a ZooClient rather than a *ZooHTTPClient.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- func getSlothsFavoriteSnack(c *ZooHTTPClient) (string, error) {
&lt;/span&gt;&lt;span class="gi"&gt;+ func getSlothsFavoriteSnack(c ZooClient) (string, error) {
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Writing a mock implementation of our client
&lt;/h3&gt;

&lt;p&gt;And now just like with the random number generator in the last tutorial, we can use the &lt;code&gt;mock.Mock&lt;/code&gt; type to write a mock implementation of our client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/stretchr/testify/mock"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;mockClient&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mock&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;newMockClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mockClient&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;mockClient&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mockClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ListAnimalFacts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="n"&gt;AnimalFactsQuery&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="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;AnimalFactsResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Called&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;AnimalFactsResponse&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&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;Just like in the last tutorial, we start by making a mock client that embeds a &lt;code&gt;mock.Mock&lt;/code&gt; object, and we retrieve the return values we assigned to the passed-in parameters using &lt;code&gt;Mock.Called&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Unlike in the random number generator example, though, the object we're returning is an &lt;code&gt;*AnimalFactsResponse&lt;/code&gt; rather than a primitive Go type like an int. So to get our response as the type we want, we call &lt;code&gt;args.Get(0)&lt;/code&gt; which returns an &lt;code&gt;interface{}/any&lt;/code&gt; that we then can convert to the type we want with &lt;code&gt;.(*AnimalFactsResponse)&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using our client in a test
&lt;/h3&gt;

&lt;p&gt;Now, let's use our client in a test!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"testing"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;firstPageAPIReq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AnimalFactsQuery&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;AnimalName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"sloth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;PageToken&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestGetSlothsFavoriteSnack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;newMockClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;On&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"ListAnimalFacts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;firstPageAPIReq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;AnimalFactsResponse&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Facts&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"Sloths' slowness is actually used as a form of camouflage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"Baby sloths make the cutest li'l squeak 🥰"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"Sloths' favorite snack is hibiscus flowers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;AreThereMore&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;NextPageToken&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;favSnack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;getSlothsFavoriteSnack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"got error getting sloths' favorite snack: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;favSnack&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;"hibiscus flowers"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"expected favorite snack to be hibiscus flowers, got %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;favSnack&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, we pass in the AnimalFactsQuery we're going to use to &lt;code&gt;c.On()&lt;/code&gt; and assign it a mock API response with &lt;code&gt;c.Return()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now our mock client is ready to use; we call &lt;code&gt;getSlothsFavoriteSnack&lt;/code&gt;, and it uses our mock client; when it calls &lt;code&gt;ZooClient.ListAnimalFacts&lt;/code&gt;, it gets back our API response, loops through the &lt;code&gt;Facts&lt;/code&gt; in the API response, and when it reaches the one titled &lt;em&gt;Sloths' favorite snack is hibiscus flowers&lt;/em&gt;, that matches the regular expression, so getSlothsFavoriteSnack returns &lt;code&gt;"hibiscus flowers", nil&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, back in our test, we verify that &lt;code&gt;favSnack&lt;/code&gt; is hibiscus flowers and &lt;code&gt;err&lt;/code&gt; is nil, just like we would if this test was using a client pointed at and authenticated to a real zoo API.&lt;/p&gt;

&lt;p&gt;Run the test, and you'll see that it passed and that sloths love hibiscus flowers! 🌺 &lt;/p&gt;

&lt;p&gt;Just like that, we've got a Go test on &lt;strong&gt;what happens when our code gets back a certain response from an API&lt;/strong&gt;, and we can run it any time we want with the same result from our mock API; if the zoo's real API server is down, then this test will still run successfully since we're not talking to the real API!&lt;/p&gt;

&lt;p&gt;Speaking of when the server is down, we don't want to test &lt;em&gt;just&lt;/em&gt; the happy path; we should have some test coverage for what happens if we get an error calling &lt;code&gt;getSlothsFavoriteSnack&lt;/code&gt; too.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⛔️ Handling error cases
&lt;/h2&gt;

&lt;p&gt;There's a couple error cases from the API we should have test coverage for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The server is giving back 500's, which as I mentioned at the beginning of this post, is hard to re-create with a real API.&lt;/li&gt;
&lt;li&gt;The API doesn't have the animal fact we want.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Testing that our code handles internal server errors correctly
&lt;/h3&gt;

&lt;p&gt;Let's start with testing the 500 internal server error case.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestGetSlothsFavoriteSnack500Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;newMockClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;On&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ListAnimalFacts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;firstPageAPIReq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;AnimalFactsResponse&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ErrorResponse&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;StatusCode&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"server 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="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;getSlothsFavoriteSnack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"got nil error from getSlothsFavoriteSnack"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;errRes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ErrorResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"expected error to be ErrorResponse, got %T"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;errRes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"expected 500, got %d status code"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&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;Like before, we set up a mock response for &lt;code&gt;firstPageAPIReq&lt;/code&gt; in &lt;code&gt;c.On().Return()&lt;/code&gt;. But this time, rather than passing in a successful response, we pass in a nil &lt;code&gt;AnimalFactsResponse&lt;/code&gt; and an &lt;code&gt;ErrorResponse&lt;/code&gt; as our error.&lt;/p&gt;

&lt;p&gt;Then, we call &lt;code&gt;getSlothsFavoriteSnack&lt;/code&gt; and validate that we got an error, it's of type &lt;code&gt;ErrorResponse&lt;/code&gt;, and that its status code is 500. So when we run the test, once again it passes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing the error case where the API doesn't have the sloth fact we want
&lt;/h3&gt;

&lt;p&gt;Now that we've got a test for our 500 error, let's test the case where we don't have the sloth fact we want. In that case we expect that &lt;code&gt;getSlothsFavoriteSnack&lt;/code&gt; returns &lt;code&gt;errFactNotFound&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestGetSlothsFavoriteSnackNotFound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;newMockClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;On&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"ListAnimalFacts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;firstPageAPIReq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;AnimalFactsResponse&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Facts&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"Sloths' slowness is actually used as a form of camouflage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"Baby sloths make the cutest li'l squeak 🥰"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"Sloths need their beauty sleep, plz send noise-cancelling headphones"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;AreThereMore&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;NextPageToken&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;getSlothsFavoriteSnack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;errFactNotFound&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"should have gotten errFactNotFound, got %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&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;We start with a similar test setup to the success case, except this time around, the response we set up doesn't include information about what sloths like to eat. So at the bottom of the test, we assert that the error we get back is &lt;code&gt;errFactNotFound&lt;/code&gt; and that we should head to the library.&lt;/p&gt;

&lt;p&gt;Run this test though, and you should get an infinite loop; if you wait about 10 minutes the test will fail because &lt;code&gt;getSlothsFavoriteSnack&lt;/code&gt; never returns, so the test times out.&lt;/p&gt;

&lt;p&gt;In other words, we found a bug in &lt;code&gt;getSlothsFavoriteSnack&lt;/code&gt;. If you recall, this was the for loop in there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListAnimalFacts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AnimalFactQuery&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;AnimalName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"sloth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;PageToken&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;pageToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Facts&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;favSnackMatcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FindStringSubmatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;pageToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NextPageToken&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use a for loop because this API is paginated so that if there's more than one page worth of sloth facts, we can check the next page. The bug is that we never &lt;code&gt;break&lt;/code&gt; out of the for loop if we're at the end of the list of sloth facts, as specified by the &lt;code&gt;AreThereMore&lt;/code&gt; field on the response. If you've tricked out your editor, that might have told you that the line returning &lt;code&gt;errFactNotFound&lt;/code&gt; was unreachable, and that's why.&lt;/p&gt;

&lt;p&gt;So let's fix the bug!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;    for _, f := range res.Facts {
        match := favSnackMatcher.FindStringSubmatch(f)
        if len(match) &amp;lt; 2 {
            continue
        }
        return match[1], nil
    }

    pageToken = res.NextPageToken
&lt;span class="gi"&gt;+   if !res.AreThereMore {
+       break 
+   }
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the test again and now our test should pass!&lt;/p&gt;

&lt;h2&gt;
  
  
  📖 Pagination with MatchedBy, Once, and AssertNumberOfCalls
&lt;/h2&gt;

&lt;p&gt;As one last thing to test, since the API is paginated, we also should have some test coverage for when the information about sloths' favorite snack isn't on page 1.&lt;/p&gt;

&lt;p&gt;In this API we're mocking, requests and responses include a &lt;code&gt;PageToken/NextPageToken&lt;/code&gt; field, to tell the API which page of sloth facts to retrieve. So a test for the scenario where the search results are on the second page might look like this pseudocode:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add a mock for page 1, where the AnimalName is "sloth" and PageToken is a blank string.

&lt;ol&gt;
&lt;li&gt;Have that mock API call return our search results, &lt;code&gt;AreThereMore=true&lt;/code&gt;, and &lt;code&gt;NextPageToken=NEXT&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;Add a mock for page 2, where AnimalName is "sloth" and PageToken is "NEXT".

&lt;ol&gt;
&lt;li&gt;Have that mock API call return a second page of search results; &lt;code&gt;AreThereMore=false&lt;/code&gt; and page 2 contains the information that sloths love hibiscus flowers.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;getSlothsFavoriteSnack&lt;/code&gt; and check that "hibiscus flowers" is still retrieved.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We could pass each individual query into &lt;code&gt;Mock.On()&lt;/code&gt;, and that wouldn't be too difficult to write in this example code. However, if this API was more complicated and we were testing more-complicated fields, it can be a pain to ensure that each call to &lt;code&gt;Mock.On&lt;/code&gt; has &lt;em&gt;exactly&lt;/em&gt; the right fields on the structs we're passing in. In particular, you might have a more complicated function than &lt;code&gt;getSlothsFavoriteSnack&lt;/code&gt; you want to test, where it takes a lot of staring at your code in order to figure out the exact arguments each individual API call has.&lt;/p&gt;

&lt;p&gt;In this test we're running, we're not that worried about the exact content of the &lt;code&gt;PageToken&lt;/code&gt; field, since API page tokens tend to be pretty opaque. Whether the page token says something like "page 2", "some more facts on the next page", or a UUID. Essentially, we're not the ones who care about the page token's formst; the zoo's API team is in charge of that!&lt;/p&gt;

&lt;p&gt;What we're really testing in a &lt;code&gt;TestGetSlothsFavoriteSnackResultIsOnTheSecondPage&lt;/code&gt; (that's a mouthful!) test is that &lt;strong&gt;if the information we want is on the second page, we're still able to retrieve it with another query for sloth facts&lt;/strong&gt;. And there's a handful of functions that can help us test that, to a reasonable "just the important stuff" level of detail, which are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#MatchedBy"&gt;MatchedBy&lt;/a&gt;; instead of passing in an argument to &lt;code&gt;Mock.On()&lt;/code&gt; that the argument in the test has to &lt;em&gt;exactly match&lt;/em&gt;, you pass in a function that defines the criteria for whether an argument in the test matches the argument to &lt;code&gt;Mock.On()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#Call.Once"&gt;Once&lt;/a&gt;; specify arguments and return values with &lt;code&gt;Mock.On().Return()&lt;/code&gt; that are only to be called and given back once. For example in a paginated API, the arguments you call in each round of the loop are nearly the same, so you can add &lt;code&gt;Once()&lt;/code&gt; on to your mock call to say "give us back each page of results only once".&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#Mock.AssertNumberOfCalls"&gt;AssertNumberOfCalls&lt;/a&gt;; if the mocked-out code you're testing is called in a loop, this allows us to check that the loop ran the expected number of times.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To try these out, let's give some test coverage where sloths' favorite snack is on page 2.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;reqSlothFacts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="n"&gt;AnimalFactsQuery&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToLower&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AnimalName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"sloth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"lemur: caffeine-free edition"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"descendants of the giants who made today's avocados happen"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;page1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AnimalFactsResponse&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Facts&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"Sloths' slowness is actually used as a form of camouflage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"Baby sloths make the cutest li'l squeak 🥰"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"Sloths need their beauty sleep, plz send noise-cancelling headphones"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;AreThereMore&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;NextPageToken&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"some more facts on the next page"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;page2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AnimalFactsResponse&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Facts&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"Sloths' favorite snack is hibiscus flowers"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestGetSlothsFavoriteSnackOnPage2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;newMockClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;On&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ListAnimalFacts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MatchedBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reqSlothFacts&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
        &lt;span class="n"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;page1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
        &lt;span class="n"&gt;Once&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;On&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ListAnimalFacts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MatchedBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reqSlothFacts&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
        &lt;span class="n"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;page2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
        &lt;span class="n"&gt;Once&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;favSnack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;getSlothsFavoriteSnack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"got error getting sloths' favorite snack: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;favSnack&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;"hibiscus flowers"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"expected favorite snack to be hibiscus flowers, got %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;favSnack&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="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AssertNumberOfCalls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ListAnimalFacts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&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;Here's what happens in our test:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Outside of our test, we define the function &lt;code&gt;reqSlothFacts&lt;/code&gt; we'll pass into &lt;code&gt;MatchedBy&lt;/code&gt;. We match the word "sloth", as well as a couple other ways to describe a sloth just for fun: "lemur: caffeine-free edition" and "descendants of the giants who made today's avocados happen" (&lt;a href="https://en.wikipedia.org/wiki/Megatherium"&gt;giant ground sloths&lt;/a&gt; 10,000 years ago ate what avocados looked like 10,000 years ago, so next time you have some guac, thank a sloth). We also define two pages of search results.&lt;/li&gt;
&lt;li&gt;Inside our &lt;code&gt;TestGetSlothsFavoriteSnackOnPage2&lt;/code&gt;, we define two calls to &lt;code&gt;ListAnimalFacts&lt;/code&gt; similar to before, but this time instead of passing in an exact query, we pass in &lt;code&gt;mock.MatchedBy(reqSlothFacts)&lt;/code&gt; to say &lt;strong&gt;"a call to ListAnimalFacts matches this call to &lt;code&gt;Mock.On()&lt;/code&gt; if its argument, passed into &lt;code&gt;reqSlothFacts&lt;/code&gt;, returns true"&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;On each call to &lt;code&gt;Mock.On()&lt;/code&gt;, we add on a call to &lt;code&gt;.Once()&lt;/code&gt;. When we call &lt;code&gt;getSlothsFavoriteSnack&lt;/code&gt;, the first time we get back the results we defined with &lt;code&gt;page1&lt;/code&gt; and the second time we get back the results we defined with &lt;code&gt;page2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Then we run the test the same way as before, but at the tail end, we run &lt;code&gt;AssertNumberOfCalls&lt;/code&gt; to show that we really did call &lt;code&gt;ListAnimalFacts&lt;/code&gt; twice, rather than getting the results on the first page.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By the way, in addition to &lt;code&gt;MatchedBy&lt;/code&gt;, if you don't need such fine-grained control over the arguments you pass in, there also is &lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#pkg-constants"&gt;mock.Anything&lt;/a&gt; that you can pass into &lt;code&gt;Mock.On&lt;/code&gt; to match any argument at all.&lt;/p&gt;

&lt;p&gt;For example, a lot of API clients these days take in a &lt;code&gt;context.Context&lt;/code&gt;, which is often in charge of things like traces with observability tools or giving a request a deadline to finish with &lt;code&gt;context.WithDeadline&lt;/code&gt;. But often that does not affect the headers and body of our request or response. So if the context isn't a focal point of what you're testing, you can mock it out with &lt;code&gt;Anything&lt;/code&gt;. For example if our client's interface looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ZooClient&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ListAnimalFacts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="n"&gt;AnimalFactsQuery&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="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;AnimalFactsResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&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;You would do your &lt;code&gt;Mock.On&lt;/code&gt; call like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  c := newMockClient()
  c.On(
      "ListAnimalFacts",
&lt;span class="gi"&gt;+     mock.Anything,
&lt;/span&gt;      firstPageAPIReq,
  ).Return(&amp;amp;AnimalFactsResponse{
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🧰 Testify Mock is just one tool for testing your web apps
&lt;/h2&gt;

&lt;p&gt;As you can see, Testify Mock is a convenient tool for testing code that needs to make an API call, particularly when it comes to HTTP responses like 500 errors that you're not suppposed to consistently be getting.&lt;/p&gt;

&lt;p&gt;But there's another way we could have tested all these API interactions without having to rely on the real API:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Make an &lt;code&gt;httptest.Server&lt;/code&gt; that has HTTP handlers to mimic the API endpoints we're testing, deserializing requests and serializing responses&lt;/li&gt;
&lt;li&gt;Point the &lt;em&gt;HTTP&lt;/em&gt; implementation of the API client at that server and run tests using that implementation&lt;/li&gt;
&lt;li&gt;Do assertions on the mock responses you get back&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both the httptest approach and Testify Mock approach are valid ways to test the code. Furthermore, while both kinds of mocks are useful themselves, that's not to say testing against the real API isn't itself beneficial. By testing against the very same servers your code talks to in production, you can sniff out server behaviors your dev team wasn't aware of from just reading the server's API documentation. While this isn't a hard and fast rule, my personal style for when to use which kind of Go test is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When I'm the one implementing the client to the API I'm working with, I would go with the &lt;strong&gt;httptest Server&lt;/strong&gt; approach for its unit tests. Part of the client's job is to serialize and deserialize Go types, so the thing being tested, so the focal point of the test is that &lt;strong&gt;the headers, request, and response bodies are correct&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;For code that's built on top of a client, such as &lt;code&gt;getSlothsFavoriteSnack&lt;/code&gt;, my go-to is Testify Mock. Either I wrote and unit-tested the HTTP implementation of the client or the open source developer I'm &lt;code&gt;go getting&lt;/code&gt; the client from did. So now the focal point of a test is the question &lt;strong&gt;"given that the API client works as expected, does my code do the right thing with the response it gets back"&lt;/strong&gt;?

&lt;ul&gt;
&lt;li&gt;However if you got the client as a dependency but it doesn't have test coverage for the API calls you're making, it might still be a good idea to test using the &lt;code&gt;httptest.Server&lt;/code&gt; approach if its implementation allows you to point it at a custom httptest Server URL.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Finally, for testing that your app works end-to-end, having your continuous integration platform run a &lt;strong&gt;nightly build&lt;/strong&gt; that runs tests against the real API will help you detect bugs and unexpected behaviors your mocks might not have taken into account.

&lt;ul&gt;
&lt;li&gt;⚠️WARNING⚠️: Chances are, the server you're talking to in this nightly build will need to obtain and use some kind of API key or authentication token. BE CAREFUL configuring your continuous integration so that that authentication doesn't get stolen. In particular, do not put the key/token directly in your code.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy testing!&lt;/p&gt;

</description>
      <category>go</category>
      <category>testing</category>
      <category>webdev</category>
      <category>codenewbie</category>
    </item>
    <item>
      <title>Mocks in Go tests with Testify Mock</title>
      <dc:creator>Andy Haskell</dc:creator>
      <pubDate>Mon, 24 Oct 2022 14:07:47 +0000</pubDate>
      <link>https://dev.to/salesforceeng/mocks-in-go-tests-with-testify-mock-6pd</link>
      <guid>https://dev.to/salesforceeng/mocks-in-go-tests-with-testify-mock-6pd</guid>
      <description>&lt;p&gt;In parts 1-3 of this tutorial series, we saw how you can use Go to write automated tests. Go's testing is very conducive to giving test coverage to a lot of your codebase's functionality. However, there's one area in particular where it's harder to do automated tests: code that is &lt;strong&gt;nondeterministic&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When I say nondeterministic code, I am talking about code where &lt;strong&gt;you don't have total control&lt;/strong&gt; over the code's logic and output. This can be things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🧮 Code that uses pseudorandom number generators, like &lt;code&gt;math/rand&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;💻 Web API calls and their response payloads, or errors&lt;/li&gt;
&lt;li&gt;⏰ The current time returned by &lt;code&gt;time.Now&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Luckily, one tool that helps with testing nondeterministic code, is the &lt;code&gt;mock&lt;/code&gt; package of the popular &lt;a href="//github.com/stretchr/testify"&gt;Testify testing framework&lt;/a&gt;, which you can use for mocking out these API calls.&lt;/p&gt;

&lt;p&gt;For this tutorial, we'll look at how to mock out code that uses &lt;code&gt;math/rand&lt;/code&gt;, then in a follow-up post, we'll mock out a fake web API client to see how to use Testify Mock in more complex scenarios.&lt;/p&gt;

&lt;p&gt;Prerequisites for this tutorial are familiarity with the basics of writing and running a Go test, which the &lt;a href="https://dev.to/salesforceeng/intro-to-automated-testing-in-go-4mjl"&gt;first tutorial&lt;/a&gt; in this series covers.&lt;/p&gt;

&lt;h2&gt;
  
  
  🎰 Getting some nondeterministic code and the Testify Mock package
&lt;/h2&gt;

&lt;p&gt;Probably the easiest nondeterministic code to get ahold of is the &lt;code&gt;math/rand&lt;/code&gt; package, so for this tutorial, we'll look at how we would use Testify Mock to test code that uses randomness. We'll make a function that takes in an integer, and integer-divides (no decimal point) it by a number between 1 and 10.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"math/rand"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;divByRand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numerator&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;numerator&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&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;Pretty simple function, but since we called &lt;code&gt;rand.Intn&lt;/code&gt;, which takes in a maximum value and returns a random integer up to that maximum, &lt;code&gt;divByRand&lt;/code&gt; as a whole is nondeterministic; we have control over the numerator, but not the denominator.&lt;/p&gt;

&lt;p&gt;But that's where Testify Mock package comes in; we can make it so in a given test, we &lt;em&gt;do&lt;/em&gt; get back the same value for &lt;code&gt;rand.Intn&lt;/code&gt; every time.&lt;/p&gt;

&lt;p&gt;First let's install Testify Mock with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go get github.com/stretchr/testify/mock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we're ready to use Testify Mock to give &lt;code&gt;divByRand&lt;/code&gt; some test coverage!&lt;/p&gt;

&lt;h2&gt;
  
  
  ✨ Using Testify Mock
&lt;/h2&gt;

&lt;p&gt;Now that we've got our nondeterministic code, here's the steps to making it testable with Testify Mock:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Take the nondeterministic piece of functionality and wrap it in a Go interface type.&lt;/li&gt;
&lt;li&gt;Write an implementation of the interface that uses Testify Mock.&lt;/li&gt;
&lt;li&gt;In the tests, use the mock implementation to select deterministic results of the functions your interface calls.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Besides injecting your mock into your code, the test is otherwise written like any other Go test.&lt;/p&gt;

&lt;p&gt;Let's try it out on &lt;code&gt;divByRand&lt;/code&gt;, step by step!&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Take the nondeterministic function calls and wrap them in an interface
&lt;/h3&gt;

&lt;p&gt;For &lt;code&gt;divByRand&lt;/code&gt;, the nondeterministic code we're working with is &lt;code&gt;math/rand&lt;/code&gt;'s &lt;code&gt;Intn&lt;/code&gt; function, which takes in an integer and returns another integer. Here's what wrapping that method in an interface looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;randNumberGenerator&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;randomInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we've got our interface, here's the plain implementation that calls the standard library's &lt;code&gt;rand.Intn&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// our standard-library implementation is an empty&lt;/span&gt;
&lt;span class="c"&gt;// struct whose randomInt method calls math/rand.Intn&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;standardRand&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;standardRand&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;randomInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max&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;Now that we've got one interface implementation, we can use that in our &lt;code&gt;divByRand&lt;/code&gt; function like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  func divByRand(
      numerator int,
&lt;span class="gi"&gt;+     r randNumberGenerator,
&lt;/span&gt;  ) int {
&lt;span class="gd"&gt;-     return numerator / rand.Intn(10) 
&lt;/span&gt;&lt;span class="gi"&gt;+     return numerator / r.randomInt(10)
&lt;/span&gt;  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We now would call divByRandom in our production code using a function call like &lt;code&gt;divByRandom(200, standardRand{})&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In tests, though, we will instead use a mock implementation of our &lt;code&gt;randNumberGenerator&lt;/code&gt; interface, which we'll write in the next section.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Write an implementation of the interface that uses Testify Mock
&lt;/h3&gt;

&lt;p&gt;The Testify Mock package's main type is &lt;code&gt;Mock&lt;/code&gt;, which handles the logic for mock API calls, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For each method being mocked, keeping track of how many times it was called, and with what arguments.&lt;/li&gt;
&lt;li&gt;Providing the coder with a way to specify return values to get back from the mock implementation when specified arguments are passed into given function calls.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We would first set up our mock implementation by embedding a Mock into a struct:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;mockRand&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mock&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;newMockRand&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mockRand&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;mockRand&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;By embedding a &lt;code&gt;Mock&lt;/code&gt;, now the &lt;code&gt;mockRand&lt;/code&gt; type has the methods for registering an API call that you expect to happen in the tests.&lt;/p&gt;

&lt;p&gt;For example, at the beginning of a test that uses the &lt;code&gt;randomNumberGenerator&lt;/code&gt; interface, we could call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="n"&gt;mockRand&lt;/span&gt;
&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;On&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"randomInt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which says "if the number 10 is passed in as the maximum number for this &lt;code&gt;mockRand&lt;/code&gt;'s &lt;code&gt;randomInt&lt;/code&gt; method, then always return the number 6".&lt;/p&gt;

&lt;p&gt;In order to be able to use &lt;code&gt;m.On("randomInt", arg)&lt;/code&gt; however, we will need to actually give our &lt;code&gt;mockRand&lt;/code&gt; a &lt;code&gt;randomInt&lt;/code&gt; method. Here's how we would do that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mockRand&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;randomInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Called&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&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;We've got two lines of code, let's take a look at what they do. If it seems confusing at first, no worries; it will make more sense when we are actually using this code in a test.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the first line when &lt;code&gt;randomInt&lt;/code&gt; is called, we call &lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#Mock.Called"&gt;Mock.Called&lt;/a&gt; to record that it was called with the value passed in for &lt;code&gt;max&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Additionally, &lt;code&gt;m.Called&lt;/code&gt; returns an &lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#Arguments"&gt;Arguments&lt;/a&gt; object, which contains the return value(s) that we specified in the test to be returned if the function gets the given value of &lt;code&gt;max&lt;/code&gt;. For example, if we called &lt;code&gt;m.On("randomInt", 20).Return(7)&lt;/code&gt; in the test, &lt;code&gt;m.Called(20)&lt;/code&gt; would return an &lt;code&gt;Arguments&lt;/code&gt; object holding the return value 7.&lt;/li&gt;
&lt;li&gt;Finally, to retrieve the return value, in the second line we call &lt;code&gt;args.Int(0)&lt;/code&gt;, which means "return the zeroeth return value, and it will be of type int".&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Note that in addition to &lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#Arguments.Int"&gt;Arguments.Int&lt;/a&gt;, there's also &lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#Arguments.Bool"&gt;Bool&lt;/a&gt;, &lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#Arguments.String"&gt;String&lt;/a&gt;, and &lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#Arguments.Error"&gt;Error&lt;/a&gt; methods, which give us back the n-th return value in those types. And if you have a return value of another type, you would retrieve it with the &lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#Arguments.Bool"&gt;Arguments.Get&lt;/a&gt; method, which returns an &lt;code&gt;interface{}&lt;/code&gt; you would then convert to the type you expect to get back.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. In the tests, use the mock implementation and feed in results the function returns.
&lt;/h3&gt;

&lt;p&gt;We've got our &lt;code&gt;mockRand&lt;/code&gt; type implementing the &lt;code&gt;randomNumberGenerator&lt;/code&gt; interface, so it can be passed into &lt;code&gt;divByRand&lt;/code&gt; in Go code, including in our tests. The steps of our test now are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create an instance of your mock interface implementation.&lt;/li&gt;
&lt;li&gt;Specify what results you want back when the mock's methods are called with a given set of arguments using the &lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#Mock.On"&gt;On&lt;/a&gt; and &lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#Call.Return"&gt;Return&lt;/a&gt; methods.&lt;/li&gt;
&lt;li&gt;Run the code that's being tested, the standard way you would in a Go test.&lt;/li&gt;
&lt;li&gt;Optionally, use methods like &lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#Mock.AssertCalled"&gt;Mock.AssertCalled&lt;/a&gt; to check that a given method indeed had been called during the test.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's what that looks like in code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"testing"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestDivByRand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// get our mockRand&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;newMockRand&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c"&gt;// specify our return value. Since the code in divByRand&lt;/span&gt;
    &lt;span class="c"&gt;// passes 10 into randomInt, we pass 10 in as the argument&lt;/span&gt;
    &lt;span class="c"&gt;// to go with randomInt, and specify that we want the&lt;/span&gt;
    &lt;span class="c"&gt;// method to return 6.&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;On&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"randomInt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// now run divByRand and assert that we got back the&lt;/span&gt;
    &lt;span class="c"&gt;// return value we expected, just like in a Go test that&lt;/span&gt;
    &lt;span class="c"&gt;// doesn't use Testify Mock.&lt;/span&gt;
    &lt;span class="n"&gt;quotient&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;divByRand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;quotient&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"expected quotient to be 5, got %d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quotient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// check that randomInt was called with the number 10;&lt;/span&gt;
    &lt;span class="c"&gt;// if not then the test fails&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AssertCalled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"randomInt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;10&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;Run &lt;code&gt;go test -v&lt;/code&gt; and you'll get a passing test. But there's a bug in the original implementation of &lt;code&gt;divByRand&lt;/code&gt;, so let's find it and give that bug some test coverage!&lt;/p&gt;

&lt;h2&gt;
  
  
  🐛 Finding and fixing a bug using Testify Mock
&lt;/h2&gt;

&lt;p&gt;We wrote a test that utilizes Testify Mock, so now let's try using it to find a bug!&lt;/p&gt;

&lt;p&gt;Since we're dividing by a nondeterministic value, we should have test coverage to make sure we can't accidentally divide by zero.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestDivByRandCantDivideByZero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;newMockRand&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;On&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"randomInt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;quotient&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;divByRand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;quotient&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"expected quotient to be 30, got %d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quotient&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;This time around, when we pass 10 into our mockRand's randomInt method, we return 0. So in divByRand, we end up dividing by 0.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;go test -v&lt;/code&gt; and you should get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--- FAIL: TestDivByRandCantDivideByZero (0.00s)
panic: runtime error: integer divide by zero [recovered]
    panic: runtime error: integer divide by zero
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A panic from dividing by zero. Let's fix &lt;code&gt;divByRand&lt;/code&gt; method to prevent this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  func divByRand(n int, r randNumberGenerator) int {
&lt;span class="gd"&gt;-     return n / r.randomInt(10)
&lt;/span&gt;&lt;span class="gi"&gt;+     denominator := 1 + int(r.randomInt(10))
+     return n / denominator
&lt;/span&gt;  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we're passing 9 instead of 10 into our call to &lt;code&gt;randomInt&lt;/code&gt;, we do need to update our test coverage to register a call to &lt;code&gt;randomInt(9)&lt;/code&gt; instead of &lt;code&gt;randomInt(10)&lt;/code&gt;, and for TestDivByRand, we need to return 5 instead of 6 since in divByRand we add 1 to the returned value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  func TestDivByRand(t *testing.T) {
      var m mockRand
&lt;span class="gd"&gt;-     m.On("randomInt", 10).Return(6)
&lt;/span&gt;&lt;span class="gi"&gt;+     m.On("randomInt", 10).Return(5)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;go test -v&lt;/code&gt; one more time and you should get...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=== RUN   TestDivByRand
--- PASS: TestDivByRand (0.00s)
=== RUN   TestDivByRandCantDivideByZero
--- PASS: TestDivByRandCantDivideByZero (0.00s)
PASS
ok      github.com/andyhaskell/testify-mock 0.114s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Passing tests!&lt;/p&gt;

&lt;p&gt;We've looked at how to use Testify Mock to write test coverage for randomness. In the next tutorial, we'll take a look at using Testify Mock to mock out a web API call.&lt;/p&gt;

</description>
      <category>go</category>
      <category>testing</category>
      <category>webdev</category>
      <category>codenewbie</category>
    </item>
    <item>
      <title>Processing user input in Bubble Tea with a menu component</title>
      <dc:creator>Andy Haskell</dc:creator>
      <pubDate>Sun, 23 Oct 2022 21:25:24 +0000</pubDate>
      <link>https://dev.to/andyhaskell/processing-user-input-in-bubble-tea-with-a-menu-component-222i</link>
      <guid>https://dev.to/andyhaskell/processing-user-input-in-bubble-tea-with-a-menu-component-222i</guid>
      <description>&lt;p&gt;In the last tutorial, we did a "hello world" app, and it processed just a bit of user input ("press Ctrl+C to exit").&lt;/p&gt;

&lt;p&gt;But we didn't really get a feel for actually using user input to change the model's data, and in turn change what we see in the app. So in this tutorial, we're going to create a menu component that lets us move between buttons.&lt;/p&gt;

&lt;h2&gt;
  
  
  📝 Defining our data
&lt;/h2&gt;

&lt;p&gt;The first thing we need for any Bubble Tea component is the data our model is in charge of. If you recall, in our simplePage model, the data was just the text we were displaying:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;simplePage&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;In our menu, what we need to do is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Display our options&lt;/li&gt;
&lt;li&gt;Show which option is selected&lt;/li&gt;
&lt;li&gt;Additionally, let the user press the enter to go to another page. But we'll add that in a later tutorial.

&lt;ul&gt;
&lt;li&gt;For now, we can still make an onPress function passed in that tells us what we do if the user presses enter.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;So our model's data will look like this; if you're following along, write this in a file named &lt;code&gt;menu.go&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;menu&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;       &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;menuItem&lt;/span&gt;
    &lt;span class="n"&gt;selectedIndex&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;menuItem&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt;    &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;onPress&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Msg&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;A menu is made up of menuItems, and each menuItem has text and a function handling pressing enter. In this tutorial we'll just have the app toggle between all-caps and all-lowercase so it's at least doing something.&lt;/p&gt;

&lt;p&gt;It returns a &lt;code&gt;tea.Msg&lt;/code&gt; because that's we're able to change the data in response to this user input. We'll see why in the next section, when we're implementing the &lt;code&gt;Model&lt;/code&gt; interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧋 Implementing the Model interface
&lt;/h2&gt;

&lt;p&gt;If you recall, for us to use our model as a UI component, it needs to implement this interface:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Model&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt;
    &lt;span class="n"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="n"&gt;Msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;View&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;First let's write the Init function.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="n"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cmd&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Again, we still don't have any initial &lt;code&gt;Cmd&lt;/code&gt; we need to run, so we can just return &lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For the &lt;code&gt;View&lt;/code&gt; function, let's make an old-school menu with an arrow to tell us which item is currently selected.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="n"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;View&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;selectedIndex&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"-&amp;gt; %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"   %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`%s

Press enter/return to select a list item, arrow keys to move, or Ctrl+C to exit.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&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;As mentioned in the last tutorial, one of the things that makes Bubble Tea really learnable is that the display for your UI is basically one big string. So in &lt;code&gt;menu.View&lt;/code&gt; we make a slice of strings where the selected option has an arrow and the non-selected options have leading spaces. Then we join them all together and add our contols to the bottom.&lt;/p&gt;

&lt;p&gt;Finally, let's write our Update method to handle user input.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="n"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cmd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KeyMsg&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KeyMsg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"ctrl+c"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Quit&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"down"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"right"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"up"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"left"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;moveCursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KeyMsg&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="n"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;moveCursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KeyMsg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;menu&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"up"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"left"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;selectedIndex&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"down"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"right"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;selectedIndex&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="c"&gt;// do nothing&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;optCount&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;selectedIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;selectedIndex&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;optCount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;optCount&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;Update&lt;/code&gt; method is the most complex part of this app, so let's break that down.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"ctrl+c"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Quit&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Like before, we're handling the &lt;code&gt;KeyMsg&lt;/code&gt; type, and we're the Ctrl+C keypress to quit the app by returning the Quit cmd.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"down"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"right"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"up"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"left"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;moveCursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KeyMsg&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;For the arrow keys, though, we use a helper function, &lt;code&gt;moveCursor&lt;/code&gt;, which returns an updated model.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="n"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;moveCursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KeyMsg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;menu&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"up"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"left"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;selectedIndex&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"down"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"right"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;selectedIndex&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="c"&gt;// do nothing&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;optCount&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;selectedIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;selectedIndex&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;optCount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;optCount&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The up and left KeyMsg strings serve as our "navigate up" keys, and the down and right ones navigate us down, decrementing and incrementing &lt;code&gt;m.selected&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then, we use the mod operator to ensure that &lt;code&gt;m.selected&lt;/code&gt; is one of the indices of our options.&lt;/p&gt;

&lt;p&gt;Finally, with the model updated, &lt;code&gt;moveCursor&lt;/code&gt; returns the model that in turn is returned by &lt;code&gt;Update&lt;/code&gt;, and the new model ultimately gets processed by our &lt;code&gt;View&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Before we move on to processing the enter key though, we should see our app run. So let's put our new &lt;code&gt;menu&lt;/code&gt; component into a &lt;code&gt;main&lt;/code&gt; function and run it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;menuItem&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;menuItem&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"new check-in"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;onPress&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Msg&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;struct&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="n"&gt;menuItem&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"view check-ins"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;onPress&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Msg&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;struct&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;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewProgram&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&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;For now, onPress is just a no-op that returns an empty struct. Now, let's run our app.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

go build
./check-ins


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

&lt;/div&gt;

&lt;p&gt;You should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feogrt056069ea53lmwfy.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%2Feogrt056069ea53lmwfy.png" alt="List of options you can select, with an arrow pointed to the selected one, and instructions at the bottom"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cool! Now the menu can toggle what's selected! Now let's handle that user input.&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ Handling the enter key and seeing what the tea.Cmd type actually does
&lt;/h2&gt;

&lt;p&gt;So far, we haven't really taken a close look at the &lt;code&gt;tea.Cmd&lt;/code&gt; type. It's one of the two return values for the &lt;code&gt;Update&lt;/code&gt; method, but we've only used it so far to exit the app. Let's take a closer look at its type signature.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Msg&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;A &lt;code&gt;Cmd&lt;/code&gt; is some sort of function that does some stuff, and then gives us back a &lt;code&gt;tea.Msg&lt;/code&gt;. That function can be time passing, it can be I/O like retrieving some data, really anything goes! The &lt;code&gt;tea.Msg&lt;/code&gt; in turn gets used by our &lt;code&gt;Update&lt;/code&gt; function to update our model and finally our view.&lt;/p&gt;

&lt;p&gt;So handling a user pressing the enter key, and then running an arbitrary onPress function, is one such way to use a Cmd. So let's start with an enter button handler.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;

&lt;/span&gt;  case tea.KeyMsg:
      switch msg.(tea.KeyMsg).String() {
      case "q":
          return m, tea.Quit
      case "down", "right", "up", "left":
          return m.moveCursor(msg.(tea.KeyMsg)), nil
&lt;span class="gi"&gt;+     case "enter", "return":
+         return m, m.options[m.selectedIndex].onPress
&lt;/span&gt;      }
&lt;span class="err"&gt;

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

&lt;/div&gt;

&lt;p&gt;Notice that when the user presses enter, we return the model, unchanged, but we &lt;strong&gt;also&lt;/strong&gt; return the selected item's &lt;code&gt;onPress&lt;/code&gt; function. If you recall when we defined the &lt;code&gt;menuItem&lt;/code&gt; type, the type of its &lt;code&gt;onPress&lt;/code&gt; field was &lt;code&gt;func() tea.Msg&lt;/code&gt;. In other words, that exactly matches the &lt;code&gt;Cmd&lt;/code&gt; type alias!&lt;/p&gt;

&lt;p&gt;There's one other thing we need to do inside the &lt;code&gt;Update&lt;/code&gt; method though. Right now, we're only handling the &lt;code&gt;tea.KeyMsg&lt;/code&gt; type. The type we're returning for toggling the selected item's capitalization will be a brand new type ot &lt;code&gt;tea.Msg&lt;/code&gt;, so we need to define it, and then add a case to our Update method for it. First, let's define the struct.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;toggleCasingMsg&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;We don't need any data to be passed in, so our Msg is just an empty struct; if you recall, the &lt;code&gt;tea.Msg&lt;/code&gt; type is just an empty interface, so we can have a Msg contain as much or as little data as we need.&lt;/p&gt;

&lt;p&gt;Now back in the Update method, let's add a case for &lt;code&gt;toggleCasingMsg&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;First add the method &lt;code&gt;toggleSelectedItemCase&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="n"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;toggleSelectedItemCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;selectedText&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;selectedIndex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;selectedText&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToUpper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;selectedText&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;selectedIndex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToLower&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;selectedText&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;selectedIndex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToUpper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;selectedText&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Then add it to the &lt;code&gt;Update&lt;/code&gt; method.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;

&lt;/span&gt;  func (m menu) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
      switch msg.(type) {
&lt;span class="gi"&gt;+     case toggleCasingMsg:
+         return m.toggleSelectedItemCase(), nil
&lt;/span&gt;      case tea.KeyMsg:
          // our KeyMsg handlers here
&lt;span class="err"&gt;

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

&lt;/div&gt;

&lt;p&gt;On a toggleCasingMsg, we update the casing of the selected menu item, and then return the updated model.&lt;/p&gt;

&lt;p&gt;Finally, in app.go, let's use our toggleCasingMsg&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;

&lt;/span&gt;  menuItem{
      text:    "new check-in",
&lt;span class="gd"&gt;-     onPress: func() tea.Msg { return struct{}{} },
&lt;/span&gt;&lt;span class="gi"&gt;+     onPress: func() tea.Msg { return toggleCasingMsg{} },
&lt;/span&gt;  },
  menuItem{
      text:    "view check-ins",
&lt;span class="gd"&gt;-     onPress: func() tea.Msg { return struct{}{} },
&lt;/span&gt;&lt;span class="gi"&gt;+     onPress: func() tea.Msg { return toggleCasingMsg{} },
&lt;/span&gt;  },
&lt;span class="err"&gt;

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

&lt;/div&gt;

&lt;p&gt;Now let's try our app out!&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

go build
./check-ins


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

&lt;/div&gt;

&lt;p&gt;The app should now look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnlbzzbqoqv7qucl1pe8h.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%2Fnlbzzbqoqv7qucl1pe8h.png" alt="List of options you can select, with an arrow pointed to the selected one that's now in all caps because the user had pressed enter, and instructions at the bottom"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note, by the way, that at this stage of the app, this isn't the only way we could have processed enter; we also could have just processed all the toggling entirely in the update function, rather than having to process it with a Cmd. The reason I chose to use a Cmd were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To show a simple use case for a non-Quit Cmd in Bubble Tea&lt;/li&gt;
&lt;li&gt;By using a Cmd, we can pass arbitrary event handler functions into our components, a similar pattern if you've coded in React.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next up, we've got a menu, but it's not very flashy just yet. In the next tutorial, we'll see how to use Bubble Tea to make our app look cool; first by hand, then with Bubble Tea's CSS-like Lip Gloss package!&lt;/p&gt;

</description>
      <category>go</category>
      <category>codenewbie</category>
      <category>100devs</category>
      <category>tui</category>
    </item>
    <item>
      <title>Intro to Bubble Tea in Go</title>
      <dc:creator>Andy Haskell</dc:creator>
      <pubDate>Sun, 23 Oct 2022 21:23:52 +0000</pubDate>
      <link>https://dev.to/andyhaskell/intro-to-bubble-tea-in-go-21lg</link>
      <guid>https://dev.to/andyhaskell/intro-to-bubble-tea-in-go-21lg</guid>
      <description>&lt;p&gt;Doing stuff in the command line is cool and can make you feel like you're the hero in a hacker movie. But it can also feel old-school with monochromatic avalanches of text, or intimidating with all the command line flags and dollar sign prefixes and different ways to break things without warning.&lt;/p&gt;

&lt;p&gt;But the command line isn't the only way to use your terminal, there's also &lt;strong&gt;TUIs&lt;/strong&gt;, terminal user interfaces, which give a more user-friendly feel to your program. I really like TUIs because they feel like the new and the old at the same time. And in Go, lately the &lt;a href="//github.com/charmbracelet/bubbletea"&gt;Bubble Tea&lt;/a&gt; library, and &lt;a href="https://charm.sh/" rel="noopener noreferrer"&gt;all of Charm Bracelet's other tools&lt;/a&gt;, has been getting a lot of attention for making it easy to make TUIs.&lt;/p&gt;

&lt;p&gt;The advantages of Bubble Tea that have jumped out at me so far are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses the &lt;a href="https://guide.elm-lang.org/architecture/" rel="noopener noreferrer"&gt;Elm architecture&lt;/a&gt; that's shared with browser UI frameworks, so if you've already done some React, Vue, or Elm, it will feel familiar&lt;/li&gt;
&lt;li&gt;The Elm architecture isn't just familiar for modern frontend devs, it's a great way to organize UI code, so it's conducive to building starting your app simple and growing its logic in a manageable way&lt;/li&gt;
&lt;li&gt;Because it's in Go, the language's consistent syntax is conducive to learning by reading other people's code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this series, I'm going to be building a basic TUI app from the ground up for logging what you've been learning in code each day if you're doing a program like #100Devs or one of the ones in the #100DaysOfCode family. At the time I'm writing this it's not finished yet, so each tutorial will be about looking at specific concepts. The approximate roadmap is going to be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🐣 Writing a simple hello world app and seeing how its architecture works&lt;/li&gt;
&lt;li&gt;📝 Building our first real Bubble Tea component, a menu&lt;/li&gt;
&lt;li&gt;✨ Making our menu look cool with some styling, using the CSS-like &lt;a href="//github.com/charmbracelet/lipgloss"&gt;Lipgloss&lt;/a&gt; library&lt;/li&gt;
&lt;li&gt;🚇 Adding routing to our app to display different pages&lt;/li&gt;
&lt;li&gt;🫧 Using Bubble Tea components other people have made, using the &lt;a href="//github.com/charmbracelet/bubbles"&gt;Bubbles&lt;/a&gt; library&lt;/li&gt;
&lt;li&gt;📝 Saving our check-ins to a JSON file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So get your terminal ready, and a boba-sized straw because without further ado it's time to jump into Bubble Tea!&lt;/p&gt;

&lt;h2&gt;
  
  
  🚧 Writing our first basic app
&lt;/h2&gt;

&lt;p&gt;As a first step, we're going to make a "hello world" app in Bubble Tea that you exit by pressing Ctrl+C, which will also introduce us to each part of a Bubble Tea app.&lt;/p&gt;

&lt;p&gt;First, in a new directory titled "code-journal", run:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

go mod init
go get github.com/charmbracelet/bubbletea


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

&lt;/div&gt;

&lt;p&gt;Then, create a file called &lt;code&gt;app.go&lt;/code&gt; and add the following code:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;tea&lt;/span&gt; &lt;span class="s"&gt;"github.com/charmbracelet/bubbletea"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewProgram&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;newSimplePage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"This app is under construction"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&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;Then, let's make another file called &lt;code&gt;simple_page.go&lt;/code&gt; that contains our first UI, a simple page that just displays some text:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 go
package main

import (
    "fmt"
    "strings"

    tea "github.com/charmbracelet/bubbletea"
)

// MODEL DATA

type simplePage struct { text string }

func newSimplePage(text string) simplePage {
    return simplePage{text: text}
}

func (s simplePage) Init() tea.Cmd { return nil }

// VIEW

func (s simplePage) View() string {
    textLen := len(s.text)
    topAndBottomBar := strings.Repeat("*", textLen + 4)
    return fmt.Sprintf(
        "%s\n* %s *\n%s\n\nPress Ctrl+C to exit",
        topAndBottomBar, s.text, topAndBottomBar,
    )
}

// UPDATE

func (s simplePage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    switch msg.(type) {
    case tea.KeyMsg:
        switch msg.(tea.KeyMsg).String() {
        case "ctrl+c":
            return s, tea.Quit
        }
    }
    return s, nil
}


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

&lt;/div&gt;

&lt;p&gt;Before we break down the code, let's run it and see what it does. In your terminal, run:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

go build
./code-journal


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

&lt;/div&gt;

&lt;p&gt;and you should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frb5mwylhpft0xflquati.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%2Frb5mwylhpft0xflquati.png" alt="Terminal displaying the text "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cool! You've got your first Bubble Tea app running. Now let's take a closer look at the code.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧋 Model is the main interface of Bubble Tea
&lt;/h2&gt;

&lt;p&gt;The main function starts the program by creating a new program with the &lt;code&gt;simplePage&lt;/code&gt; model.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewProgram&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;newSimplePage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"This app is under construction"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&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;We call &lt;code&gt;tea.NewProgram&lt;/code&gt;, whose signature is:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewProgram&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initialModel&lt;/span&gt; &lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Program&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;and then calling that program's Start method starts our app. But what is the &lt;code&gt;initialModel&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Model&lt;/code&gt; is the main interface of Bubble Tea. It has three methods:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Model&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt;
    &lt;span class="n"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="n"&gt;Msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Cmd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;View&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;Init&lt;/code&gt; method is called when the app starts, returning a &lt;code&gt;tea.Cmd&lt;/code&gt;. A &lt;code&gt;Cmd&lt;/code&gt; is more or less "stuff happening behind the scenes" like loading data, or time flowing. But for the current tutorial, we don't have any background stuff, so our &lt;code&gt;init&lt;/code&gt; method just returns &lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;simplePage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cmd&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Next up, we've got the &lt;code&gt;View&lt;/code&gt; method. One of the cool abstractions of Bubble Tea is that &lt;strong&gt;your whole UI's display is a string!&lt;/strong&gt; And &lt;code&gt;View&lt;/code&gt; is where you make that string.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;simplePage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;View&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;textLen&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;topAndBottomBar&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;textLen&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;* %s *&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;%s&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;Press Ctrl+C to exit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;topAndBottomBar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;topAndBottomBar&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;So we put the text of our &lt;code&gt;simplePage&lt;/code&gt; in a box made of asterisks, with a message at the bottom saying "Press Ctrl+C to exit"&lt;/p&gt;

&lt;p&gt;But we can't exit our app if it doesn't handle user input, so that's where our &lt;code&gt;Update&lt;/code&gt; method comes in.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;simplePage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cmd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KeyMsg&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KeyMsg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"ctrl+c"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Quit&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;Update&lt;/code&gt; method takes in a &lt;code&gt;tea.Msg&lt;/code&gt; and returns a new &lt;code&gt;tea.Model&lt;/code&gt; and sometimes a &lt;code&gt;tea.Cmd&lt;/code&gt; (like if an action results in retrieving some data or a timer going off).&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;tea.Msg&lt;/code&gt;'s type signature is&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Msg&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;So it can be any type and carry as much or as little data as you need. It's sort of like a browser event in JavaScript if you've done frontend there; a timer event doesn't carry any data, a click event tells you what clicked on, etc.&lt;/p&gt;

&lt;p&gt;The kind of message we're processing is &lt;code&gt;tea.KeyMsg&lt;/code&gt;, which represents keyboard input. We're checking if the user pressed Ctrl+C, and if so, we return the &lt;code&gt;tea.Quit&lt;/code&gt; command, which is of the type &lt;code&gt;tea.Cmd&lt;/code&gt; and tells Bubble Tea to exit the app.&lt;/p&gt;

&lt;p&gt;For any other kind of input though, we don't do anything. We just return the model as-is. If we were doing something though like UI navigation, though, we would change some fields on the Model and then return it, causing the UI to update. And that's what we're going to see in the next tutorial where we make a menu component!&lt;/p&gt;

</description>
      <category>go</category>
      <category>codenewbie</category>
      <category>100devs</category>
      <category>tui</category>
    </item>
    <item>
      <title>#WebDevSampler challenge - My answers in Go</title>
      <dc:creator>Andy Haskell</dc:creator>
      <pubDate>Fri, 12 Aug 2022 00:48:08 +0000</pubDate>
      <link>https://dev.to/andyhaskell/webdevsampler-challenge-my-answers-in-go-3hkl</link>
      <guid>https://dev.to/andyhaskell/webdevsampler-challenge-my-answers-in-go-3hkl</guid>
      <description>&lt;p&gt;As a first time doing the &lt;a href="https://dev.to/andyhaskell/introducing-the-webdevsampler-challenge-answers-in-go-5cmh"&gt;#WebDevSampler challenge&lt;/a&gt;, I used Go, which is a popular backend language, as well as the language I have been coding in professionally for seven years. Ahead are my answers to the 11 exercises in the sampler, which are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;(1) Get an HTTP server up and running, serving an endpoint that gives the HTTP response with a message like "hello world!".&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Concept demonstrated: starting an HTTP server and processing an HTTP request.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(2) Give that HTTP response as HTML, with Content-Type &lt;code&gt;text/html&lt;/code&gt;&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Concept demonstrated: editing the HTTP response using response headers&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(3) Adding another endpoint/route on your HTTP server, such as an &lt;code&gt;/about.html&lt;/code&gt; page&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Concept demonstrated: serving more than one HTTP endpoint&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(4) Serving an endpoint with an image or webpage in your file system&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Concept demonstrated: serving content from a file system&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(5) Route to an endpoints using more complex route like &lt;code&gt;/signup/my-name-is/:name&lt;/code&gt;, for example if I send a request to &lt;code&gt;/signup/my-name-is/Andy&lt;/code&gt; I would get back "You're all signed up for the big convention Andy!"&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Concept demonstrated: Parameterized routing&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(6) Write and run an automated test for your HTTP parameterized endpoint&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Concept demonstrated: Automated testing with an HTTP endpoint in one of your language's testing CLI tools.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(7) Escape HTML tags in your endpoint. For example, &lt;code&gt;/signup/my-name-is/&amp;lt;i&amp;gt;Andy&lt;/code&gt; should be sanitized so you DON'T display your name in italics&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Concept demonstrated: Basic input sanitization&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(8) Serialize an object/struct/class to some JSON and serve it on an endpoint with a &lt;code&gt;Content-Type: application/json&lt;/code&gt;&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Concept demonstrated: JSON serialization, which is done a lot creating backend APIs&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(9) Add a POST HTTP endpoint whose input is of Content-Type &lt;code&gt;application/json&lt;/code&gt;, deserialize it to an object/struct/class, and then use some part of the object to produce some part of the HTTP response.&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Concept demonstrated: JSON deserialization&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(10) Now have that POST endpoint save the content to some database (MongoDB, Postgres, Cassandra, any database you want)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Concept demonstrated: Database input&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(11) Now make a GET endpoint that retrieves a piece of data from the database&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Concept demonstrated: Database retrieval&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The tools I used for doing this challenge were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Go standard library&lt;/li&gt;
&lt;li&gt;Go's built-in testing command for doing automated test coverage&lt;/li&gt;
&lt;li&gt;Gorilla Mux for parameterized HTTP routing&lt;/li&gt;
&lt;li&gt;SQLite and mattn's SQLite package for the database problems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, onward to the answers!&lt;/p&gt;

&lt;h2&gt;
  
  
  (1) Get an HTTP server up and running, serving an endpoint that gives the HTTP response with a message like "hello world!".
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Go code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c"&gt;// Go's standard library package for HTTP clients and servers&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// make an http.ServeMux, a Go standard library object that&lt;/span&gt;
    &lt;span class="c"&gt;// routes HTTP requests to different endpoints&lt;/span&gt;
    &lt;span class="n"&gt;rt&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServeMux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// Make a catch-all endpoint for all requests going into the&lt;/span&gt;
    &lt;span class="c"&gt;// server. When the endpoint is hit, we run the function passed&lt;/span&gt;
    &lt;span class="c"&gt;// in to process the request.&lt;/span&gt;
    &lt;span class="n"&gt;rt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// We have the ResponseWriter write the bytes of the string&lt;/span&gt;
        &lt;span class="c"&gt;// "Hello world!"&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello world!"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c"&gt;// create a new server and run it with ListenAndServe to take&lt;/span&gt;
    &lt;span class="c"&gt;// HTTP requests on port 1123&lt;/span&gt;
    &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Addr&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;":1123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rt&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&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;h3&gt;
  
  
  Starting the program
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;go run main.go&lt;/code&gt;, or use &lt;code&gt;go install&lt;/code&gt; and run the installed binary&lt;/li&gt;
&lt;li&gt;Go to &lt;code&gt;http://localhost:1123&lt;/code&gt; in a browser or in a program like cURL. You should see the text "hello world!"&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  (2) Give that HTTP response as HTML, with Content-Type &lt;code&gt;text/html&lt;/code&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Go code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;rt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Add the header "Content-Type: text/html"&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"text/html"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Add some HTML &amp;lt;h1&amp;gt; tags to the hello world response. The&lt;/span&gt;
    &lt;span class="c"&gt;// browser, seeing the response is Content-Type: text/html,&lt;/span&gt;
    &lt;span class="c"&gt;// will display the response as a big header.&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;h1&amp;gt;Hello world!&amp;lt;/h1&amp;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;h3&gt;
  
  
  Starting the program
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Compile and start the server again, and refresh &lt;code&gt;http://localhost:1123&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The response should now be displayed as a webpage&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  (3) Add another endpoint/route on your HTTP server, such as an &lt;code&gt;/about.html&lt;/code&gt; page
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Go code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// naming the route "/about" makes it so when a request is sent to&lt;/span&gt;
&lt;span class="c"&gt;// http://localhost:1123/about, the about page is served instead of&lt;/span&gt;
&lt;span class="c"&gt;// the hello world page&lt;/span&gt;
&lt;span class="n"&gt;rt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/about"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"text/html"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`
      &amp;lt;!DOCTYPE html&amp;gt;
      &amp;lt;html&amp;gt;
        &amp;lt;head&amp;gt;
          &amp;lt;title&amp;gt;About us&amp;lt;/title&amp;gt;
        &amp;lt;/head&amp;gt;
        &amp;lt;body&amp;gt;
          &amp;lt;h1&amp;gt;About us&amp;lt;/h1&amp;gt;
          &amp;lt;p&amp;gt;We've got a website!&amp;lt;/p&amp;gt;
        &amp;lt;/body&amp;gt;
      &amp;lt;/html&amp;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;h3&gt;
  
  
  Starting the program
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Compile and start the server again&lt;/li&gt;
&lt;li&gt;Go to &lt;a href="http://localhost:1123/about"&gt;http://localhost:1123/about&lt;/a&gt;. You should now see your about page.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  (4) Serving an endpoint with an image or webpage in your file system
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Preliminary steps
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Make a directory inside the directory where main.go is, named "images"&lt;/li&gt;
&lt;li&gt;Save a JPEG image in that images directory named "gopher.jpg"&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Go code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// We are using Handle, not HandleFunc, because we're passing&lt;/span&gt;
&lt;span class="c"&gt;// in an object of type http.Handler, not a function&lt;/span&gt;
&lt;span class="n"&gt;rt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"/images/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c"&gt;// StripPrefix chops the prefix, in this case "/images/",&lt;/span&gt;
    &lt;span class="c"&gt;// off of the HTTP request's path before passing the&lt;/span&gt;
    &lt;span class="c"&gt;// request to the http.FileServer&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StripPrefix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"/images/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c"&gt;// create a FileServer handler that serves files in&lt;/span&gt;
        &lt;span class="c"&gt;// your "images" directory&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FileServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"images"&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;h3&gt;
  
  
  Starting the program
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Compile and start the server again&lt;/li&gt;
&lt;li&gt;Go to &lt;a href="http://localhost:1123/images/gopher.jpg"&gt;http://localhost:1123/images/gopher.jpg&lt;/a&gt;. You now should see your gopher.jpg file&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  (5) Route to an endpoints using more complex route like /signup/my-name-is/:name
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Preliminary steps
&lt;/h3&gt;

&lt;p&gt;For this, one, we'll use the &lt;a href="https://github.com/gorilla/mux"&gt;Gorilla Mux&lt;/a&gt; library, since that is one of the most popular HTTP routing libraries in Go.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set up a &lt;code&gt;go.mod&lt;/code&gt; file with &lt;code&gt;go mod init&lt;/code&gt;. &lt;code&gt;go mod&lt;/code&gt; is Go's built-in package manager, and it is where your project's dependencies are listed, similar to package.json in Node.js.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;go get github.com/gorilla/mux&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Go code
&lt;/h3&gt;

&lt;p&gt;First add Gorilla Mux to your imports&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c"&gt;// fmt is a string formatting package in Go&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;

    &lt;span class="c"&gt;// Now we're importing the Gorilla Mux package in addition to&lt;/span&gt;
    &lt;span class="c"&gt;// net/http&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/gorilla/mux"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then at the start of &lt;code&gt;main&lt;/code&gt;, replace the &lt;code&gt;ServeMux&lt;/code&gt; with a Gorilla Mux &lt;code&gt;Router&lt;/code&gt; and add your parameterized endpoint to it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// now instead of a ServeMux, we're using a Gorilla Mux router&lt;/span&gt;
    &lt;span class="n"&gt;rt&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRouter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// Our new parameterized route&lt;/span&gt;
    &lt;span class="n"&gt;rt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="c"&gt;// make a parameter in the request path that Gorilla&lt;/span&gt;
        &lt;span class="c"&gt;// recognizes with the string "name"&lt;/span&gt;
        &lt;span class="s"&gt;"/signup/my-name-is/{name}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c"&gt;// the route parameters on the request are parsed&lt;/span&gt;
            &lt;span class="c"&gt;// into a map[string]string&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Vars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

            &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"text/html"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="c"&gt;// use the route parameter in the HTTP response&lt;/span&gt;
                &lt;span class="s"&gt;"&amp;lt;h1&amp;gt;You're all signed up for the big convention %s!&amp;lt;/h1&amp;gt;"&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="p"&gt;)))&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Our existing endpoints mostly stay the same as before&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, update the format of the images directory endpoint to use PathPrefix, which is what you use for path prefixes in Gorilla Mux as opposed to &lt;code&gt;Handle("/path/", handler)&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;rt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PathPrefix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/images/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StripPrefix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"/images/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FileServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"images"&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;h3&gt;
  
  
  Starting the program
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Compile and start the server again&lt;/li&gt;
&lt;li&gt;Go to &lt;a href="http://localhost:1123/signup/my-name-is/YOUR_NAME"&gt;http://localhost:1123/signup/my-name-is/YOUR_NAME&lt;/a&gt;. You now should get an HTML response saying you're signed up&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  (6) Write an automated test for your HTTP parameterized endpoint
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Preliminary steps
&lt;/h3&gt;

&lt;p&gt;First, take the logic for setting up our Mux router and move it to its own function&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;handleSignup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Vars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"text/html"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"&amp;lt;h1&amp;gt;You're all signed up for the big convention %s!&amp;lt;/h1&amp;gt;"&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="p"&gt;)))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// The router function is pretty much the same as the main&lt;/span&gt;
&lt;span class="c"&gt;// function as of the last exercise, from when rt is declared&lt;/span&gt;
&lt;span class="c"&gt;// to when we declared the last handler in the router.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;rt&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRouter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;rt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/signup/my-name-is/{name}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handleSignup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;// not shown: The other endpoints' handlers&lt;/span&gt;

    &lt;span class="c"&gt;// mux.Router, the type of rt, implements the http.Handler&lt;/span&gt;
    &lt;span class="c"&gt;// interface, which is in charge of handling HTTP requests&lt;/span&gt;
    &lt;span class="c"&gt;// and serving HTTP responses.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;rt&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now replace the body of &lt;code&gt;main&lt;/code&gt; with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// create a new server and run it with ListenAndServe to take&lt;/span&gt;
    &lt;span class="c"&gt;// HTTP requests on port 1123&lt;/span&gt;
    &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Addr&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;":1123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;
    &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&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;Then, make a new file named &lt;code&gt;app_test.go&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Go code (in app_test.go)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c"&gt;// Standard library package for working with I/O&lt;/span&gt;
    &lt;span class="s"&gt;"io"&lt;/span&gt;
    &lt;span class="c"&gt;// Standard library testing utilities for Go web apps&lt;/span&gt;
    &lt;span class="s"&gt;"net/http/httptest"&lt;/span&gt;
    &lt;span class="c"&gt;// Standard library URL-parsing package&lt;/span&gt;
    &lt;span class="s"&gt;"net/url"&lt;/span&gt;
    &lt;span class="c"&gt;// Standard library testing package&lt;/span&gt;
    &lt;span class="s"&gt;"testing"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// Functions whose name start with Test and then a capital&lt;/span&gt;
&lt;span class="c"&gt;// letter and take in a testing.T object are run by the&lt;/span&gt;
&lt;span class="c"&gt;// `go test` subcommand&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestSignup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// A ResponseRecorder is the httptest implementation of&lt;/span&gt;
    &lt;span class="c"&gt;// http.ResponseWriter, that lets us see the HTTP response&lt;/span&gt;
    &lt;span class="c"&gt;// it wrote after running an HTTP handler function&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;httptest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRecorder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// convert a string to a *url.URL object&lt;/span&gt;
    &lt;span class="n"&gt;reqURL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://localhost:1123/signup/my-name-is/Andy"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// if parsing the URL fails, have the test fail&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error parsing URL: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// set up our HTTP request, which will be to the endpoint&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;reqURL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// send the request to the HTTP server by passing it and the&lt;/span&gt;
    &lt;span class="c"&gt;// ResponseWriter to mux.Router.ServeHTTP(). The result of&lt;/span&gt;
    &lt;span class="c"&gt;// that HTTP call is stored in the ResponseRecorder.&lt;/span&gt;
    &lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServeHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c"&gt;// convert the response stored in res.Body to bytes and check&lt;/span&gt;
    &lt;span class="c"&gt;// that we got back the response we expected.&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error retrieving response body: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;bodyStr&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;`&amp;lt;h1&amp;gt;You're all signed up for the big convention Andy!&amp;lt;/h1&amp;gt;`&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;bodyStr&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"expected response %s, got %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bodyStr&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;h3&gt;
  
  
  Running the test
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;From the directory the Go files are in, run &lt;code&gt;go test -v&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Observe the test passing. If you change the text the sign-up endpoint serves, then the test should now fail.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  (7) Escape HTML tags in your endpoint.
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Go code (main.go)
&lt;/h3&gt;

&lt;p&gt;First import the net/html package&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c"&gt;// standard library package for working with HTML&lt;/span&gt;
    &lt;span class="s"&gt;"html"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/gorilla/mux"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then update handleSignup to call EscapeString. In a real production app, we'd be doing more advanced sanitization of user data than this and probably rendering our HTML using a templating library that has sanitization built-in in order to catch more edge cases with malicious input, but EscapeString handles sanitizing HTML characters as a very simple demonstration of input sanitization.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;handleSignup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Vars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="c"&gt;// we use EscapeString to escape characters that are used in&lt;/span&gt;
    &lt;span class="c"&gt;// HTML syntax. For example, the character &amp;lt; becomes &amp;amp;lt; and&lt;/span&gt;
    &lt;span class="c"&gt;// &amp;gt; becomes &amp;amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EscapeString&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="c"&gt;// rest of the endpoint stays the same&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"text/html"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"&amp;lt;h1&amp;gt;You're all signed up for the big convention %s!&amp;lt;/h1&amp;gt;"&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="p"&gt;)))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Go test code (main_test.go)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestSignupHTMLEscape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;httptest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRecorder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// convert a string to a *url.URL object, this time with&lt;/span&gt;
    &lt;span class="c"&gt;// some HTML in it that should be escaped&lt;/span&gt;
    &lt;span class="n"&gt;urlString&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"http://localhost:1123/signup/my-name-is/&amp;lt;i&amp;gt;Andy"&lt;/span&gt;
    &lt;span class="n"&gt;reqURL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urlString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// if parsing the URL fails, have the test fail&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error parsing URL: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// run ServeHTTP just like before&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;reqURL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServeHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error retrieving response body: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Expect that we thwarted the HTML injection attempt&lt;/span&gt;
    &lt;span class="n"&gt;bodyStr&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;`&amp;lt;h1&amp;gt;You're all signed up for the big convention &amp;amp;lt;i&amp;amp;gt;Andy!&amp;lt;/h1&amp;gt;`&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;bodyStr&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"expected response %s, got %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bodyStr&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;h3&gt;
  
  
  Running the test
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;From the directory the Go files are in, run &lt;code&gt;go test -v&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Observe the test passing. If you comment out the EscapeString call, then the test should now fail.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Running the server
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Compile and start the server again&lt;/li&gt;
&lt;li&gt;Go to &lt;code&gt;http://localhost:1123/signup/my-name-is/&amp;lt;i&amp;gt;YOUR_NAME&lt;/code&gt;. You now should NOT get any italicized text since the &lt;code&gt;&amp;lt;i&amp;gt;&lt;/code&gt; tag was escaped.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  (8) Serialize an object/struct/class to some JSON and serve it on an endpoint with a &lt;code&gt;Content-Type: application/json&lt;/code&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Go code (near top of main.go)
&lt;/h3&gt;

&lt;p&gt;First, import &lt;code&gt;encoding/json&lt;/code&gt;, Go's standard library package for serializing objects to JSON&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c"&gt;// Go's standard library for JSON serialization&lt;/span&gt;
    &lt;span class="s"&gt;"encoding/json"&lt;/span&gt;
    &lt;span class="s"&gt;"net/html"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then define this struct and HTTP endpoint&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Define a type with JSON serialization specified by JSON&lt;/span&gt;
&lt;span class="c"&gt;// Go struct tags&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;animalFact&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;AnimalName&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"animal_name"`&lt;/span&gt;
    &lt;span class="n"&gt;AnimalFact&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"animal_fact"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// add this function into the "router" function&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;sendAnimalFact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fact&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;animalFact&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;AnimalName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Tree kangaroo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;AnimalFact&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"They look like teddy bears but have a long"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
                        &lt;span class="s"&gt;" tail to keep their balance in trees!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c"&gt;// Set the Content-Type for the response to application/json&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// load the ResponseWriter into a JSON encoder, and then by&lt;/span&gt;
    &lt;span class="c"&gt;// calling that Encoder's Encode method with a pointer to the&lt;/span&gt;
    &lt;span class="c"&gt;// animalFact struct, the ResponseWriter will write the struct&lt;/span&gt;
    &lt;span class="c"&gt;// as JSON.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;fact&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// if serializing the response fails, then return a&lt;/span&gt;
        &lt;span class="c"&gt;// 500 internal server error response with the error&lt;/span&gt;
        &lt;span class="c"&gt;// message "error serializing response to JSON".&lt;/span&gt;
        &lt;span class="c"&gt;// If the serialization succeeds though, we're all&lt;/span&gt;
        &lt;span class="c"&gt;// set and the HTTP response is already sent.&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`{"error": "couldn't serialize to JSON"}`&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;Finally, add the animal fact to the &lt;code&gt;router&lt;/code&gt; function&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;rt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/animal-fact"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sendAnimalFact&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running the server
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Compile and start the server again&lt;/li&gt;
&lt;li&gt;Go to &lt;code&gt;http://localhost:1123/animal-fact&lt;/code&gt;. You should get your animal fact in JSON.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  (9) Add a POST HTTP endpoint whose input is of Content-Type &lt;code&gt;application/json&lt;/code&gt;, deserialize it to an object/struct/class, and then use some part of the object to produce some part of the HTTP response.
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Go code (near top of main.go)
&lt;/h3&gt;

&lt;p&gt;First, define a signup struct, its JSON serialization using Go struct tags, and an endpoint to handle a JSON payload&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c"&gt;// Go's standard library for JSON serialization&lt;/span&gt;
    &lt;span class="s"&gt;"encoding/json"&lt;/span&gt;
    &lt;span class="s"&gt;"net/html"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/gorilla/mux"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// Define a type with JSON serialization specified by JSON&lt;/span&gt;
&lt;span class="c"&gt;// Go struct tags. For example, `json:"days_signed_up_for"`&lt;/span&gt;
&lt;span class="c"&gt;// indicates that the DaysSignedUpFor field should be&lt;/span&gt;
&lt;span class="c"&gt;// serialized as days_signed_up_for, not DaysSignedUpFor&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;signup&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt;            &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"name"`&lt;/span&gt;
    &lt;span class="n"&gt;DaysSignedUpFor&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;    &lt;span class="s"&gt;`json:"days_signed_up_for"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// add this function into the "router" function&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;handleJSONSignup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="c"&gt;// load the request's Body into a JSON Decoder, and then by&lt;/span&gt;
    &lt;span class="c"&gt;// calling that Decoder's Decode method with a pointer to the&lt;/span&gt;
    &lt;span class="c"&gt;// signup struct,&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;signup&lt;/span&gt; 
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// if deserializing the response fails, then return a&lt;/span&gt;
        &lt;span class="c"&gt;// 400 Bad Request header and the error message&lt;/span&gt;
        &lt;span class="c"&gt;// "invalid JSON payload"&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"invalid JSON payload"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// use the signup in the response body&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EscapeString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DaysSignedUpFor&lt;/span&gt;
    &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"You're all signed up %s! Have a great %d days at the big convention!"&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="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// NOTE: in a real production endpoint, if we're taking&lt;/span&gt;
    &lt;span class="c"&gt;// in a JSON payload we'd probably send a JSON response&lt;/span&gt;
    &lt;span class="c"&gt;// rather than plain text&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&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;Finally, in the &lt;code&gt;router&lt;/code&gt; function, add our handleJSONSignup endpoint&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;rt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Methods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MethodPost&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/signup"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandlerFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handleJSONSignup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running the server
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Compile and start the server again&lt;/li&gt;
&lt;li&gt;Send a request to the POST signup endpoint with your HTTP client. For example, in cURL, that would look like: &lt;code&gt;curl -XPOST http://localhost:1123/signup --data '{"name": "YOUR_NAME", "days_signed_up_for": 3}'&lt;/code&gt;. You should now see a response indicating how many days you're signed up for.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  (10) Save the input of your POST request to a database
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Preliminary steps to using my implementation
&lt;/h3&gt;

&lt;p&gt;In the interest of simplicity, we will use &lt;a href="https://www.sqlite.org/index.html"&gt;SQLite&lt;/a&gt; as our database. &lt;a href="https://www.sqlite.org/whentouse.html"&gt;If we were developing a big web app&lt;/a&gt; and planning on the site getting really popular with tons of people wanting data from the database at the same time, we might instead opt for a database like Postgres or MongoDB.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install SQLite and add it to your computer's path&lt;/li&gt;
&lt;li&gt;Open SQLite's command-line tool from the folder you've been coding the Sampler in. The command to do so is &lt;code&gt;sqlite3&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Create your SQLite database with the command &lt;code&gt;.open website.db&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Create your database table with the command &lt;code&gt;CREATE TABLE signups (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, days_signed_up_for INTEGER);&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now we have a database table to store sign-ups! Now for Go to be able to talk to SQLite, or any SQL database with the Go standard library's &lt;code&gt;database/sql&lt;/code&gt; package, we need a &lt;strong&gt;database driver&lt;/strong&gt; for the database we're using. We can get the one for SQLite using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go get github.com/mattn/go-sqlite3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we're ready to use the actual code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Go code
&lt;/h3&gt;

&lt;p&gt;First in main.go, import &lt;code&gt;database/sql&lt;/code&gt;, Go's standard library package for working with SQL databases, and underscore-import &lt;code&gt;go-sqlite3&lt;/code&gt; so that &lt;code&gt;database/sql&lt;/code&gt; &lt;strong&gt;registers&lt;/strong&gt; the SQLite Go database driver. With that underscore import, your Go code is now able to talk to SQLite databases.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c"&gt;// Go's standard library for JSON serialization&lt;/span&gt;
    &lt;span class="s"&gt;"database/sql"&lt;/span&gt;
    &lt;span class="s"&gt;"encoding/json"&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"html"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/gorilla/mux"&lt;/span&gt;
    &lt;span class="c"&gt;// register the database driver for SQLite&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="s"&gt;"github.com/mattn/go-sqlite3"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, define an object for interacting with our &lt;code&gt;signups&lt;/code&gt; database table. This is so that the logic for interacting with the database is not intertwined with the logic for serving the endpoint, making the code easier to test and harder to get unexpected bugs with.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// signupsDB centralizes the logic for storing signups in&lt;/span&gt;
&lt;span class="c"&gt;// SQLite.&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;signupsDB&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;newSignupsDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;signupsDB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Open a database/sql DB for the file path, using the&lt;/span&gt;
    &lt;span class="c"&gt;// sqlite3 database driver.&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sqlite3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;signupsDB&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// SQLite syntax to more or less say "insert the values of the&lt;/span&gt;
&lt;span class="c"&gt;// two question mark parameters into the name and&lt;/span&gt;
&lt;span class="c"&gt;// days_signed_up_for fields of a new item in the signups table&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;insertSignupQuery&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;`
INSERT INTO signups (name, days_signed_up_for)
VALUES (?, ?)`&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;signupsDB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;signup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// run DB.Exec to insert an item into the database&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;insertSignupQuery&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DaysSignedUpFor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// check that only one item was inserted into the database&lt;/span&gt;
    &lt;span class="c"&gt;// table&lt;/span&gt;
    &lt;span class="n"&gt;rowsAffected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RowsAffected&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;rowsAffected&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"expected 1 row to be affected, but %d rows were."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;rowsAffected&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="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now add an &lt;code&gt;init&lt;/code&gt; function for initializing our database. Note that this isn't how we'd set up a database connectioin in a production app, but it's probably the simplest way to do this setup.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// in a real production Go web app, we would be structuring&lt;/span&gt;
&lt;span class="c"&gt;// our HTTP handlers to be data structures instead of plain&lt;/span&gt;
&lt;span class="c"&gt;// functions so we aren't relying on global variables, but&lt;/span&gt;
&lt;span class="c"&gt;// for the sampler we'll just initialize our database in the&lt;/span&gt;
&lt;span class="c"&gt;// init function and panic if that fails to keep things simple&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;signupsDB&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newSignupsDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./website.db"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"error opening db: %v; can't start the web app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&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;Then add &lt;code&gt;db:&lt;/code&gt; struct tags for serializing your object in a database as well as in JSON.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;signup&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt;            &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"name",db:"name"`&lt;/span&gt;
    &lt;span class="n"&gt;DaysSignedUpFor&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;    &lt;span class="s"&gt;`json:"days_signed_up_for",db:"days_signed_up_for"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, in the &lt;code&gt;handleJSONSignup&lt;/code&gt; endpoint, add this if statement right before where you serve the HTTP response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// in a real production web app, we'd look in more&lt;/span&gt;
        &lt;span class="c"&gt;// detail at the error's value to decide the&lt;/span&gt;
        &lt;span class="c"&gt;// appropriate status code and error message&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error inserting signup"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running the server
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Compile and start the server again&lt;/li&gt;
&lt;li&gt;Send a request to the POST signup endpoint with your HTTP client. For example, in cURL, that would look like: &lt;code&gt;curl -XPOST http://localhost:1123/signup --data '{"name": "YOUR_NAME", "days_signed_up_for": 3}'&lt;/code&gt;. You should now see a response indicating how many days you're signed up for.&lt;/li&gt;
&lt;li&gt;To see that you really put a sign-up in the database entity, open &lt;code&gt;sqlite3&lt;/code&gt; in the command line, open the database again with &lt;code&gt;.open website.db&lt;/code&gt;, and finally, run &lt;code&gt;SELECT * FROM signups&lt;/code&gt;. You should now see a single item in the database.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  (11) Make a GET endpoint that retrieves a piece of data from the database
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Go code
&lt;/h3&gt;

&lt;p&gt;First, add a new method to the &lt;code&gt;signupsDB&lt;/code&gt; type for retrieving signups by name&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// SQLite syntax more or less saying "get the "name" and&lt;/span&gt;
&lt;span class="c"&gt;// "days_signed_up_for" fields of AT MOST one item in the&lt;/span&gt;
&lt;span class="c"&gt;// signups table whose name matches the question-mark&lt;/span&gt;
&lt;span class="c"&gt;// parameter"&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;getSignupQuery&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;`SELECT name, days_signed_up_for FROM signups WHERE name=? LIMIT 1`&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;signupsDB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;getByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;signup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// retrieve a single item from the "signups" database&lt;/span&gt;
    &lt;span class="c"&gt;// table. We get back a *sql.Row containing our result, or&lt;/span&gt;
    &lt;span class="c"&gt;// lack thereof if the item we want is not in the database&lt;/span&gt;
    &lt;span class="c"&gt;// table.&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QueryRow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;getSignupQuery&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="c"&gt;// We deserialize the Row to the data type we want using&lt;/span&gt;
    &lt;span class="c"&gt;// Row.Scan. If no database entity had been retrieved,&lt;/span&gt;
    &lt;span class="c"&gt;// then we instead get back sql.ErrNoRows.&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;signup&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DaysSignedUpFor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, make a new endpoint that uses getByName to query for signups&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;handleGetSignupFromDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Vars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;signup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getByName&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="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="c"&gt;// if there's no error, we have a signup, so carry on&lt;/span&gt;
        &lt;span class="c"&gt;// with sending it as our JSON response&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrNoRows&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="c"&gt;// if we got ErrNoRows, then return a 404&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusNotFound&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`{"error": "sign-up not found"}`&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="c"&gt;// for any other kind of error, return a 500&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`{"error": "unexpected error"}`&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signup&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`{"error": "couldn't serialize to JSON"}`&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;Finally, add &lt;code&gt;handleGetSignupFromDB&lt;/code&gt; to &lt;code&gt;router&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;rt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/signup/get/{name}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handleGetSignupFromDB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running the server
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Compile and start the server again&lt;/li&gt;
&lt;li&gt;Send a request to the &lt;a href="http://localhost:1123/signup/get/YOUR_NAME"&gt;http://localhost:1123/signup/get/YOUR_NAME&lt;/a&gt;. You should now see the JSON of your sign-up you did in the last step.&lt;/li&gt;
&lt;li&gt;Send another request to the signup endpoint, this time with the name of someone that didn't sign up. You should now see the JSON of a sign-up not found error.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>webdevsampler</category>
      <category>go</category>
      <category>codenewbie</category>
      <category>backend</category>
    </item>
    <item>
      <title>Introducing the #WebDevSampler challenge</title>
      <dc:creator>Andy Haskell</dc:creator>
      <pubDate>Wed, 10 Aug 2022 02:29:03 +0000</pubDate>
      <link>https://dev.to/andyhaskell/introducing-the-webdevsampler-challenge-answers-in-go-5cmh</link>
      <guid>https://dev.to/andyhaskell/introducing-the-webdevsampler-challenge-answers-in-go-5cmh</guid>
      <description>&lt;p&gt;There are a lot of programming languages you can use to code the server for your web app, but regardless of which one you use, there are core concepts you will always need to know how to do. Some of those are things like routing, security, database interactions, serialization to formats like JSON, and HTTP.&lt;/p&gt;

&lt;p&gt;With all the different concepts to be thinking about, and all the different tools and frameworks you can choose from, learning web development can be understandably overwhelming to get going with. But one thing that I find helps when learning a new tool, is breaking down what I'm learning into bite-size tasks, especially when they build on each other.&lt;/p&gt;

&lt;p&gt;So for trying out a new language's web development stack, see if I like it, and get feedback on implementation patterns, I am trying something called &lt;strong&gt;#WebDevSampler&lt;/strong&gt; as a set of bite-sized excercises for starting web development in a new programming language. The idea of the challenge is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;#WebDevSampler assumes you know the fundamentals for the language, such as iteration, functions, data types, and compiling/running a program.

&lt;ul&gt;
&lt;li&gt;The ninth exercise assumes are familiar with using an HTTP client like &lt;strong&gt;cURL&lt;/strong&gt;, &lt;strong&gt;httpie&lt;/strong&gt;, or &lt;strong&gt;Postman&lt;/strong&gt; to send a JSON payload to an HTTP endpoint.&lt;/li&gt;
&lt;li&gt;The final two exercises, the database ones, do assume familiarity with talking to at least one kind of database. But I left it vague which database to use so you can use the one you like best. I am using SQLite in my own example.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Each exercise is intended to be the relatively simple so the code changes it entails can demonstrate the concept.&lt;/li&gt;
&lt;li&gt;Each exercise builds on each other, so they are intended to be run in order.&lt;/li&gt;
&lt;li&gt;For any exercise, what you use to solve the problem is up to you, which is why what you build in an exercise is intentionally vague. You can use just the standard library in the language, or you can use dependencies like libraries, microframeworks, and even big frameworks (but I personally wouldn't start in a new language with the big Rails-like framework for that language, unless you know you want to be using that framework on the job).

&lt;ul&gt;
&lt;li&gt;In fact, you're encouraged to try tools out in your language and compare them to see which ones you like best, and to learn about which tools are commonly used on the job in your language's web developer community. And you're encouraged to try installing at least one dependency so you can see how package management works in the language.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Want to do other experimentation with your code that's not on the exercises? Then you should! Going off the beaten path is a great way to learn more stuff, and you do a lot of that in a web development job!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The exercises are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;(1) Get an HTTP server up and running, serving an endpoint that gives the HTTP response with a message like "hello world!".&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Concept demonstrated: starting an HTTP server and processing an HTTP request.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(2) Give that HTTP response as HTML, with Content-Type &lt;code&gt;text/html&lt;/code&gt;&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Concept demonstrated: editing the HTTP response using response headers&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(3) Adding another endpoint/route on your HTTP server, such as an &lt;code&gt;/about.html&lt;/code&gt; page&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Concept demonstrated: serving more than one HTTP endpoint&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(4) Serving an endpoint with an image or webpage in your file system&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Concept demonstrated: serving content from a file system&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(5) Route to an endpoints using more complex route like &lt;code&gt;/signup/my-name-is/:name&lt;/code&gt;, for example if I send a request to &lt;code&gt;/signup/my-name-is/Andy&lt;/code&gt; I would get back "You're all signed up for the big convention Andy!"&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Concept demonstrated: Parameterized routing&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(6) Write and run an automated test for your HTTP parameterized endpoint&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Concept demonstrated: Automated testing with an HTTP endpoint in one of your language's testing CLI tools.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(7) Escape HTML tags in your endpoint. For example, &lt;code&gt;/signup/my-name-is/&amp;lt;i&amp;gt;Andy&lt;/code&gt; should be sanitized so you DON'T display your name in italics&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Concept demonstrated: Basic input sanitization&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(8) Serialize an object/struct/class to some JSON and serve it on an endpoint with a &lt;code&gt;Content-Type: application/json&lt;/code&gt;&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Concept demonstrated: JSON serialization, which is done a lot creating backend APIs&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(9) Add a POST HTTP endpoint whose input is of Content-Type &lt;code&gt;application/json&lt;/code&gt;, deserialize it to an object/struct/class, and then use some part of the object to produce some part of the HTTP response.&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Concept demonstrated: JSON deserialization&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(10) Now have that POST endpoint save the content to some database (MongoDB, Postgres, Cassandra, any database you want)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Concept demonstrated: Database input&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(11) Now make a GET endpoint that retrieves a piece of data from the database&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Concept demonstrated: Database retrieval&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to see my answers in Go, which I've been coding in professionally for 7 years, you can check them out &lt;a href="https://dev.to/andyhaskell/webdevsampler-challenge-my-answers-in-go-3hkl"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to after the challenge?
&lt;/h2&gt;

&lt;p&gt;If you worked through the examples, congratulations and I hope you learned something about how web development is done in your language! &lt;/p&gt;

&lt;p&gt;Since this was a sampler, the exercises were intended to give just a taste of each of the web development concepts they talk about. So if you are newer to web development, a good next stop would be to search the concepts that the exercises cover and keep learning more about them, for example in the input sanitization exercise, as I alluded to in the code comments, in a production app I would be more likely to be generating HTML using a library that has user data sanitization built-in, and also have a more rigorous set of unit tests to cover possible security holes. While in the database examples, I would be building out the rest of the CRUD (Create, Read, Update, Delete) methods to talk to the database.&lt;/p&gt;

&lt;p&gt;If you've already done web development in another language, the next stop I would recommend taking is to look at more of the &lt;strong&gt;ecosystem&lt;/strong&gt; of the programming language you did this challenge in. Like frameworks, package management, language idioms, and popular libraries for solving problems in web development.&lt;/p&gt;

&lt;p&gt;And regardless of experience level, I recommend checking out your programming language's &lt;strong&gt;community&lt;/strong&gt;, which in particular is great for networking (I got my first job in Go through networking at &lt;a href="https://meetup.com/bostongo"&gt;Boston Go&lt;/a&gt; in 2015!), getting familiar with other people's code in the language, and if you're looking to do public speaking in a new programming language, a meetup in that language is a great opportunity.&lt;/p&gt;

&lt;p&gt;Finally, I definitely encourage you to share your answers in your language on here, tweeting at me at @AndyHaskell2013, on GitHub, or anywhere else with the hashtag #WebDevSampler&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>webdevsampler</category>
      <category>codenewbie</category>
      <category>100devs</category>
    </item>
    <item>
      <title>#GopherDiggingRuby: Intro to blocks in Ruby</title>
      <dc:creator>Andy Haskell</dc:creator>
      <pubDate>Sat, 22 Jan 2022 21:27:05 +0000</pubDate>
      <link>https://dev.to/andyhaskell/gopherdiggingruby-intro-to-blocks-in-ruby-46bj</link>
      <guid>https://dev.to/andyhaskell/gopherdiggingruby-intro-to-blocks-in-ruby-46bj</guid>
      <description>&lt;p&gt;When you're coding in Ruby, one piece of syntax you'll see a lot of is &lt;strong&gt;blocks&lt;/strong&gt;, with either the curly braces or &lt;code&gt;do...end&lt;/code&gt; syntax. So in this tutorial, we will take a look at how we can use blocks as convenient feature of a Ruby developer's toolbelt, and how that compares to Go.&lt;/p&gt;

&lt;h2&gt;
  
  
  🐼 Looping over collections with Lola
&lt;/h2&gt;

&lt;p&gt;In Go, the idiomatic way to loop over a slice is with the &lt;code&gt;range&lt;/code&gt; keyword, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;doggoTricks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"roll over"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"speak"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"shake paws"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"toodle-oo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;trick&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;doggoTricks&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Lola! Can you %s?&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;trick&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;lola&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DoTrick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trick&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Good pupper! Have a biscuit! 🦴"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the for loop's top line, we loop over the &lt;code&gt;doggoTricks&lt;/code&gt; slice one item at a time, putting the current dog trick in the variable &lt;code&gt;trick&lt;/code&gt;. Then, inside the block, we use the &lt;code&gt;trick&lt;/code&gt; variable to tell my dog Lola to do that trick, and then she does the trick using the function &lt;code&gt;lola.DoTrick&lt;/code&gt;. And because of the curly braces block, the varable &lt;code&gt;trick&lt;/code&gt; is scoped to only exist inside the for loop.&lt;/p&gt;

&lt;p&gt;Ruby does have &lt;a href="https://www.geeksforgeeks.org/ruby-loops-for-while-do-while-until"&gt;loops of its own&lt;/a&gt;, but another cool, and in my opinion quite satisfying way of looping over a Ruby array is with the &lt;a href="https://ruby-doc.org/core-3.1.0/Array.html#method-i-each"&gt;Array#each method&lt;/a&gt;. Doing the same loop in Ruby looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;doggo_tricks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'roll over'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'speak'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'shake paws'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'toodle-oo'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;doggo_tricks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;trick&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Lola! Can you &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;trick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;?"&lt;/span&gt;
  &lt;span class="n"&gt;lola&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;do_trick&lt;/span&gt; &lt;span class="n"&gt;trick&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Good pupper! Have a biscuit! 🦴"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The part &lt;code&gt;do |trick| ... end&lt;/code&gt; is the block, and inside the pair of pipe (these &lt;code&gt;|&lt;/code&gt;) characters, you name the variable that's scoped to the block. Then, inside the block, you can use that variable, such as printing it with &lt;code&gt;puts&lt;/code&gt; and passing it into &lt;code&gt;lola.do_trick&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In addition to looping over arrays, there's also an &lt;a href="https://ruby-doc.org/core-3.1.0/Hash.html#method-i-each"&gt;each method for hashes&lt;/a&gt; that works similarly to looping over maps in Go. And &lt;code&gt;each&lt;/code&gt; isn't the only method that takes in a block; you can also use blocks on methods like &lt;code&gt;Array#sort&lt;/code&gt; to influence how an array is sorted, &lt;code&gt;Array#map&lt;/code&gt; to create a new array by running the code in the block on each item in the current array, and &lt;code&gt;Array#filter&lt;/code&gt; to return an array of only the items where the block's code would return true.&lt;/p&gt;

&lt;p&gt;As an example, if we had code like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;with_paws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doggo_tricks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;trick&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;uses_paws&lt;/span&gt; &lt;span class="n"&gt;trick&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then the &lt;code&gt;with_paws&lt;/code&gt; array would only have tricks where &lt;code&gt;uses_paws&lt;/code&gt; is true, which includes &lt;code&gt;toodle-oo&lt;/code&gt; and &lt;code&gt;shake paws&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you read &lt;a href="https://dev.to/andyhaskell/gopherdiggingruby-make-a-devto-link-fetcher-in-ruby-18mb"&gt;my last tutorial&lt;/a&gt; on building a dev.to fetcher in Ruby, by the way, a couple places where we used blocks in this way were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;with &lt;code&gt;Array.map&lt;/code&gt; to convert an array of Ruby hashes to an array of &lt;code&gt;Article&lt;/code&gt; objects&lt;/li&gt;
&lt;li&gt;walking a Markdown document's nodes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the way, toodle-oo is Lola's signature trick, and it's really cute!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--McuyiGnx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/82ba8xoox3525xy209sb.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--McuyiGnx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/82ba8xoox3525xy209sb.gif" alt="Animated gif of adorable black and white Havanese dog who looks like a panda standing on her hind legs and waving her front paws up and down" width="260" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🌺 Having an object only in the part of the code where you need it, as told by making a smoothie
&lt;/h2&gt;

&lt;p&gt;Another great use of blocks in your code is when you want to declare a variable, use it, and then do any clean-up code afterwards, like if you're opening a file, reading it into some kind of data structure, and then closing it when you no longer need that &lt;code&gt;File&lt;/code&gt; variable, for example. When a Ruby API has use cases following that pattern, blocks are a common way to do that pattern.&lt;/p&gt;

&lt;p&gt;As a more fun example, when it's a hot day out, nothing cools off a sloth like a refreshing hibiscus and cecropia leaf smoothie, fresh from the blender. Without blocks, the Ruby code would look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;blender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_blender&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;blender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ice cubes'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'hibiscus flowers'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'cecropia leaves'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;blender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;serve_drinks&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# now on to more Ruby code for the rest of a sloth's day! &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The one problem with this code is, the &lt;code&gt;blender&lt;/code&gt; variable is still in scope, and if this is in the middle of a long section of Ruby code, it's easy to forget to call &lt;code&gt;clean_up(blender)&lt;/code&gt; and &lt;code&gt;put_back(blender)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The Go approach to making sure that code gets called would be to either use &lt;code&gt;defer&lt;/code&gt; like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;blender&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;getBlender&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;cleanUp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blender&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;putBack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blender&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;blender&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ice cubes"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"hibiscus flowers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"cecropia leaves"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;blender&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServeDrinks&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c"&gt;// now on to more Ruby code for the rest of a sloth's day!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Go function in the &lt;code&gt;defer&lt;/code&gt; statement runs at the end of the Go code block we're in, so no matter what branches of code we take, &lt;code&gt;cleanUp(blender)&lt;/code&gt; and &lt;code&gt;putBack()&lt;/code&gt; blender will be called.&lt;/p&gt;

&lt;p&gt;For a Ruby approach with blocks, let's say that this &lt;code&gt;get_blender&lt;/code&gt; function had &lt;code&gt;clean_up(blender)&lt;/code&gt; and &lt;code&gt;put_back(blender)&lt;/code&gt; built-in. Then, the Ruby code for serving smoothies for sloths would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;get_blender&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;blender&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;blender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s1"&gt;'ice cubes'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'hibiscus flowers'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'cecropia leaves'&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;blender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;serve_drinks&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We put the code we want to run into the block, and use the variable &lt;code&gt;blender&lt;/code&gt; inside the block to add the ingredients and then serve the smoothies. Then, behind the scenes, &lt;code&gt;get_blender&lt;/code&gt; calls the cleanup code. The person using our blender API, and the people reviewing their code, don't need to pore over lines of code to make sure all the cleanup code is called, because that's built right in, saving time and bug fixes for your dev team!&lt;/p&gt;

&lt;p&gt;In my last tutorial on building a dev.to image link fetcher in Ruby, by the way, a couple places where we used blocks in this way were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sending an HTTP request to dev.to, deserializing the response from JSON, and then no longer needing the response body to be in-scope&lt;/li&gt;
&lt;li&gt;Generating a CSV file object, and then inside the block adding the image links as rows of the CSV&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🍹 Making your own functions that use blocks
&lt;/h2&gt;

&lt;p&gt;One final thing to look at for demystifying Ruby blocks, is how to make your own code that works with them. To do that, we use a keyword called &lt;code&gt;yield&lt;/code&gt;. This keyword confused me when I was first learning Rails, but essentially you can use &lt;code&gt;yield&lt;/code&gt; to do the pattern of:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run any code that's before the yield keyword&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;yield&lt;/code&gt; 0 or more Ruby objects that can be passed into the block&lt;/li&gt;
&lt;li&gt;Then, run any code past the yield keyword&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's try that out by giving the &lt;code&gt;get_blender&lt;/code&gt; function a definition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_blender&lt;/span&gt;
  &lt;span class="n"&gt;blender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;take_blender_out_of_cabinet&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;blender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plug_in&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;blender&lt;/span&gt;
  &lt;span class="n"&gt;clean_up&lt;/span&gt; &lt;span class="n"&gt;blender&lt;/span&gt;
  &lt;span class="n"&gt;put_away&lt;/span&gt; &lt;span class="n"&gt;blender&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We first run &lt;code&gt;take_blender_out_of_cabinet()&lt;/code&gt; and &lt;code&gt;blender.plug_in()&lt;/code&gt; to get the blender ready. Then, we run &lt;code&gt;yield blender&lt;/code&gt;. At that point, the coder using our blender can run a block that has the &lt;code&gt;blender&lt;/code&gt; passed in as a variable in the block's scope. We run that code, and then return to the body of the &lt;code&gt;get_blender&lt;/code&gt; function, where we call &lt;code&gt;clean_up blender&lt;/code&gt; and &lt;code&gt;put_away blender&lt;/code&gt; to clean up after the sloths enjoy a nice tasty smoothie!&lt;/p&gt;

&lt;p&gt;You don't need to necessarily just use a block once in a function, by the way. Remember how we used the Array &lt;code&gt;filter&lt;/code&gt; and &lt;code&gt;each&lt;/code&gt; methods with blocks that run on each item in an array? Let's say we had some prep work to do before putting the ingredients into the blender. Before blending the hibiscus flowers and cecropia leaves, let's wash them, which we can do by using &lt;code&gt;yield&lt;/code&gt; inside a loop, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Blender&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ingredients&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# do prep work for the smoothie here!&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ingredient&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ingredients&lt;/span&gt;
      &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;ingredient&lt;/span&gt;
      &lt;span class="n"&gt;add_ingredient_to_blender&lt;/span&gt; &lt;span class="n"&gt;ingredient&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now_make_the_smoothie!&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For each ingredient we pass into &lt;code&gt;add&lt;/code&gt;, we &lt;code&gt;yield&lt;/code&gt; the ingredient to the block passed in before putting it in the blender. Finally, with all that done, we &lt;code&gt;now_make_the_smoothie!&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;So now, the code for adding our smoothie ingredients would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;blender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s1"&gt;'ice cubes'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'hibiscus flowers'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'cecropia leaves'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;ingredient&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;need_to_wash?&lt;/span&gt; &lt;span class="n"&gt;ingredient&lt;/span&gt;
    &lt;span class="n"&gt;wash&lt;/span&gt; &lt;span class="n"&gt;ingredient&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the block we are using, we pass the ingredient into &lt;code&gt;need_to_wash?&lt;/code&gt;, and then wash the ones where &lt;code&gt;need_to_wash?&lt;/code&gt; returns true (ice cubes are already made of water to begin with so no need to wash them). We run the block for each ingredient one at a time, so with all our smoothie ingredients prepped and put in the blender, we finally call &lt;code&gt;blender.now_make_the_smoothies!&lt;/code&gt; to get refreshing hibiscus-cecropia smoothies to get just the energy you need for a long slothful day, brought to you by blocks!&lt;/p&gt;

&lt;p&gt;For more information about how &lt;code&gt;yield&lt;/code&gt; and &lt;code&gt;yield_self&lt;/code&gt;, I recommend looking at &lt;a href="https://www.rubyguides.com/2019/12/yield-keyword/"&gt;this blog post by RubyGuides&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>codenewbie</category>
      <category>beginners</category>
      <category>go</category>
    </item>
    <item>
      <title>#GopherDiggingRuby: Make a dev.to image link fetcher in Ruby</title>
      <dc:creator>Andy Haskell</dc:creator>
      <pubDate>Tue, 18 Jan 2022 05:59:16 +0000</pubDate>
      <link>https://dev.to/andyhaskell/gopherdiggingruby-make-a-devto-link-fetcher-in-ruby-18mb</link>
      <guid>https://dev.to/andyhaskell/gopherdiggingruby-make-a-devto-link-fetcher-in-ruby-18mb</guid>
      <description>&lt;p&gt;I write a lot of blog posts on dev.to and really like using Markdown for blogging. But one thing that would make the blogging process even more convenient, is if I had all the image links I've made on previous dev.to posts in one place for reusing images.&lt;/p&gt;

&lt;p&gt;So in this tutorial, I will show how we can use Ruby packages to make a CSV file of every image link in your blog posts from the command line, using the &lt;a href="https://docs.forem.com/api/"&gt;dev.to/Forem API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;💻 Send an authenticated request to the dev.to API with the standard library &lt;code&gt;net/http&lt;/code&gt; package and the Forem API&lt;/li&gt;
&lt;li&gt;🐈 Deserialize JSON into objects of a custom class with the standard library &lt;code&gt;json&lt;/code&gt; package&lt;/li&gt;
&lt;li&gt;💎 Retrieve the image links using the &lt;code&gt;commonmarker&lt;/code&gt; gem&lt;/li&gt;
&lt;li&gt;💼 Serialize objects into CSV files with the standard library &lt;code&gt;csv&lt;/code&gt; package&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This tutorial assumes you're familiar with JSON, HTTP requests, and the basics of Ruby.&lt;/p&gt;

&lt;h2&gt;
  
  
  Contacting the dev.to API
&lt;/h2&gt;

&lt;p&gt;The first thing you need in order to talk to a web API is an API &lt;strong&gt;client&lt;/strong&gt;. An API client is some code that sends authenticated HTTP requests to the web API. We can get a client in one of two ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Search for a Ruby Gem of a client for the dev.to/Forem APIs; a lot of people have made code repositories for talking to websites' APIs so that other people can use them.&lt;/li&gt;
&lt;li&gt;Make our own API client from scratch&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Since we're only talking to one HTTP endpoint on dev.to's API in this tutorial, we'll go with the second option. So let's jump to dev.to's &lt;a href="https://developers.forem.com/"&gt;API documentation&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;The endpoint we're talking to is the &lt;a href="https://developers.forem.com/api#operation/getUserArticles"&gt;User's Articles endpoint&lt;/a&gt;, which lists all articles belonging to the user calling that endpoint as JSON. Looking at the request and response samples on the right, we will find that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The request is a GET request to the endpoint &lt;code&gt;/articles/me&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The response is an array of JSON objects

&lt;ul&gt;
&lt;li&gt;Each JSON object in the array contains many fields for all the data representing the article, namely &lt;code&gt;title&lt;/code&gt; for the title of the article, and &lt;code&gt;body_markdown&lt;/code&gt; for the Markdown of the entire text of the article&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;The sample cURL request contacting that endpoint contains the header &lt;code&gt;api-key&lt;/code&gt;, which tells dev.to who you are and gives you access to your own account's data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So we need a client class that can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Send an HTTP request to the dev.to API's &lt;code&gt;/articles/me&lt;/code&gt; endpoint, with an API key as authentication&lt;/li&gt;
&lt;li&gt;Deserialize the JSON response to Ruby objects, giving us access to the fields we are interested in.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you're following along, make a folder for your Ruby app and write this code to &lt;code&gt;app.rb&lt;/code&gt; in that folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'net/http'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'json'&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DevToClient&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@api_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;api_key&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_my_articles&lt;/span&gt;
    &lt;span class="c1"&gt;# [TODO] Send HTTP request to /articles/me and deserialize&lt;/span&gt;
    &lt;span class="c1"&gt;# the JSON response&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have a &lt;code&gt;DevToClient&lt;/code&gt; class with two methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;initialize&lt;/code&gt; as its constructor. In the constructor, we pass in our API key, and it gets stored in the instance variable &lt;code&gt;@api_key&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get_my_articles&lt;/code&gt;, which will send an HTTP request to dev.to's &lt;code&gt;/articles/me&lt;/code&gt; endpoint that uses the &lt;code&gt;@api_key&lt;/code&gt; and deserialize the response&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now for getting the HTTP response. Looking at the documentation for &lt;code&gt;net/http&lt;/code&gt;, there is the method &lt;a href="https://ruby-doc.org/stdlib-3.0.1/libdoc/net/http/rdoc/Net/HTTP.html#method-c-get"&gt;HTTP.get_response&lt;/a&gt; for sending a GET request to the URL passed in and getting back an HTTP response.&lt;/p&gt;

&lt;p&gt;From the &lt;code&gt;get_response&lt;/code&gt; method's documentation, in addition to a URL, we also are able to optionally pass in a hash of any request headers we want to pass in. So we can pass in an &lt;code&gt;api-key&lt;/code&gt; header with this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_my_articles&lt;/span&gt;
    &lt;span class="no"&gt;Net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="no"&gt;URI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'https://dev.to/api/articles/me'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;'api-key'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="vi"&gt;@api_key&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We send the request to dev.to's &lt;code&gt;/api/articles/me&lt;/code&gt; endpoint with an &lt;code&gt;api-key&lt;/code&gt; header containing the value of the &lt;code&gt;DevToClient&lt;/code&gt;'s &lt;code&gt;@api_key&lt;/code&gt; instance variable.&lt;/p&gt;

&lt;p&gt;To run this, you are going to need to get your own API key for the dev.to API. To do that, first, make a dev.to account if you don't have one already. Then, you can get your API key by following &lt;a href="https://developers.forem.com/api#section/Authentication"&gt;the Authentication instructions on the dev.to API docs&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️WARNING!⚠️ For any web API you are working with, DO NOT share your API key or other forms of authentication with anyone; don't post it online or email it to your friends, and also don't commit it in your code! If someone else gets ahold of your API key, they will be able to impersonate you on that API and access your account data! If you suspect that someone has obtained one of your authentication keys or secrets, you should have that key/secret invalidated and then a fresh API key/secret created to protect your account.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, your save your API key to the environment variable &lt;code&gt;DEVTO_API_KEY&lt;/code&gt;. Then, at the bottom of &lt;code&gt;app.rb&lt;/code&gt;, add this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;api_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'DEVTO_API_KEY'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="no"&gt;DevToClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get_my_articles&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the code with &lt;code&gt;ruby app.rb&lt;/code&gt; and you should see terminal output like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#&amp;lt;Net::HTTPOK:0x00007fc20a92f800&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We got back a response of class &lt;a href="https://ruby-doc.org/stdlib-3.0.1/libdoc/net/http/rdoc/Net/HTTPOK.html"&gt;HTTPOK&lt;/a&gt; (which inherits from &lt;a href="https://ruby-doc.org/stdlib-3.0.1/libdoc/net/http/rdoc/Net/HTTPSuccess.html"&gt;HTTPSuccess&lt;/a&gt; and in turn inherits from &lt;a href="https://ruby-doc.org/stdlib-3.0.1/libdoc/net/http/rdoc/Net/HTTPResponse.html"&gt;HTTPResponse&lt;/a&gt;). So now we have our response, so let's parse it to make Ruby objects for each article.&lt;/p&gt;

&lt;h2&gt;
  
  
  JSON parsing in Ruby
&lt;/h2&gt;

&lt;p&gt;In addition to &lt;code&gt;net/http&lt;/code&gt;, the Ruby standard library has a &lt;a href="https://ruby-doc.org/stdlib-3.0.1/libdoc/json/rdoc/JSON.html"&gt;json&lt;/a&gt; package for serializing deserializing JSON, and inside that package there is the method &lt;a href="https://ruby-doc.org/stdlib-3.0.1/libdoc/json/rdoc/JSON.html#method-i-parse"&gt;JSON.parse&lt;/a&gt;. So if we did Ruby code like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;sloth_json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
{
    "sci_name":    "Bradypus",
    "common_name": "Three-toed sloth",
    "claw_count":  3
}
&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;

&lt;span class="n"&gt;sloth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sloth_json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;sci_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sloth&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"sci_name"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;common_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sloth&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"common_name"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;claw_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sloth&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"claw_count"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"The &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;sci_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;common_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;) has &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;claw_count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; claws"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then ran &lt;code&gt;ruby app.rb&lt;/code&gt;, we would get output like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The Bradypus (Three-toed sloth) has 3 claws
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The object returned from &lt;code&gt;JSON.parse&lt;/code&gt; is a Ruby hash, with its field names becoming the hash's keys.&lt;/p&gt;

&lt;p&gt;Let's try &lt;code&gt;JSON.parse&lt;/code&gt; to return a Ruby object from &lt;code&gt;DevToClient#get_my_articles&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_my_articles&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="no"&gt;URI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'https://dev.to/api/articles/me'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;'api-key'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="vi"&gt;@api_key&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;code&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;299&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;code&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
      &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="s2"&gt;"got status code &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;body&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, if we got a status code besides 2xx, we raise an error. Otherwise, we return the result of parsing the response body.&lt;/p&gt;

&lt;p&gt;If you then ran code like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="no"&gt;DevToClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get_my_articles&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;you will see that the Ruby object that the response body deserialized to was an array of Ruby hashes. So we could do something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;DevToClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get_my_articles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;md&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"body_markdown"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="c1"&gt;# now use a Markdown file to find every image link in&lt;/span&gt;
  &lt;span class="c1"&gt;# the article&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But what if we wanted a &lt;code&gt;DevToArticle&lt;/code&gt; class that handles digging for all the image links, and we wanted to deserialize our JSON to an array of &lt;code&gt;DevToArticles&lt;/code&gt; instead of hashes?&lt;/p&gt;

&lt;p&gt;Let's start by making a &lt;code&gt;DevToArticle&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DevToArticle&lt;/span&gt;
  &lt;span class="nb"&gt;attr_accessor&lt;/span&gt; &lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:body_markdown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:url&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;
    &lt;span class="c1"&gt;# [TODO] Add deserialization logic here&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_article_images&lt;/span&gt;
    &lt;span class="c1"&gt;# [TODO] Add Markdown parsing for the article's&lt;/span&gt;
    &lt;span class="c1"&gt;# @body_markdown&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since Ruby doesn't directly know if that the JSON it's getting is supposed to be a &lt;code&gt;DevToArticle&lt;/code&gt;, calling &lt;code&gt;JSON.parse&lt;/code&gt; will return an array of Ruby hashes. So we will need just a bit of extra logic for converting those hashes to &lt;code&gt;DevToArticle&lt;/code&gt;s.&lt;/p&gt;

&lt;p&gt;I wasn't sure how to do this at first; in Go, the main programming language I work with, I would be doing this using code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;DevToArticle&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ID&lt;/span&gt;           &lt;span class="kt"&gt;int&lt;/span&gt;    &lt;span class="s"&gt;`json:"id"`&lt;/span&gt;
    &lt;span class="n"&gt;Title&lt;/span&gt;        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"title"`&lt;/span&gt;
    &lt;span class="n"&gt;BodyMarkdown&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"body_markdown"`&lt;/span&gt;
    &lt;span class="n"&gt;URL&lt;/span&gt;          &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"url"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;DevToClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetMyArticles&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="n"&gt;DevToArticle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// get the HTTP response for the "user's articles" API&lt;/span&gt;
    &lt;span class="c"&gt;// endpoint here&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;articles&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;DevToArticle&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;articles&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;articles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I searched for how to deserialize to a custom class rather than a hash, and after asking about that on Twitter, Jamie Gaskins told me that there isn't really a standardized way in Ruby to deserialize to a class, but you are able to &lt;a href="https://twitter.com/jamie_gaskins/status/1483130085716725761"&gt;give your Ruby class an initialize method that takes in a hash&lt;/a&gt;. So based on that advice, in our &lt;code&gt;DevToArticle#initialize&lt;/code&gt; class, the deserialization logic would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="vi"&gt;@title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'title'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="vi"&gt;@body_markdown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'body_markdown'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="vi"&gt;@url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'url'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For each field we want an instance variable for, we just pull it out of the &lt;code&gt;attributes&lt;/code&gt; hash passed in.&lt;/p&gt;

&lt;p&gt;Note, by the way, that this also gives us control of the casing scheme for the deserialized objects. In Ruby, the standardized casing for instance variables is snake_case, and that's the casing the Forem API uses, but what if Forem was a camelCase API instead? &lt;code&gt;@body_markdown&lt;/code&gt; still is able to be snake_case even if &lt;code&gt;bodyMarkdown&lt;/code&gt; in the hash is camelCase:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;    &lt;span class="vi"&gt;@body_markdown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'bodyMarkdown'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, to have &lt;code&gt;DevToClient#get_my_articles&lt;/code&gt; return an array of &lt;code&gt;DevToArticle&lt;/code&gt;s instead of an array of hashes, we can do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;    &lt;span class="n"&gt;articles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;articles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;DevToArticle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="n"&gt;article&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By passing that block into &lt;code&gt;articles.map&lt;/code&gt;, we get back an array of &lt;code&gt;DevToArticle&lt;/code&gt;s created from each hash in the &lt;code&gt;articles&lt;/code&gt; array, so now &lt;code&gt;get_my_articles&lt;/code&gt; returns the type we want: an array of &lt;code&gt;DevToArticle&lt;/code&gt;s. Now let's jump into the Markdown of those articles all their image links!&lt;/p&gt;

&lt;h2&gt;
  
  
  Markdown parsing with commonmarker
&lt;/h2&gt;

&lt;p&gt;Unlike HTTP and JSON, the standard library in Ruby doesn't have a Markdown package, so we can either write our own Markdown parser, or use a Markdown-parsing Ruby Gem.&lt;/p&gt;

&lt;p&gt;And it turns out that there's a popular Ruby Gem that lets us parse a Markdown file and then walk over its nodes (nodes as in text, links, images, etc): &lt;a href="https://github.com/gjtorikian/commonmarker"&gt;CommonMarker&lt;/a&gt;! To get it, first run &lt;code&gt;bundle init&lt;/code&gt; to create a Gemfile, then in the Gemfile, add the line&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"commonmarker"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run &lt;code&gt;bundle install&lt;/code&gt;. If CommonMarker it successfully installs, you should be able to use it in your Ruby code.&lt;/p&gt;

&lt;p&gt;To start, add &lt;code&gt;require 'commonmarker'&lt;/code&gt; to the top of &lt;code&gt;app.rb&lt;/code&gt;, then in &lt;code&gt;DevToArticle#get_article_images&lt;/code&gt;, add this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_article_images&lt;/span&gt;
    &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;CommonMarker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render_doc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@body_markdown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:DEFAULT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you run that function in &lt;code&gt;app.rb&lt;/code&gt;, you will get output for an article like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#&amp;lt;CommonMarker::Node:0x00007fca8718f228&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;indicating that we were able to parse the Markdown in &lt;code&gt;@body_markdown&lt;/code&gt;, converting it to a &lt;code&gt;CommonMarker::Node&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;Following &lt;a href="https://www.gjtorikian.com/commonmarker/#label-Generating+a+document"&gt;this example in the CommonMarker documentation&lt;/a&gt;, we can walk over all the nodes in the document with code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_article_images&lt;/span&gt;
    &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;CommonMarker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render_doc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@body_markdown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:DEFAULT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;walk&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;type&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now in the &lt;code&gt;do&lt;/code&gt; block, we are looking at each &lt;code&gt;Node&lt;/code&gt; and seeing what type of node it is. So if you run this code, you might see output like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;text
code
text
paragraph
image
text
text
paragraph
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're only interested in &lt;code&gt;image&lt;/code&gt; nodes, so we'll add an if statement to check the node's type, which according to the documentation, is the Ruby symbol &lt;code&gt;:image&lt;/code&gt; according to the &lt;a href="https://www.gjtorikian.com/commonmarker/CommonMarker/Node.html#method-c-new"&gt;new(p1) docs&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;    &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;walk&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="ss"&gt;:image&lt;/span&gt;
        &lt;span class="c1"&gt;# [TODO] retrieve the node's content&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we're only processing image links. And a Markdown image link has two parts: descriptive alt text, which screen reader software reads when viewing images, and the URL of the image. So we need to find ways to get both of those.&lt;/p&gt;

&lt;p&gt;Looking at the CommonMarker documentation, the &lt;code&gt;Node&lt;/code&gt; method for getting the alt text is &lt;a href="https://www.gjtorikian.com/commonmarker/CommonMarker/Node.html#method-i-to_plaintext"&gt;to_plaintext&lt;/a&gt;, and the &lt;code&gt;Node&lt;/code&gt; method for getting the URL of the image is &lt;a href="https://www.gjtorikian.com/commonmarker/CommonMarker/Node.html#method-i-url"&gt;url&lt;/a&gt;. So now, we can return the parts to the image link:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_article_images&lt;/span&gt;
    &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;CommonMarker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render_doc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@body_markdown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:DEFAULT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;image_links&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;walk&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="ss"&gt;:image&lt;/span&gt;
        &lt;span class="n"&gt;image_links&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_plaintext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete_suffix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;image_links&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So now, we have all the data we'll need for serializing to a CSV file!&lt;/p&gt;

&lt;h2&gt;
  
  
  Serializing your image links to a CSV file
&lt;/h2&gt;

&lt;p&gt;The Ruby standard library also comes with a &lt;code&gt;csv&lt;/code&gt; package for parsing CSV files, or generating them from arrays of data. Each row will be one image link, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The alt text of the image link&lt;/li&gt;
&lt;li&gt;The URL of the image&lt;/li&gt;
&lt;li&gt;The ID of the article that the image link came from&lt;/li&gt;
&lt;li&gt;The title of the article that the image link came from&lt;/li&gt;
&lt;li&gt;The URL of the article that the image link came from&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So we will want CSV header text like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Alt Text,Image URL,Article ID,Article Title,Article URL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And for each row in the CSV, we will want an &lt;code&gt;DevToImageLink&lt;/code&gt; Ruby class to represent all the data in that row&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DevToImageLink&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image_alt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image_url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@article&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;article&lt;/span&gt;
    &lt;span class="vi"&gt;@image_alt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;image_alt&lt;/span&gt;
    &lt;span class="vi"&gt;@image_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;image_url&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;to_csv_row&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="vi"&gt;@image_alt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vi"&gt;@image_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vi"&gt;@article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vi"&gt;@article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vi"&gt;@article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;initialize&lt;/code&gt; method we pass in the &lt;code&gt;DevToArticle&lt;/code&gt; for the image link, and the alt text and URL of the image, to become instance variables. And in the &lt;code&gt;to_csv_row&lt;/code&gt; method, all of these fields are put into a Ruby array.&lt;/p&gt;

&lt;p&gt;Heading back to the &lt;code&gt;DevToArticle&lt;/code&gt; class, now that we have the &lt;code&gt;DevToImageLink&lt;/code&gt; class defined, let's have &lt;code&gt;DevToArticle#get_article_images&lt;/code&gt; return an array of &lt;code&gt;DevToImageLink&lt;/code&gt;s, rather than an array of arrays:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;      if node.type == :image
&lt;span class="gd"&gt;-       image_links.push [node.to_plaintext, node.url]
&lt;/span&gt;&lt;span class="gi"&gt;+       image_alt = node.to_plaintext
+       image_url = node.url
+       image_links.push DevToImageLink.new(self, image_alt, image_url)
&lt;/span&gt;      end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that that's all set, let's add a top-level &lt;code&gt;get_image_links_csv&lt;/code&gt; function that will convert our article to a CSV.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_image_links_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;CSV&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;csv&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="s1"&gt;'Alt Text'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'Image URL'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'Article ID'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'Article Title'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'Article URL'&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="no"&gt;DevToClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get_my_articles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_article_images&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;image_link&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="n"&gt;csv&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;image_link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_csv_row&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function &lt;code&gt;CSV.generate&lt;/code&gt; takes in a block and returns the CSV string generated in that block.&lt;/p&gt;

&lt;p&gt;In the first line inside the block, we pass in our CSV headers with the CSV's &lt;a href="https://ruby-doc.org/stdlib-3.0.1/libdoc/csv/rdoc/CSV.html#method-i-3C-3C"&gt;&amp;lt;&amp;lt; method&lt;/a&gt;, so they will serve as the first line of the CSV.&lt;/p&gt;

&lt;p&gt;Now, we loop over the image links in each of the articles returned by &lt;code&gt;DevToClient#get_my_articles&lt;/code&gt;. For each image link, we call the &lt;code&gt;DevToImageLink#to_csv_row&lt;/code&gt; method, and then load the returned array into the CSV.&lt;/p&gt;

&lt;p&gt;Finally, the return value of &lt;code&gt;CSV#generate&lt;/code&gt; is a string in CSV format. So now, we can use that code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;get_image_links_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using three standard library packages and a gem, we were able to make a convenient script for getting all our dev.to image links and converting them to a CSV. In my next Ruby tutorial, I will be looking at using a gem for giving this script a better user experience so it's easier to search the CSV for the image you want.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>codenewbie</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Convert images to mosaics in p5.js</title>
      <dc:creator>Andy Haskell</dc:creator>
      <pubDate>Sat, 01 Jan 2022 22:22:54 +0000</pubDate>
      <link>https://dev.to/andyhaskell/convert-images-to-mosaics-in-p5js-2dlc</link>
      <guid>https://dev.to/andyhaskell/convert-images-to-mosaics-in-p5js-2dlc</guid>
      <description>&lt;p&gt;p5.js is a fun JavaScript library for drawing on an HTML5 canvas, and it has &lt;a href="https://p5js.org/get-started/" rel="noopener noreferrer"&gt;some of the clearest tutorials I have seen&lt;/a&gt;. It gives you functionality for things like image manipulation, drawing lines and shapes, displaying images, working with trigonometry, and more. And it is especially popular for &lt;a href="https://dev.to/aspittel/intro-to-generative-art-2hi7"&gt;generative art&lt;/a&gt;, such as fractals.&lt;/p&gt;

&lt;p&gt;In this tutorial, I will show you how to use p5.js to convert an image like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcz8m78ut9yjsiamaki9g.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcz8m78ut9yjsiamaki9g.jpg" alt="Photograph of large boulders on the sand at Singing Beach in Manchester By The Sea. Behind them is the Atlantic Ocean, in many shades of blue"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;to a mosaic of dots like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1l2wy8sgh5y45yhm6hcg.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%2F1l2wy8sgh5y45yhm6hcg.png" alt="The same photograph of Singing Beach, converted to a mosaic of dots, rather than pixels. Each dot is the color of the pixel of the original image that's located at the center of that dot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This tutorial assumes a working knowledge of JavaScript and familiarity with pre-algebra, but prior knowledge of p5.js isn't strictly necessary. You can follow along on this by creating an account on the &lt;a href="https://editor.p5js.org/" rel="noopener noreferrer"&gt;p5.js online editor&lt;/a&gt; and logging in. The finished product can be found &lt;a href="https://editor.p5js.org/andyhaskell/sketches/fwaWSmAh_" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  📝 Making a first canvas
&lt;/h2&gt;

&lt;p&gt;As a basic p5.js program, let's start by making a canvas and drawing a single small dot there. We would do that by taking this code to the p5.js editor:&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;createCanvas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;ellipse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&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;We are starting with basic implementations two of the major functions in a p5.js program: &lt;code&gt;setup&lt;/code&gt; and &lt;code&gt;draw&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;setup&lt;/code&gt; function runs at the beginnng of a p5.js program, and what we're doing in it is calling &lt;a href="https://p5js.org/reference/#/p5/createCanvas" rel="noopener noreferrer"&gt;createCanvas&lt;/a&gt;, a built-in function from p5.js, to create a small HTML5 &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; element of width 300 and height 200.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;draw&lt;/code&gt; function runs repeatedly in the JavaScript event loop, and what we're doing is calling &lt;code&gt;ellipse&lt;/code&gt; to put a circle on the canvas, with a diameter of 15 pixels and its center at point &lt;code&gt;(50, 60)&lt;/code&gt; of that canvas. Remember at school plotting points on Cartesian coordinate grids in math class? That is the same concept here with drawing on a canvas. In fact, a lot of concepts from math class can be used as tools to make cool art!&lt;/p&gt;

&lt;p&gt;Now that we've got our setup and draw functions, press play on the p5.js editor, and you should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2x9ytz1h69mm9htikvha.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%2F2x9ytz1h69mm9htikvha.png" alt="Blank white canvas in the p5.js editor, with a single white circle with a black outline in its top left corner"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One key difference between the Cartesian grids in math class, and the ones in an HTML5 canvas, though, is that as you can see, point &lt;code&gt;(50, 60)&lt;/code&gt; is at the top-left of the canvas, not the bottom-left. Unlike in the graphs from math class, the y-axis on an HTML5 canvas goes from top to bottom, not bottom to top. The x-axis, though, still goes left to right.&lt;/p&gt;

&lt;p&gt;By the way, since we're only drawing our picture once rather than repeatedly (like if we were making an animated p5.js sketch), it's kind of pointless to call &lt;code&gt;draw&lt;/code&gt; repeatedly. So let's make it so we're only calling &lt;code&gt;draw&lt;/code&gt; once.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  function setup() {
    createCanvas(300, 200);
&lt;span class="gi"&gt;+   noLoop();
&lt;/span&gt;  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By adding a call to &lt;a href="https://p5js.org/reference/#/p5/noloop" rel="noopener noreferrer"&gt;noLoop&lt;/a&gt;, now after the first time we call &lt;code&gt;draw&lt;/code&gt;, we don't call &lt;code&gt;draw&lt;/code&gt; again unless our code calls &lt;a href="https://p5js.org/reference/#/p5/redraw" rel="noopener noreferrer"&gt;redraw&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Before we move on to loading an image, one other thing worth noting, circles/ellipses are not the only shape you can draw in p5. You can find code to draw other shapes, like lines, curves, rectangles, and more, in the links at &lt;a href="https://p5js.org/reference/#group-Shape" rel="noopener noreferrer"&gt;this reference&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  📷 Loading an image
&lt;/h2&gt;

&lt;p&gt;We've got our canvas made, but now we need a way of loading the image we're editing.&lt;/p&gt;

&lt;p&gt;First, in the p5 editor, left of the &lt;code&gt;sketch.js&lt;/code&gt; filename, click the right arrow to pop our the "sketch files" panel, click the down triangle on the line that says "sketch files", select "upload file" in the dropdown, and then upload your image.&lt;/p&gt;

&lt;p&gt;Now, to use the image, add the following code to the p5.js editor, adding a &lt;code&gt;preload&lt;/code&gt; function and replacing the &lt;code&gt;setup&lt;/code&gt; function:&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;preload&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;loadImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./beach.jpg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;createCanvas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;noLoop&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;The &lt;code&gt;preload&lt;/code&gt; function runs before &lt;code&gt;setup&lt;/code&gt; to load any assets needed for our p5.js program. What we're doing in our preload function is calling p5.js's &lt;a href="https://p5js.org/reference/#/p5/loadImage" rel="noopener noreferrer"&gt;loadImage&lt;/a&gt; function to load an image, represented in JavaScript as a &lt;a href="https://p5js.org/reference/#/p5.Image" rel="noopener noreferrer"&gt;p5.Image&lt;/a&gt; object, that we can manipulate. We store that Image in the &lt;code&gt;img&lt;/code&gt; global variable. Note that if you're using an image besides &lt;code&gt;beach.jpg&lt;/code&gt;, you'll want to change the name of the image you're loading in &lt;code&gt;loadImage&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, in &lt;code&gt;setup&lt;/code&gt;, we call &lt;code&gt;createCanvas&lt;/code&gt; like before, but now we use the &lt;code&gt;Image&lt;/code&gt; object to load the image. We then retrieve the image's width and height so the canvas we make is now the same size as the image.&lt;/p&gt;

&lt;p&gt;Now that we've got the image's width and height, and a canvas made in that size, we're going to switch over to drawing the dots on our mosaic.&lt;/p&gt;

&lt;h2&gt;
  
  
  🐆 Plotting the dots
&lt;/h2&gt;

&lt;p&gt;Circling back to our &lt;code&gt;draw&lt;/code&gt; function, let's replace that function's entire code with this:&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;drawMosaic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;drawMosaic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dotRadius&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// [TODO] Add code to put the dots on the mosaic!&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just like how in programming languages like Go, it's a good idea to have the &lt;code&gt;main&lt;/code&gt; relatively simple, I like having my &lt;code&gt;draw&lt;/code&gt; function be just a one-liner that calls the function that does the bulk of the action. We're going to have &lt;code&gt;drawMosaic&lt;/code&gt; be the central function of this program; it takes in the radius we want each dot to be, and it will be in charge of drawing all our dots.&lt;/p&gt;

&lt;p&gt;We want dots all over the picture, so let's break up the image into columns; each column will be about 1.5 times the width of a dot (3 times the radius), and will be filled top to bottom with dots. So we'll need to know:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How many columns the image will have&lt;/li&gt;
&lt;li&gt;With that knowledge, how to draw a column.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's start by just displaying a vertical line for each column. We'll get rid of the line later, but for now this is helpful as scaffolding, so if something is off about how we render the dots, such as what size they are, or where the dots are drawn, we can figure out what's being drawn in a given column relative to that column's lines.&lt;/p&gt;

&lt;p&gt;So let's add these functions:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;columnWidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dotRadius&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;dotRadius&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;3&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;numberOfColumns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dotRadius&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nf"&gt;columnWidth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dotRadius&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;drawColumnDots&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dotRadius&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;offsetX&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// [TODO] Replace the line with a column of dots&lt;/span&gt;
  &lt;span class="nf"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offsetX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;offsetX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;drawMosaic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dotRadius&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nf"&gt;numberOfColumns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dotRadius&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;offsetX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;columnWidth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dotRadius&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;drawColumnDots&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dotRadius&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;offsetX&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;Here's our functions so far:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;columnWidth&lt;/code&gt; is a helper function to get the width of a column. We have a column be triple the radius of a dot, so that we give each dot a bit of wiggle room as to where it will be drawn.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;numberOfColumns&lt;/code&gt; tells us how many columns of dots we can fit in the picture. Which is the width of the image divided by the width of a column.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;drawColumnDots&lt;/code&gt; will be in charge of adding all the dots to a given column, starting at the x-coordinate &lt;code&gt;offsetX&lt;/code&gt; we pass in and ending at &lt;code&gt;offsetX + dotRadius&lt;/code&gt;. For now, as scaffolding, we will just draw a straight vertical line at the left edge of the column.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;drawMosaic&lt;/code&gt; draws every column; we loop over the number of columns we have, and for each one we create a column that starts at the x-coordinate &lt;code&gt;i&lt;/code&gt; times the width of a column. For example, if we have a column width of 15, then the sixth column of dots (zero indexed, so i = 5) of the mosaic starts at an &lt;code&gt;offsetX&lt;/code&gt; of 75 pixels.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Press play on the p5.js editor, and you should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa2jf3d38vk737as67w0z.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%2Fa2jf3d38vk737as67w0z.png" alt="p5.js editor showing an HTML5 canvas displaying several vertical 1-pixel-wide black lines, indicating the left edge of each column of dots"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But we didn't come here to draw some vertical lines, we came here to draw some dots, so let's do that!&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;drawColumnDots&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dotRadius&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;offsetX&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// [TODO] Replace the line with a column of dots&lt;/span&gt;
  &lt;span class="nf"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offsetX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;offsetX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;dotDiameter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;dotRadius&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;dotHeightWithPadding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dotDiameter&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;numDotsInColumn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;dotHeightWithPadding&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;numDotsInColumn&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;centerX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;offsetX&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;dotRadius&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;offsetX&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;columnWidth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dotRadius&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;dotRadius&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;centerY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;dotHeightWithPadding&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;dotRadius&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;ellipse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;centerX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;centerY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dotDiameter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dotDiameter&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;Here's what happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, we declare variables for the diameter of a dot, and the height of each dot, with two pixels of padding so the dots aren't touching each other. We then divide the height of the image by &lt;code&gt;dotHeightWithPadding&lt;/code&gt; to get the number of dots in the column.&lt;/li&gt;
&lt;li&gt;Then, in the for loop, we will draw all the dots, from the top of the column to the bottom. First, we calculate the coordinates of the pixel at the center of the dot.

&lt;ul&gt;
&lt;li&gt;For the x-coordinate, the leftmost position a dot can be is &lt;code&gt;dotRadius&lt;/code&gt; pixels to the right of the start of the column. And the rightmost column is &lt;code&gt;dotRadius&lt;/code&gt; pixels to the left of the end of the column. So if a column is 15 pixels wide with a 5-pixel dot radius, we would randomly select an x-coordinate between 5 and 10 pixels to the right of the start of a column.&lt;/li&gt;
&lt;li&gt;For the y-coordinate, each dot is &lt;code&gt;dotHeightWithPadding&lt;/code&gt; pixels lower than the dot above it. We place the top dot's center at &lt;code&gt;dotRadius&lt;/code&gt; pixels below the top of the pixel, so that the top dots don't get cut off.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flblzf44av9d1n3kvz09d.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%2Flblzf44av9d1n3kvz09d.png" alt="Our HTML5 canvas. Now, in each column marked by the lines, there are black circle outlines a couple pixels apart from each other."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looks good, but we could use some randomness vertically too to so the dots aren't necessarily at the same height as the ones to the left and right of each other.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gi"&gt;+ let topY = Math.floor(random(10));
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  for (let i = 0; i &amp;lt; numDotsInColumn; i++) {
    let centerX = Math.floor(random(
      offsetX + dotRadius,
      offsetX + columnWidth(dotRadius) - dotRadius,
    ))
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gd"&gt;-   let centerY = i * dotHeightWithPadding + dotRadius;
&lt;/span&gt;&lt;span class="gi"&gt;+   let centerY = topY + i * dotHeightWithPadding + dotRadius;
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;    ellipse(centerX, centerY, dotDiameter, dotDiameter);
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwnpa6knrxs98f0ojo1lz.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%2Fwnpa6knrxs98f0ojo1lz.png" alt="Our HTML5 canvas. Now, the columns of dots start at different pixel positions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looks good! Before we go on to fill in the colors of the columns, remove the call to &lt;code&gt;line&lt;/code&gt;, since we no longer need that piece of scaffolding.&lt;/p&gt;

&lt;h2&gt;
  
  
  🎨 Giving the dots their colors
&lt;/h2&gt;

&lt;p&gt;The last step of drawing our mosaic is to color the dots. Each dot will be the same color as the color of the pixel at the center of the dot. Here's how we would do that:&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;dotColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;centerX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;centerY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;noStroke&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dotColor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;ellipse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;centerX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;centerY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dotDiameter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dotDiameter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, we use &lt;code&gt;Image.get&lt;/code&gt; to retrieve the color of the pixel at the coordinates &lt;code&gt;(centerX, centerY)&lt;/code&gt;. This is represented as an array of 4 numbers: red, green, blue, and alpha-transparency (how see-through a pixel is).&lt;/li&gt;
&lt;li&gt;We call &lt;a href="https://p5js.org/reference/#/p5/nostroke" rel="noopener noreferrer"&gt;noStroke&lt;/a&gt; to remove the outline on the dots, and we call &lt;a href="https://p5js.org/reference/#/p5/fill" rel="noopener noreferrer"&gt;fill&lt;/a&gt; to set the color of a dot.&lt;/li&gt;
&lt;li&gt;Finally, calling &lt;code&gt;ellipse&lt;/code&gt; draws the dot in the color we selected.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Press play on the p5.js editor, and now the canvas will look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj3i4elxpdz6htoyscq4j.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%2Fj3i4elxpdz6htoyscq4j.png" alt="Our canvas, now showing all the dots from earlier, but each dot's color is taken from the image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cool! One other thing I'd like to add though. This picture has a lot of light-colored pixels, so the dots would stand out better on a dark-colored background. So let's refactor &lt;code&gt;drawMosaic&lt;/code&gt; so that you can pick the color of the background.&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;drawMosaic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;drawMosaic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dotRadius&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;background&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// ... rest of the code in the function ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We add a new parameter &lt;code&gt;backgroundColor&lt;/code&gt; to our &lt;code&gt;drawMosaic&lt;/code&gt; function, and we pass that into &lt;a href="https://p5js.org/reference/#/p5/background" rel="noopener noreferrer"&gt;background&lt;/a&gt; to draw a background. In &lt;code&gt;draw&lt;/code&gt;, I picked the color &lt;code&gt;30, 30, 30&lt;/code&gt;; since red/green/blue go from 0 to 255, this gives us a charcoal-black background color. I also made the dot radius 10 pixels instead of 5 to make the picture feel more abstract. Run the play button on the sketch, and now the mosaic looks like this!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1l2wy8sgh5y45yhm6hcg.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%2F1l2wy8sgh5y45yhm6hcg.png" alt="Our canvas, now showing all the dots from earlier, but each dot's color is taken from the image, and the background the dots are on is charcoal black"&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We've made a cool piece of artwork with just 46 lines of code, but we've only scratched the surface of the kinds of art you can do with p5.js. If you had fun with this, you should check out the docs for more of p5's code, other people's sketches and YouTube videos for ideas on how you can work with p5 concepts, and check out your old notes from math class to see what other kinds of math, like trigonometry, can be used to make cool artwork!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>art</category>
      <category>tutorial</category>
      <category>codenewbie</category>
    </item>
  </channel>
</rss>
