<?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: Jordan Gregory</title>
    <description>The latest articles on DEV Community by Jordan Gregory (@j4ng5y).</description>
    <link>https://dev.to/j4ng5y</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%2F165010%2F77b2e639-7e86-4b15-aefb-b45e5cc27afe.jpeg</url>
      <title>DEV Community: Jordan Gregory</title>
      <link>https://dev.to/j4ng5y</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/j4ng5y"/>
    <language>en</language>
    <item>
      <title>Easy Access to Terminal Commands in Neovim using FTerm</title>
      <dc:creator>Jordan Gregory</dc:creator>
      <pubDate>Mon, 18 Mar 2024 13:26:14 +0000</pubDate>
      <link>https://dev.to/j4ng5y/easy-access-to-terminal-commands-in-neovim-using-fterm-468a</link>
      <guid>https://dev.to/j4ng5y/easy-access-to-terminal-commands-in-neovim-using-fterm-468a</guid>
      <description>&lt;p&gt;Have you ever found yourself having to switch contexts too many times in the course of using your favorite text editor Neovim? I certainly have.&lt;/p&gt;

&lt;p&gt;Having a common set of tools already set up in different windows or sessions in &lt;a href="https://github.com/tmux/tmux"&gt;Tmux&lt;/a&gt; or &lt;a href="https://github.com/zellij-org/zellij"&gt;Zellij&lt;/a&gt; is obviously an option, but there is a subset of us ( 👋 ) that would rather just have fingertip access to our common tools inside of our editor.&lt;/p&gt;

&lt;p&gt;This quick article will show you how to achieve such a state.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Setup
&lt;/h2&gt;

&lt;p&gt;Obviously, you should probably have Neovim installed and are somewhat familiar working with it.&lt;/p&gt;

&lt;p&gt;In my case, I have switched to &lt;a href="https://github.com/folke/lazy.nvim"&gt;Lazy.nvim&lt;/a&gt; for all of my Neovim plugin needs ( Thanks again Folke! ), so it would be great if you were at least minimally familiar with how Lazy works as well.&lt;/p&gt;

&lt;p&gt;The last thing you really need is a common set of tools that you want fingertip access to. I really commonly use &lt;a href="https://github.com/jesseduffield/lazygit"&gt;LazyGit&lt;/a&gt; and &lt;a href="https://github.com/derailed/k9s"&gt;K9s&lt;/a&gt; in my day job so those are the tools I will show off in this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Plugin
&lt;/h2&gt;

&lt;p&gt;To achieve our goals of fingertip access nirvana, we are going to be using a plugin called &lt;a href="https://github.com/numToStr/FTerm.nvim"&gt;FTerm.nvim&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want to see an exhaustive list of all the things you can do with FTerm, go check out the repository (and leave a star or whatever).&lt;/p&gt;

&lt;h2&gt;
  
  
  The How
&lt;/h2&gt;

&lt;p&gt;In typical Lazy.nvim fashion, we simply add a lua file in the normal plugins directory that looks like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- ~/.nvim/lua/plugins/fterm.lua&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s1"&gt;'numToStr/FTerm.nvim'&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 you save that, you now have access to FTerm as soon as you run &lt;code&gt;:Lazy&lt;/code&gt; or restart Neovim.&lt;/p&gt;

&lt;p&gt;The default state is not exactly ergonomic though because to launch it, you would need to run &lt;code&gt;:lua require("FTerm").toggle()&lt;/code&gt; to get it to show up, but now that we have access to the FTerm API, we can get all kinds of fancy with user commands or with custom keybindings as I will show here.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- ~/.nvim/lua/plugins/fterm.lua&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s1"&gt;'numToStr/FTerm.nvim'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;fterm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'FTerm'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;tt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;fterm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'[T]oggle [T]terminal'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'t'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;tt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;fterm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'[T]oggle [T]erminal'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;end&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 didn't add a whole lot, but now FTerm is a whole lot easier to get access to. While in &lt;code&gt;NORMAL&lt;/code&gt; (&lt;code&gt;n&lt;/code&gt;) mode, you simply have to press &lt;code&gt;&amp;lt;leader&amp;gt;tt&lt;/code&gt; to toggle open the floating terminal, and the same to toggle it closed assuming you are in that floating terminal (which is in &lt;code&gt;TERM&lt;/code&gt; (&lt;code&gt;t&lt;/code&gt;) mode).&lt;/p&gt;

&lt;p&gt;FTerm, by default, will simply open your &lt;code&gt;$SHELL&lt;/code&gt; which is great for a whole lot of reasons, but we are wanting direct access to a handful of terminal commands, so lets add them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- ~/.nvim/lua/plugins/fterm.lua&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s1"&gt;'numToStr/FTerm.nvim'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;fterm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'FTerm'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;tt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;fterm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'[T]oggle [T]terminal'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'t'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;tt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;fterm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'[T]oggle [T]erminal'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;end&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="s1"&gt;'numToStr/FTerm.nvim'&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="s1"&gt;'FTerm.LazyGit.nvim'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;fterm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'FTerm'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;lazygit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fterm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'lazygit'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;

      &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;lg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;lazygit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Toggle [L]azy[G]it'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'t'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;lg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;lazygit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Toggle [L]azy[G]it'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;end&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="s1"&gt;'numToStr/FTerm.nvim'&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="s1"&gt;'FTerm.k9s.nvim'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;fterm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'FTerm'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;k9s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fterm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'k9s'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;

      &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;tk'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;k9s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'[T]oggle [K]9s'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'t'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;tk'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;k9s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'[T]oggle [K]9s'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;end&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 things got just a little more complicated, but lets walk through it:&lt;/p&gt;

&lt;p&gt;Now we have 3 plugins being returned by the same lua file that I've called fterm.lua, but if you notice, they are all the same source, just renamed. This is how I am getting custom behavior.&lt;/p&gt;

&lt;p&gt;The first is just the behavior we defined before because I do still want access to just my &lt;code&gt;$SHELL&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The second renames the plugin from the default (FTerm.nvim) to &lt;code&gt;FTerm.LazyGit.nvim&lt;/code&gt; (this is just so Lazy doesn't smash all of the configs together in one directory and we get weird behavior). The last little bit we added was the custom command we want to run; &lt;code&gt;lazygit&lt;/code&gt; in this case. We then do basically the same thing as before, but with new keybindings to get easy access to our custom command.&lt;/p&gt;

&lt;p&gt;The third is a repeat of the second, but with &lt;code&gt;k9s&lt;/code&gt; rather than &lt;code&gt;lazygit&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In doing this, I now have access to &lt;code&gt;lazygit&lt;/code&gt; in a floating window just by typing &lt;code&gt;&amp;lt;leader&amp;gt;lg&lt;/code&gt; and access to &lt;code&gt;k9s&lt;/code&gt; in a floating window by typing &lt;code&gt;&amp;lt;leader&amp;gt;tk&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Feel free to rinse and repeat with your favorite commands 😄&lt;/p&gt;

&lt;p&gt;If you liked this content, let me know and I can create some more. Even better if you have a topic. Heck, maybe I'll even make a series.&lt;/p&gt;

</description>
      <category>neovim</category>
      <category>vim</category>
      <category>editor</category>
    </item>
    <item>
      <title>Writing a Rust CLI to complete the DigitalOcean Functions Challenge</title>
      <dc:creator>Jordan Gregory</dc:creator>
      <pubDate>Wed, 15 Jun 2022 04:24:44 +0000</pubDate>
      <link>https://dev.to/j4ng5y/writing-a-rust-cli-to-complete-the-digitalocean-functions-challenge-560k</link>
      <guid>https://dev.to/j4ng5y/writing-a-rust-cli-to-complete-the-digitalocean-functions-challenge-560k</guid>
      <description>&lt;h1&gt;
  
  
  Prelude
&lt;/h1&gt;

&lt;p&gt;To continue from my &lt;a href="https://dev.to/j4ng5y/writing-a-go-cli-to-complete-the-digital-ocean-functions-challenge-3372"&gt;Go CLI write-up&lt;/a&gt; and my &lt;a href="https://dev.to/j4ng5y/writing-a-python-cli-to-complete-the-digitalocean-functions-challenge-1e29"&gt;Python CLI Write-up&lt;/a&gt;, I will go in to detail about writing a Rust CLI to perform the same &lt;a href="https://functionschallenge.digitalocean.com"&gt;DigitalOcean Functions Challenge&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Code
&lt;/h2&gt;

&lt;p&gt;I'm sensing a theme here, but much like my last two write-ups, I simply threw everything into the &lt;code&gt;main.rs&lt;/code&gt; file that was created with the &lt;code&gt;cargo new sharks&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;First things first, if you have done any development with Rust that accesses the web via JSON, there are a few essential crates to grab:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.rs/reqwest/0.9.18/reqwest/"&gt;Reqwest&lt;/a&gt; is a crate that makes sending web requests simple, and even though I used the blocking client, you can use &lt;a href="https://docs.rs/tokio/1.19.2/tokio/"&gt;Tokio&lt;/a&gt; to &lt;a href="https://docs.rs/reqwest/0.9.18/reqwest/async/index.html"&gt;make Reqwest asynchronous&lt;/a&gt; just as simply.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.rs/serde/1.0.137/serde/"&gt;Serde&lt;/a&gt; / &lt;a href="https://docs.rs/serde_json/1.0.81/serde_json/"&gt;serde_json&lt;/a&gt;  / &lt;a href="https://docs.rs/serde_derive/1.0.137/serde_derive/"&gt;serde_derive&lt;/a&gt; are obvious choices for serialization/deserialization.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For the CLI, I personally like to use &lt;a href="https://docs.rs/structopt/0.3.26/structopt/"&gt;Structopt&lt;/a&gt;, but feel free to use whatever you are comfortable with.&lt;/p&gt;

&lt;p&gt;My &lt;code&gt;Cargo.toml&lt;/code&gt; dependencies look like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[dependencies]&lt;/span&gt;
&lt;span class="nn"&gt;structopt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.3"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nn"&gt;reqwest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.11"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"blocking"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"json"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
&lt;span class="nn"&gt;serde&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.0"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nn"&gt;serde_json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.0"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nn"&gt;serde_derive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.0"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, knowing that I want something similar to my previous two write-ups, I started with the API URL constant and some Request and Response structs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/main.rs&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;serde_derive&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Serialize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;Deserialize&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;API_URL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://functionschallenge.digitalocean.com/api/sammy"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Obviously, the serialize trait needs to be here so that&lt;/span&gt;
&lt;span class="c1"&gt;// we can turn this into JSON later. I usually use debug here&lt;/span&gt;
&lt;span class="c1"&gt;// as well just in case I need to do a little println!&lt;/span&gt;
&lt;span class="c1"&gt;// debugging.&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Debug,&lt;/span&gt; &lt;span class="nd"&gt;Serialize)]&lt;/span&gt;
&lt;span class="k"&gt;struct&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="c1"&gt;// Because of the type keyword, we needed to name this&lt;/span&gt;
    &lt;span class="c1"&gt;// field something other than type, so _type suits me&lt;/span&gt;
    &lt;span class="c1"&gt;// just fine, but we have to tell serde that we want to&lt;/span&gt;
    &lt;span class="c1"&gt;// rename this field when we go to actually serialize&lt;/span&gt;
    &lt;span class="c1"&gt;// the JSON.&lt;/span&gt;
    &lt;span class="nd"&gt;#[serde(rename(serialize&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"type"&lt;/span&gt;&lt;span class="nd"&gt;))]&lt;/span&gt;
    &lt;span class="n"&gt;_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Again, and obvious deserialize trait needed with the&lt;/span&gt;
&lt;span class="c1"&gt;// response. And again, the almost obligatory Debug trait.&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Debug,&lt;/span&gt; &lt;span class="nd"&gt;Deserialize)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="c1"&gt;// In this case, we need to tell serde to give us the&lt;/span&gt;
    &lt;span class="c1"&gt;// "zero" value of a HashMap&amp;lt;String,Vec&amp;lt;String&amp;gt;&amp;gt; because&lt;/span&gt;
    &lt;span class="c1"&gt;// a successful response will not have this field, and&lt;/span&gt;
    &lt;span class="c1"&gt;// will cause the app to panic because this field doesn't &lt;/span&gt;
    &lt;span class="c1"&gt;// get used.&lt;/span&gt;
    &lt;span class="nd"&gt;#[serde(default)]&lt;/span&gt;
    &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And for the request/response, this is really all we need to do.&lt;/p&gt;

&lt;p&gt;Now, I'll set up the CLI struct really fast:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/main.rs&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;structopt&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;StructOpt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="c1"&gt;// I went ahead and created a "possible values" constant here&lt;/span&gt;
&lt;span class="c1"&gt;// so that we have the CLI filter our sammy type input for us.&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;TYPE_VALUES&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s"&gt;"sammy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"punk"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"dinosaur"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"retro"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"pizza"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"robot"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"pony"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"bootcamp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"xray"&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="c1"&gt;// In classic fashion, we have to derive the structopt trait&lt;/span&gt;
&lt;span class="c1"&gt;// as well as the obligatory debug trait. The additional&lt;/span&gt;
&lt;span class="c1"&gt;// structopt config follows it.&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Debug,&lt;/span&gt; &lt;span class="nd"&gt;StructOpt)]&lt;/span&gt;
&lt;span class="nd"&gt;#[structopt(name&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"sharks"&lt;/span&gt;&lt;span class="nd"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;version&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.1.0"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Opt&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;#[structopt(long&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;sammy_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="nd"&gt;#[structopt(long&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"type"&lt;/span&gt;&lt;span class="nd"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;possible_values(TYPE_VAULES))]&lt;/span&gt;
    &lt;span class="n"&gt;sammy_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&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 all we have to do is pull it all together in the &lt;code&gt;main()&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/main.rs&lt;/span&gt;

&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Build the opt struct from the arguments provided&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Opt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Opt&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_args&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Build a new request from those arguments&lt;/span&gt;
    &lt;span class="k"&gt;let&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;Request&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="c1"&gt;// notice the clones here, I needed that values later&lt;/span&gt;
        &lt;span class="c1"&gt;// in the output, so this was just the most painless&lt;/span&gt;
        &lt;span class="c1"&gt;// way to not fight the borrow checker :D&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;opt&lt;/span&gt;&lt;span class="py"&gt;.sammy_name&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="py"&gt;.sammy_type&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="c1"&gt;// Grab a new blocking client. I don't care if this&lt;/span&gt;
    &lt;span class="c1"&gt;// blocks because of what this app is and does, but&lt;/span&gt;
    &lt;span class="c1"&gt;// you may care more. Feel free to try this async.&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;reqwest&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;blocking&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Client&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="c1"&gt;// Build the JSON from our Request struct&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;resp_body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;serde_json&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;to_string&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;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Send the request&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="nf"&gt;.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;API_URL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ACCEPT"&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="c1"&gt;// Set a header&lt;/span&gt;
        &lt;span class="nf"&gt;.header&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="c1"&gt;// Set a header&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;resp_body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Set the body&lt;/span&gt;
        &lt;span class="nf"&gt;.send&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// Send it&lt;/span&gt;
        &lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to get response"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Don't fail&lt;/span&gt;
        &lt;span class="nf"&gt;.json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// Convert response to JSON&lt;/span&gt;
        &lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to get payload"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Don't fail&lt;/span&gt;

    &lt;span class="c1"&gt;// Here, I'm just doing a little error checking to see if&lt;/span&gt;
    &lt;span class="c1"&gt;// something exists. There are obviously far nicer ways&lt;/span&gt;
    &lt;span class="c1"&gt;// to do this, but again, this was fast and accomplished&lt;/span&gt;
    &lt;span class="c1"&gt;// the goal.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="py"&gt;.errors&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ERROR: {:#?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="py"&gt;.errors&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="c1"&gt;// Give us a success message if it worked!&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Successfully created Sammy: {} of type {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="py"&gt;.sammy_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="py"&gt;.sammy_type&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;With all this written down, now we can just do a &lt;code&gt;cargo run -- --name &amp;lt;your sammy name&amp;gt; --type &amp;lt;your sammy type&amp;gt;&lt;/code&gt; and it works as expected.&lt;/p&gt;

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

&lt;p&gt;Like usual, if you want to see the full file, feel free to check it out on the repository here:&lt;br&gt;
&lt;a href="https://github.com/j4ng5y/digitalocean-functions-challenge/tree/main/rust"&gt;https://github.com/j4ng5y/digitalocean-functions-challenge/tree/main/rust&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>digitalocean</category>
      <category>serverless</category>
      <category>api</category>
    </item>
    <item>
      <title>Writing a Python CLI to complete the DigitalOcean Functions Challenge</title>
      <dc:creator>Jordan Gregory</dc:creator>
      <pubDate>Mon, 13 Jun 2022 19:38:19 +0000</pubDate>
      <link>https://dev.to/j4ng5y/writing-a-python-cli-to-complete-the-digitalocean-functions-challenge-1e29</link>
      <guid>https://dev.to/j4ng5y/writing-a-python-cli-to-complete-the-digitalocean-functions-challenge-1e29</guid>
      <description>&lt;h1&gt;
  
  
  Prelude
&lt;/h1&gt;

&lt;p&gt;To continue from my &lt;a href="https://dev.to/j4ng5y/writing-a-go-cli-to-complete-the-digital-ocean-functions-challenge-3372"&gt;Go CLI write-up&lt;/a&gt;, I will go in to detail about writing a Python CLI to perform the same &lt;a href="https://functionschallenge.digitalocean.com"&gt;DigitalOcean Functions Challenge&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Code
&lt;/h2&gt;

&lt;p&gt;Like the Go code I wrote earlier, I just threw everything into &lt;code&gt;main.py&lt;/code&gt; for this example, so to get started, I simply created a main.py file and installed the first few dependencies I knew I wanted to use with &lt;a href="https://pipenv.pypa.io/en/latest/index.html"&gt;Pipenv&lt;/a&gt; like so:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pipenv install requests structlog click&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://requests.readthedocs.io/en/latest/"&gt;Requests&lt;/a&gt; I always use when I have to interface with the web in Python applications.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.structlog.org/en/stable/"&gt;Structlog&lt;/a&gt; is my structured logging package of choice for Python applications.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://click.palletsprojects.com/en/8.1.x/"&gt;Click&lt;/a&gt; is my CLI framework of choice for Python applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In doing this, now I have a Pipfile and a Pipfile.lock and can go about doing my actually development.&lt;/p&gt;

&lt;p&gt;First, I knew I wanted to have a Request and a Response class defined, and knowing what I know from the previous example, I was able to just write the classes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;structlog&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;click&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    The Request class will contain all of our methods to handle a request to the DigitalOcean Function Challenge api.

    Attributes
    ----------
    API_URL : str
        The API_URL attribute is a static string to hold the URL of the API to access.

    name: str
        The name attribute is the name of the Sammy that we wish to create.

    t : str
        The &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;t&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; attribute is the type of the Sammy that we wish to create. This attribute is named &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;t&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; to avoid
        conflicting with the &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; keywork.

    log : structlog.BoundLogger
        The log attribute is not an attribute to be dealt with directly, rather the _get_log(self) method will retrieve
        the bound logger for us.

    Methods
    -------
    _set_name(name: str)
        This method sets the value of the name attribute.

    _set_type(t: str)
        This method sets the value of the t attribute.

    _set_log()
        This method gets the application logger and sets it to the log attribute.

    _get_url() -&amp;gt; str
        This method returns the value of the API_URL attribute.

    _get_name() -&amp;gt; str
        This method returns the value of the name attribute.

    _get_type() -&amp;gt; str
        This method returns the value of the t attribute.

    _build_headers() -&amp;gt; dict
        This static method returns a dictionary to be used as a request header.

    _build_request_body() -&amp;gt; dict
        This method returns a dictionary to be used as the request body.

    do() -&amp;gt; requests.Response
        This method is the primary class method and is used to perform the HTTP POST request.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&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="nb"&gt;str&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="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        Parameters
        ----------
        :param name: str
            The name to give to your new Sammy.
        :param t: str
            The type to give to your new Sammy.
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;API_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://functionschallenge.digitalocean.com/api/sammy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="n"&gt;self&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="bp"&gt;None&lt;/span&gt;
        &lt;span class="n"&gt;self&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="bp"&gt;None&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;structlog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BoundLogger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_set_name&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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_set_type&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="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_set_log&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_set_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&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="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;This method sets the value of the name attribute.

        Parameters
        ----------
        :param name: str
            The name of the new sammy to create.
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="n"&gt;self&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;name&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_set_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&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="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;This method sets the value of the t attribute.

        Input validation is handled at the CLI layer. We will need to do further input validation if we don&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t do the
        validation at the CLI layer.

        Parameters
        ----------
        :param t: str
            The type of the new sammy to create.
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="n"&gt;self&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;t&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_set_log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;This method gets the application logger and sets it to the log attribute.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;structlog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_logger&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_get_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&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;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;This method returns the value of the API_URL attribute.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;API_URL&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_get_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&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;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;This method returns the value of the name attribute.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_get_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&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;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;This method returns the value of the t attribute.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_build_request_body&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&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;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;This method returns a dictionary to be used as the request body.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;self&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;self&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="p"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_build_headers&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;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;This static method returns a dictionary to be used as a request header.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Accept&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;This method is the primary class method and is used to perform the HTTP POST request.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_get_url&lt;/span&gt;&lt;span class="p"&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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_build_request_body&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_build_headers&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    The Response class will contain all of our methods to handle a response from the DigitalOcean Functions Challenge
    api.

    Attributes
    ----------
    resp : requests:Response
        The actual response that is retrieved from performing the do() function from our Request class.
    log: : structlog.BoundLogger
        The log attribute is not an attribute to be dealt with directly, rather the _get_log(self) method will retrieve
        the bound logger for us.

    Methods
    -------
    _set_log() -&amp;gt; None
        Gets the application logger.

    _get_status_code() -&amp;gt; int
        Gets the HTTP status code from the requests.Response object the class was initialized with.

    _has_errors() -&amp;gt; bool
        A helper to let us know if errors exist in the requests.Response object the class was initialized with.

    do() -&amp;gt; None
        The primary method of this class. Do is used to print the information from the response to the terminal.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        Parameters
        ----------
        :param resp: requests.Response
            A response object from our Request class do() method.
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;structlog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BoundLogger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_set_log&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_set_log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Gets the application logger.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;structlog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_logger&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_get_status_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&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;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Gets the HTTP status code from the requests.Response object the class was initialized with.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_has_errors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&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;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;A helper to let us know if errors exist in the requests.Response object the class was initialized with.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="n"&gt;respj&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;errors&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;respj&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;The primary method of this class. Do is used to print the information from the response to the terminal.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_has_errors&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;e&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;errors&lt;/span&gt;&lt;span class="sh"&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;ee&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;errors&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
                    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ee&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;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Notice the shebang at the top of the file. I personally like to do this with Python applications so I can call the file directly. In doing this though, you have to provide the file with the appropriate permissions to run. In my case (on a unix-like OS), I just had to run &lt;code&gt;chmod +x main.py&lt;/code&gt; to allow it to run.&lt;/p&gt;

&lt;p&gt;Now we have a few classes to handle our request and our response.&lt;/p&gt;

&lt;p&gt;I wanted structlog to handle things a little more json-y for me, so I needed to add a logger configuration function as well like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="bp"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;configure_logger&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Basic application level logging configuration&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basicConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%(message)s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;structlog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;processors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="n"&gt;structlog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;processors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_log_level&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;structlog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;processors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;JSONRenderer&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;logger_factory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;structlog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LoggerFactory&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 our logger is configured, all we had to do pull it all together with a CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@click.command&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nd"&gt;@click.option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;-n&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;The name to give to your new Sammy.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@click.option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;-t&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--type&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;t&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;click&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Choice&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sammy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;punk&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dinosaur&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;retro&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pizza&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;robot&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pony&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bootcamp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;xray&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;case_sensitive&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;The type to give to your new Sammy.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&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;t&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;configure_logger&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Request&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;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;do&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;do&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;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Again, notice the &lt;code&gt;if __name__ == "__main__"&lt;/code&gt; statement, this is just the line that says "Do this if the file is called directly".&lt;/p&gt;

&lt;p&gt;Really all this &lt;code&gt;main()&lt;/code&gt; function does (with the help of some Click decorators), is to set the &lt;code&gt;name&lt;/code&gt; flag, the &lt;code&gt;t&lt;/code&gt; flag for the type, and then run our functions as we have designed them.&lt;/p&gt;

&lt;p&gt;Running our new app is a simple as &lt;code&gt;./main.py --name &amp;lt;my name&amp;gt; --type &amp;lt;my type&amp;gt;&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Like usual, if you want to see the full file, feel free to check it out on the repository here:&lt;br&gt;
&lt;a href="https://github.com/j4ng5y/digitalocean-functions-challenge/tree/main/python"&gt;https://github.com/j4ng5y/digitalocean-functions-challenge/tree/main/python&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>digitalocean</category>
      <category>serverless</category>
      <category>api</category>
    </item>
    <item>
      <title>Writing a Go CLI to complete the DigitalOcean Functions Challenge</title>
      <dc:creator>Jordan Gregory</dc:creator>
      <pubDate>Thu, 09 Jun 2022 15:39:23 +0000</pubDate>
      <link>https://dev.to/j4ng5y/writing-a-go-cli-to-complete-the-digital-ocean-functions-challenge-3372</link>
      <guid>https://dev.to/j4ng5y/writing-a-go-cli-to-complete-the-digital-ocean-functions-challenge-3372</guid>
      <description>&lt;h1&gt;
  
  
  The Challenge
&lt;/h1&gt;

&lt;p&gt;DigitalOcean released their version of &lt;a href="https://docs.digitalocean.com/products/functions"&gt;serverless functions&lt;/a&gt; and &lt;a href="https://functionschallenge.digitalocean.com"&gt;released a challenge&lt;/a&gt; recently to showcase them as well. Being one that doesn't like to turn down a challenge, I took DigitalOcean up on their challenge with a Go CLI.&lt;/p&gt;

&lt;h1&gt;
  
  
  Getting started
&lt;/h1&gt;

&lt;p&gt;First, it was pretty simple to read the challenge on the &lt;a href="https://functionschallenge.digitalocean.com"&gt;challenge website&lt;/a&gt;, but it left a few questions to be answered.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;Content-Type&lt;/code&gt; and &lt;code&gt;Accepted&lt;/code&gt; headers tell me that this application accepts and sends back JSON data, but the directions in the overall documentation don't really say that other than that a parameters file is a JSON document, but I went ahead and wrote my CLI as thought the API did accept and send back JSON. I was correct, but the documentation here wasn't entirely clear.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once you have deployed you "Sammy" (or your DigitalOcean mascot). You have to have a keen eye to catch it. If you don't believe it's there, you can easily inspect the page elements for something that looks like the Sammy that you created.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  The Code
&lt;/h1&gt;

&lt;p&gt;In this case, as this was just a throw away app, I just wrote everything into a &lt;code&gt;main.go&lt;/code&gt; file and turns on modules with &lt;code&gt;go mod init &amp;lt;github.com/your_handle/project_name&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The first thing to do was to start with a CLI that would accept the &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;type&lt;/code&gt; parameters as described in the instructions. I opted to put these flags in the &lt;code&gt;init&lt;/code&gt; function and load a few module variables so I didn't really have to do much with them and I expected them to run each time the app was run.&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;// main.go&lt;/span&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;"flag"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;sammyname&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;sammytype&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;const&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;API_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://functionschallenge.digitalocean.com/api/sammy"&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;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StringVar&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;sammyname&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="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"The name to give your new Sammy."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StringVar&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;sammytype&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"type"&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="s"&gt;"The type to assign to your new Sammy."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;flag&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running our app with &lt;code&gt;go run main.go&lt;/code&gt; now gives us our command line flags.&lt;/p&gt;

&lt;p&gt;After looking again at the docs, the Sammy Type parameter is really a enum, so I created a type and a few helper functions and used them to set the variable appropriately.&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;// main.go&lt;/span&gt;
&lt;span class="o"&gt;...&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;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"flag"&lt;/span&gt;
    &lt;span class="s"&gt;"strings"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;sammyname&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;sammytype&lt;/span&gt; &lt;span class="n"&gt;sammyType&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="n"&gt;sammyType&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;const&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;API_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://functionschallenge.digitalocean.com/api/sammy"&lt;/span&gt;

    &lt;span class="n"&gt;sammyType_Sammy&lt;/span&gt; &lt;span class="n"&gt;sammyType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"sammy"&lt;/span&gt;
    &lt;span class="n"&gt;sammyType_Punk&lt;/span&gt; &lt;span class="n"&gt;sammyType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"punk"&lt;/span&gt;
    &lt;span class="n"&gt;sammyType_Dinosaur&lt;/span&gt; &lt;span class="n"&gt;sammyType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"dinosaur"&lt;/span&gt;
    &lt;span class="n"&gt;sammyType_Retro&lt;/span&gt; &lt;span class="n"&gt;sammyType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"retro"&lt;/span&gt;
    &lt;span class="n"&gt;sammyType_Pizza&lt;/span&gt; &lt;span class="n"&gt;sammyType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"pizza"&lt;/span&gt;
    &lt;span class="n"&gt;sammyType_Robot&lt;/span&gt; &lt;span class="n"&gt;sammyType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"robot"&lt;/span&gt;
    &lt;span class="n"&gt;sammyType_Pony&lt;/span&gt; &lt;span class="n"&gt;sammyType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"pony"&lt;/span&gt;
    &lt;span class="n"&gt;sammyType_Bootcamp&lt;/span&gt; &lt;span class="n"&gt;sammyType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"bootcamp"&lt;/span&gt;
    &lt;span class="n"&gt;sammyType_XRay&lt;/span&gt; &lt;span class="n"&gt;sammyType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"xray"&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;NewSammyType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&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="n"&gt;sammyType&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="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="n"&gt;sammyType&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;s&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;"sammy"&lt;/span&gt;&lt;span class="o"&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;sammyType_Sammy&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"punk"&lt;/span&gt;&lt;span class="o"&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;sammyType_Punk&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"dinosaur"&lt;/span&gt;&lt;span class="o"&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;sammyType_Dinosaur&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"retro"&lt;/span&gt;&lt;span class="o"&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;sammyType_Retro&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"pizza"&lt;/span&gt;&lt;span class="o"&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;sammyType_Pizza&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"robot"&lt;/span&gt;&lt;span class="o"&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;sammyType_Robot&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"pony"&lt;/span&gt;&lt;span class="o"&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;sammyType_Pony&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"bootcamp"&lt;/span&gt;&lt;span class="o"&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;sammyType_Bootcamp&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"xray"&lt;/span&gt;&lt;span class="o"&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;sammyType_XRay&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="s"&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;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%s is an invalid sammyType"&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="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;t&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;s&lt;/span&gt; &lt;span class="n"&gt;sammyType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;String&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="kt"&gt;string&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="p"&gt;}&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="n"&gt;flag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StringVar&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;sammyname&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="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"The name to give your new Sammy."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;st&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;flag&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="s"&gt;"type"&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="s"&gt;"The type to assign to your new Sammy."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;flag&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;sammyType&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;NewSammyType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;st&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;log&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="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="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we had something that is type correct for the API.&lt;br&gt;
Next, I simply wrote in a struct to represent the request, as well as a few helper functions there as well.&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;// main.go&lt;/span&gt;
&lt;span class="o"&gt;...&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;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"flag"&lt;/span&gt;
    &lt;span class="s"&gt;"strings"&lt;/span&gt;
    &lt;span class="s"&gt;"bytes"&lt;/span&gt;
    &lt;span class="s"&gt;"encoding/json"&lt;/span&gt;
    &lt;span class="s"&gt;"io"&lt;/span&gt;
    &lt;span class="s"&gt;"io/ioutil"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;sammyType&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;

    &lt;span class="n"&gt;sharksRequest&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;Type&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// func NewSharksRequest() is something that I normally write, but there was really no point in this case.&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;req&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sharksRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;setName&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="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sharksRequest&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&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;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;req&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sharksRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;setType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="n"&gt;sammyType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sharksRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="o"&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;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;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sharksRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;marshalJSON&lt;/span&gt;&lt;span class="p"&gt;()&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="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="k"&gt;return&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;Marshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we had something to send to the API. So it was just a matter of sending a request, and seeing what the output was as the output wasn't documented at all (that I could see).&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;// main.go&lt;/span&gt;
&lt;span class="o"&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;// Set some variables to use:&lt;/span&gt;
    &lt;span class="c"&gt;// Mostly we need the set up the base request struct and&lt;/span&gt;
    &lt;span class="c"&gt;// the http client.&lt;/span&gt;
    &lt;span class="k"&gt;var&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;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DefaultClient&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;sharksRequest&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;sammyname&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;// We can use our helper function to make sure we are&lt;/span&gt;
    &lt;span class="c"&gt;// getting correct values here.&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;setType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NewSammyType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sammytype&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="c"&gt;// marshal the struct to JSON&lt;/span&gt;
    &lt;span class="n"&gt;rb&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;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;marshalJSON&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;log&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="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;// Build the new http request&lt;/span&gt;
    &lt;span class="n"&gt;req&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;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRequest&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="n"&gt;API_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rb&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;log&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="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 the required headers (from the docs).&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;map&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;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"Accept"&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;"application/json"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="s"&gt;"Content-Type"&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;"application/json"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Send the request&lt;/span&gt;
    &lt;span class="n"&gt;resp&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;Do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&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;log&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="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;// Because we don't know the structure of the output&lt;/span&gt;
    &lt;span class="c"&gt;// we can just output the response to the terminal.&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;out&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;ioutil&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;resp&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;log&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="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;log&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="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&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;Running our code via go run, &lt;code&gt;go run main.go -name &amp;lt;myname&amp;gt; -type &amp;lt;mytype&amp;gt;&lt;/code&gt; actually works at this point, but I don't like the raw byte string that we are outputting. In a real API handler, we want to put the response into a struct, so now that I can see some output, I can build a struct.&lt;/p&gt;

&lt;p&gt;The output for me looked something like this for a success:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{"message":"Shark created successfully! Congrats on successfully completing the functions challenge!"}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and this for a failure:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{"message":"The name has already been taken.","errors":{"name":["The name has already been taken."]}}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;So, with this info in mind, I wrote another struct and some more helper methods to load that info into:&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;// main.go&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;sammyType&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;

    &lt;span class="n"&gt;sharksRequest&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;Type&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="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;sharksResponse&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// Message seems pretty strait forward and exists &lt;/span&gt;
        &lt;span class="c"&gt;// in both the responses, so this is a pretty safe&lt;/span&gt;
        &lt;span class="c"&gt;// bet&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="c"&gt;// Errors on the other hand, I don't have enough&lt;/span&gt;
        &lt;span class="c"&gt;// info to strongly type the response, but the&lt;/span&gt;
        &lt;span class="c"&gt;// map type here works for now. I can change it&lt;/span&gt;
        &lt;span class="c"&gt;// later if there is more I want to do with the&lt;/span&gt;
        &lt;span class="c"&gt;// errors.&lt;/span&gt;
        &lt;span class="n"&gt;Errors&lt;/span&gt; &lt;span class="k"&gt;map&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;string&lt;/span&gt; &lt;span class="s"&gt;`json:"errors"`&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// func NewSharksResponse() is something again that I would normally write, but it isn't necessary in this example&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;resp&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sharksResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;unmarshalJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&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;ReadCloser&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="n"&gt;b&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;ioutil&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;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="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;"unable to read http body: %w"&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;return&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;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resp&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have this, we can add it to our main 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="c"&gt;// main.go&lt;/span&gt;
&lt;span class="o"&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;// Set some variables to use:&lt;/span&gt;
    &lt;span class="c"&gt;// Mostly we need the set up the base request struct, &lt;/span&gt;
    &lt;span class="c"&gt;// the response struct, and the http client.&lt;/span&gt;
    &lt;span class="k"&gt;var&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;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DefaultClient&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;sharksRequest&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;sammyname&lt;/span&gt;&lt;span class="p"&gt;,&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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;sharksResponse&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 can use our helper function to make sure we are&lt;/span&gt;
    &lt;span class="c"&gt;// getting correct values here.&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;setType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NewSammyType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sammytype&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="c"&gt;// marshal the struct to JSON&lt;/span&gt;
    &lt;span class="n"&gt;rb&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;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;marshalJSON&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;log&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="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;// Build the new http request&lt;/span&gt;
    &lt;span class="n"&gt;req&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;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRequest&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="n"&gt;API_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rb&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;log&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="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 the required headers (from the docs).&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;map&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;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"Accept"&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;"application/json"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="s"&gt;"Content-Type"&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;"application/json"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Send the request&lt;/span&gt;
    &lt;span class="n"&gt;resp&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;Do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&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;log&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="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;// We have a structure to unmarshal to now, so lets use&lt;/span&gt;
    &lt;span class="c"&gt;// it.&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&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;R&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unmarshalJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&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="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;log&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="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;// Now we can send some better info to the terminal&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;R&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;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;log&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;"An error occurred. Message: %s, Errors: %v"&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;Message&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;Errors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;log&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="n"&gt;R&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And with that, I would say we have a successful application. To see the full code, feel free to check out my repository for the challenge here: &lt;a href="https://github.com/j4ng5y/digitalocean-functions-challenge"&gt;https://github.com/j4ng5y/digitalocean-functions-challenge&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I will put more languages in this repo too, so follow the instructions in the README to look at other examples (as I create them). I will have similar write-ups for those other languages as well.&lt;/p&gt;

</description>
      <category>go</category>
      <category>digitalocean</category>
      <category>functions</category>
      <category>api</category>
    </item>
    <item>
      <title>Basic auth with NGINX Ingress Controller on Kubernetes</title>
      <dc:creator>Jordan Gregory</dc:creator>
      <pubDate>Thu, 20 May 2021 15:27:07 +0000</pubDate>
      <link>https://dev.to/j4ng5y/basic-auth-with-nginx-ingress-controller-on-kubernetes-1ko3</link>
      <guid>https://dev.to/j4ng5y/basic-auth-with-nginx-ingress-controller-on-kubernetes-1ko3</guid>
      <description>&lt;p&gt;So, I couldn't find a lot of good resources online when I went to do this yesterday, so I figured I would post what I did to accomplish this task.&lt;/p&gt;

&lt;p&gt;This particular post will not try to explain the basics of Kubernetes Ingress controllers, if the need is there, I can write another post explaining more of the basics. Feel free to comment on the post if you would like me to do so.&lt;/p&gt;

&lt;p&gt;First things first, let me start by clearing up a few things:&lt;/p&gt;

&lt;p&gt;The first order of business is that I am in no way affiliated with NGINX or F5, I am just a fan of their products.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;NGINX Ingress Controller&lt;/em&gt;, provided by F5 (the company that owns NGINX) is not the same thing as the &lt;em&gt;ingress-nginx&lt;/em&gt; controller (the ingress provided and maintained by the Kubernetes community).&lt;/p&gt;

&lt;p&gt;I don't have anything against the &lt;em&gt;ingress-nginx&lt;/em&gt; controller, but there are a number of things that the &lt;em&gt;NGINX Ingress Controller&lt;/em&gt; does that &lt;em&gt;ingress-nginx&lt;/em&gt; does not, and I needed those particular features. Again, if you would like a breakdown of the differences, I could write another post, but I feel like F5 did a decent job with this post:&lt;br&gt;
&lt;a href="https://www.nginx.com/blog/wait-which-nginx-ingress-controller-kubernetes-am-i-using/"&gt;Which NGINX Ingress Controller am I using?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Both are open source (but the &lt;em&gt;NGINX Ingress Controller&lt;/em&gt; has a paid support option) and I'm pretty sure that the following steps can be performed with the &lt;em&gt;ingress-nginx&lt;/em&gt; controller as well, but I've not tested it.&lt;/p&gt;

&lt;p&gt;With that out of the way, here is what I did to enable &lt;strong&gt;BASIC AUTH&lt;/strong&gt; using the &lt;em&gt;NGINX Ingress Controller&lt;/em&gt; by F5.&lt;/p&gt;
&lt;h2&gt;
  
  
  Assumptions and Necessary Pre-Work
&lt;/h2&gt;

&lt;p&gt;So, my basic assumptions are these:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You have a running Kubernetes cluster that you can access ... somewhere.&lt;/li&gt;
&lt;li&gt;You have the &lt;em&gt;NGINX Ingress Controller&lt;/em&gt; installed (NGINX Plus is not necessary, but enabling snippets is necessary).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you do not have the &lt;em&gt;NGINX Ingress Controller&lt;/em&gt; installed, just follow the steps in the guides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.nginx.com/nginx-ingress-controller/installation/installation-with-manifests/"&gt;Installation With Raw Kubernetes Manifests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.nginx.com/nginx-ingress-controller/installation/installation-with-helm/"&gt;Installation with Helm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.nginx.com/nginx-ingress-controller/installation/installation-with-operator/"&gt;Installation with the NGINX Ingress Controller Operator&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The only real pre-work step is that you have to have a valid &lt;code&gt;.htpasswd&lt;/code&gt; file to provide to the controller pods.&lt;/p&gt;

&lt;p&gt;In my case, I did the following in an Ubuntu container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apt-get update
apt-get &lt;span class="nb"&gt;install &lt;/span&gt;apache2-utils
htpasswd &lt;span class="nt"&gt;-c&lt;/span&gt; .htpasswd &amp;lt;my_first_user&amp;gt;
&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;The&lt;/span&gt;&lt;span class="sh"&gt; utility will ask you to input the password for the user &amp;gt;&amp;gt;

cat .htpasswd
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you need more than a single user, feel free to rinse//repeat the &lt;code&gt;htpasswd -c ...&lt;/code&gt; step for as many users as you need.&lt;/p&gt;

&lt;p&gt;I then just copied the contents of that file via &lt;code&gt;cat&lt;/code&gt;, but you could have just as easily mounted a local volume to the running container and saved the file there for easier use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding the .htpasswd file to the existing/future &lt;em&gt;NGINX Ingress Controller&lt;/em&gt; pods
&lt;/h2&gt;

&lt;p&gt;First, we have to add the contents of the .htpasswd file to either a ConfigMap or a Secret, and given the contents, I chose a Secret, so to do this, I created this resource:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Contents of htpasswd.yaml&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Secret&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Opaque&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;htpasswd&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
&lt;span class="na"&gt;stringData&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;.htpasswd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;&amp;lt;&amp;lt; CONTENTS OF .HTPASSWD THAT YOU COPIED FROM PRE-WORK &amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then simply applied it using &lt;code&gt;kubectl apply -f htpasswd.yaml&lt;/code&gt;, but feel free to call the file whatever you want.&lt;/p&gt;

&lt;p&gt;If you happened to save the contents of the .htpasswd to a file before hand, you could have simply run &lt;code&gt;kubectl create secret generic htpasswd -n nginx --from-file=&amp;lt;your_file&amp;gt;&lt;/code&gt;, in hindsight, I would probably do this.&lt;/p&gt;

&lt;p&gt;Now, we have to add this file the NGINX pods. To do this step, we need to get the deployment name that we have to edit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get deployments -n nginx

NAME           READY  UP-TO-DATE  AVAILABLE  AGE
nginx-ingress  1/1    1           1          15d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using this, we can simple edit the resource using the following command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl edit deployment nginx-ingress -n nginx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The modifications we have to make are as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s"&gt;...&lt;/span&gt;
  &lt;span class="s"&gt;template&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;...&lt;/span&gt;
    &lt;span class="s"&gt;spec&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-ingress&lt;/span&gt;
        &lt;span class="s"&gt;...&lt;/span&gt;
        &lt;span class="c1"&gt;# THIS IS WHAT WE NEED TO ADD TO THE CONTAINER&lt;/span&gt;
        &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/etc/apache2&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;htpasswd&lt;/span&gt;
        &lt;span class="s"&gt;...&lt;/span&gt;
      &lt;span class="c1"&gt;# AND THIS IS WHAT WE NEED TO ADD TO THE OVERALL SPEC&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;defaultMode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;420&lt;/span&gt;
          &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.htpasswd&lt;/span&gt;
            &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.htpasswd&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;htpasswd&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;htpasswd&lt;/span&gt;
      &lt;span class="s"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are comfortable with patching Kubernetes resources, that would be a viable alternative to just editing, but I was in a time crunch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modifying your ingress to use the work
&lt;/h2&gt;

&lt;p&gt;So now, the last step is you modify your ingress to actually use everything we have done up to this point. So again, we need to get the name of your ingress and edit it.&lt;br&gt;
&lt;/p&gt;

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

NAME        CLASS  HOSTS                      ADDRESS  PORTS AGE
my-ingress  nginx  my-service.whatever.myTld  1.2.3.4  80,443  15d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go ahead and edit your ingress like so:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl edit ingress my-ingress&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The only changes we need to make are to the annotations of the ingress, and the annotations we need to add are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s"&gt;...&lt;/span&gt;
  &lt;span class="s"&gt;annotations&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;...&lt;/span&gt;
    &lt;span class="s"&gt;# THIS IS THE ADDITION&lt;/span&gt;
    &lt;span class="s"&gt;nginx.org/server-snippets&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;auth_basic "my-ingress";&lt;/span&gt;
      &lt;span class="s"&gt;auth_basic_user_file /etc/apache2/.htpasswd;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you save the resource, go ahead and try to access you ingress ... and voila! you are presented with a login popup that we are all so familiar with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parting Words
&lt;/h2&gt;

&lt;p&gt;Yeah, basic auth is kind of dumb, but there are still reasons for it. If you are interested in paying for &lt;em&gt;NGINX Plus&lt;/em&gt; you get access to automated JWT authentication and things of that nature, but I simply just didn't need all of that at this layer. Other ingress controllers (ambassador, kong, etc...) may make this process easier or not, but we don't use them, so that is the reason for this post.&lt;/p&gt;

&lt;p&gt;Like I said, this may very well work with the &lt;em&gt;ingress-nginx&lt;/em&gt; controller as well, but, I'll leave that to y'all to work out and report back.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>k8s</category>
      <category>nginx</category>
      <category>auth</category>
    </item>
    <item>
      <title>Svelte + Rust WASM = ❤️</title>
      <dc:creator>Jordan Gregory</dc:creator>
      <pubDate>Sat, 17 Oct 2020 03:13:35 +0000</pubDate>
      <link>https://dev.to/j4ng5y/svelte-rust-wasm-1b73</link>
      <guid>https://dev.to/j4ng5y/svelte-rust-wasm-1b73</guid>
      <description>&lt;p&gt;So, over at STLRust, I've been looking for the best JS framework to pair with my WASM escapades for a while.&lt;/p&gt;

&lt;p&gt;At this point, I've all but written off the bigger frameworks such as React, Angular, and Vue for reasons beyond the scope of this article.&lt;/p&gt;

&lt;p&gt;I decided on Svelte due to its minimalism ultimately.&lt;/p&gt;

&lt;p&gt;On my path of bootstrapping my new stack though, I realized that there just isn't any real good documentation on doing this sort of thing yet, so I went ahead and created a template to solve half of that equation.&lt;/p&gt;

&lt;p&gt;So if you are in the mood to play around with Svelte and WASM, feel free to give it a try:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://git.stlrust.org/j4ng5y/svelte-wasm-template.git"&gt;https://git.stlrust.org/j4ng5y/svelte-wasm-template.git&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>webassembly</category>
      <category>svelte</category>
    </item>
    <item>
      <title>I switched to OpenSuse</title>
      <dc:creator>Jordan Gregory</dc:creator>
      <pubDate>Sat, 11 Jul 2020 22:22:44 +0000</pubDate>
      <link>https://dev.to/j4ng5y/i-switched-to-opensuse-5d5b</link>
      <guid>https://dev.to/j4ng5y/i-switched-to-opensuse-5d5b</guid>
      <description>&lt;p&gt;So, after the news that SUSE purchased Rancher, I figured I would give them another go mostly because I love &lt;code&gt;k3s&lt;/code&gt; almost as much as I love &lt;code&gt;kind&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Is there anyone else to thought the same thing?&lt;/p&gt;

&lt;p&gt;Is there anything else that made you make a hard OS switch like this?&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>linux</category>
    </item>
    <item>
      <title>a new way to download hashicorp tools</title>
      <dc:creator>Jordan Gregory</dc:creator>
      <pubDate>Wed, 08 Jul 2020 18:53:54 +0000</pubDate>
      <link>https://dev.to/j4ng5y/a-new-way-to-download-hashicorp-tools-23cm</link>
      <guid>https://dev.to/j4ng5y/a-new-way-to-download-hashicorp-tools-23cm</guid>
      <description>&lt;p&gt;Have you ever found yourself distro hopping, or supporting a large cluster of servers/workstations that all need certain hashicorp tools on them?&lt;/p&gt;

&lt;p&gt;Have you ever started to make up curse words from having to go to the downloads section of each tool and/or build them from source every time?&lt;/p&gt;

&lt;p&gt;Well folks, I have the tool for you. In an abundance of laziness, I created this tool to grab any/all of the hashicorp tools for you and put them in normal places.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&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%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/j4ng5y" rel="noopener noreferrer"&gt;
        j4ng5y
      &lt;/a&gt; / &lt;a href="https://github.com/j4ng5y/hashi.up" rel="noopener noreferrer"&gt;
        hashi.up
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A simple app to get the hashicorp tools
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Hashi.UP&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;This is a little tool to help grab the hashicorp tools more easily, rather than having to go to each web page, find your OS/Arch, and download the tool.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting the tool&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Head on over to the &lt;a href="https://github.com/j4ng5y/hashi.up/releases" rel="noopener noreferrer"&gt;Releases&lt;/a&gt; page and grab the version you need for your os. This is a simple binary, so no real installation is necessary.&lt;/p&gt;
&lt;p&gt;On a *nix system, you may need to provide execution privliedges to run this tool: &lt;code&gt;chmod +x hashi.up&lt;/code&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Building from source&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;You would need to have Go installed and runable, to do this, head over to &lt;a href="https://golang.org/dl" rel="nofollow noopener noreferrer"&gt;The Go Downloads Website&lt;/a&gt; and install it.&lt;/p&gt;
&lt;p&gt;Additionally, you would need to have &lt;code&gt;make&lt;/code&gt; installed.&lt;/p&gt;
&lt;p&gt;Otherwise, simply clone this repository, &lt;code&gt;cd&lt;/code&gt; into the repository direcotry, and run &lt;code&gt;make &amp;amp;&amp;amp; make install&lt;/code&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;
&lt;pre class="notranslate"&gt;&lt;code&gt;
Usage
  hashi.up [flags]
  hashi.up [command]

Available Commands:
  help        Help about any command
  install     Install one, some, or all of the hashicorp&lt;/code&gt;&lt;/pre&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/j4ng5y/hashi.up" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Feel free to check it out and if you find a bug, I'm very interesting in making that a good tool, so I'll fix it in a jiffy.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>hashicorp</category>
      <category>terraform</category>
      <category>go</category>
    </item>
    <item>
      <title>How I Do Go Application Configuration in 2020</title>
      <dc:creator>Jordan Gregory</dc:creator>
      <pubDate>Wed, 19 Feb 2020 21:18:33 +0000</pubDate>
      <link>https://dev.to/j4ng5y/how-i-do-go-application-configuration-in-2020-336b</link>
      <guid>https://dev.to/j4ng5y/how-i-do-go-application-configuration-in-2020-336b</guid>
      <description>&lt;p&gt;There are many ways to handle application configuration in Go applications:&lt;/p&gt;

&lt;p&gt;1). Simple environment variable using &lt;code&gt;os.Getenv("MY_AWESOME_ENV")&lt;/code&gt;&lt;br&gt;
2). Manually writing parsers for yaml/json/toml/hcl/envfile/java.properties files with their corresponding libraries.&lt;br&gt;
3). Reading in from an external system (e.g. etcd, consul, etc...) using their individual libraries/api's.&lt;br&gt;
4). CLI flags&lt;br&gt;
5). Using a battle-harded library to do the hard stuff for you.&lt;/p&gt;

&lt;p&gt;For this particular article, I'll focus on number 5 from the list above because this is actually the way I do configuration these days.&lt;/p&gt;
&lt;h2&gt;
  
  
  Enter The Viper 🐍
&lt;/h2&gt;

&lt;p&gt;So these days, rather than spending cycles maintaining my own configuration library, I use one of the more popular configuration libraries in the wild today:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/spf13"&gt;
        spf13
      &lt;/a&gt; / &lt;a href="https://github.com/spf13/viper"&gt;
        viper
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Go configuration with fangs
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Viper allows you to do all of the common configuration scenarios and then some, so for my projects, it's the best of all worlds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set it up
&lt;/h2&gt;

&lt;p&gt;In all things Go these days, installing dependencies, Viper included, is as simple as running the following command in your "Go Modules" enabled project:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;go get -u github.com/spf13/viper&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: The "-u" in the &lt;code&gt;go get&lt;/code&gt; command just updates the dependency if you already have it for some reason or another. I usually tend to include it.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Great! How do I use it?
&lt;/h2&gt;

&lt;p&gt;The repository hosts a few good examples on usage, so feel free to check it out here: &lt;a href="https://github.com/spf13/viper/blob/master/README.md"&gt;https://github.com/spf13/viper/blob/master/README.md&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Considering that you are reading this particular article though, I'll run through a few common scenarios that I find myself in when I write things these days.&lt;/p&gt;

&lt;p&gt;The way I tend to really set this up is by defining a new Viper instance in a primary &lt;code&gt;struct&lt;/code&gt; and having sub-components read from that configuration.&lt;/p&gt;

&lt;p&gt;So let's pretend that I want to build an HTTP server.&lt;/p&gt;

&lt;p&gt;I typically will have a struct defined somewhere in my application that will look something 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="o"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Server&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// HTTPServer should be fairly obvious&lt;/span&gt;
    &lt;span class="n"&gt;HTTPServer&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="c"&gt;// Configuration is the Viper instance we will reference later on&lt;/span&gt;
    &lt;span class="n"&gt;Configuration&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;viper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Viper&lt;/span&gt;

    &lt;span class="c"&gt;// You may or may not need this, but most apps do :D&lt;/span&gt;
    &lt;span class="n"&gt;Database&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;NewServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;viper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Viper&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;Server&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;// my fancy server setup constructor logic&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;All of my handlers (db, web, etc...), hang off of this &lt;code&gt;Server&lt;/code&gt; &lt;code&gt;struct&lt;/code&gt; in some way or another, so these components can access the configuration data.&lt;/p&gt;
&lt;h3&gt;
  
  
  Scenario 1: Environment Variables
&lt;/h3&gt;

&lt;p&gt;Viper has a few ways to work with environment variables. Personally, I like to be fairly explicit with what I am expecting, but Viper gives us the ability to simply set an environment variable prefix to handle things later:&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="o"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;viper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetEnvPrefix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MYAPP_"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// All environment variables that match this prefix will be loaded and can be referenced in the code&lt;/span&gt;
&lt;span class="n"&gt;viper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AllowEmptyEnv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// Allows an environment variable to not exist and not blow up, I suggest using switch statements to handle these though&lt;/span&gt;
&lt;span class="n"&gt;viper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AutomaticEnv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c"&gt;// Do the darn thing :D&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Scenario 2: Configuration Files (regardless of extension!!)
&lt;/h3&gt;

&lt;p&gt;Usually, you would support a single configuration file format and stick with that until the app dies or a new major version came out, but you don't have to worry about that any more with Viper because it supports most of the big ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSON&lt;/li&gt;
&lt;li&gt;YAML&lt;/li&gt;
&lt;li&gt;TOML&lt;/li&gt;
&lt;li&gt;HCL&lt;/li&gt;
&lt;li&gt;.env&lt;/li&gt;
&lt;li&gt;.properties&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You may be asking yourself, "But rando teacher internet guy, my config files are deeply nested! How do I access this data?". Getting data is easy fortunately and just follows the dot-notion way of life:&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="o"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;viper&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="s"&gt;"my.deeply.nested.configuration.item"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;this will get the value of the "item" item from the following JSON file:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"my"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"deeply"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"nested"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"configuration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"item"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"check it"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Configuration items don't have to be strings either, there are plenty of functions for pulling specific data types out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GetBool&lt;/li&gt;
&lt;li&gt;GetDuration&lt;/li&gt;
&lt;li&gt;GetFloat64&lt;/li&gt;
&lt;li&gt;GetInt&lt;/li&gt;
&lt;li&gt;GetInt32&lt;/li&gt;
&lt;li&gt;GetInt64&lt;/li&gt;
&lt;li&gt;GetIntSlice&lt;/li&gt;
&lt;li&gt;GetSizeInBytes&lt;/li&gt;
&lt;li&gt;GetString&lt;/li&gt;
&lt;li&gt;GetStringMap&lt;/li&gt;
&lt;li&gt;GetStringMapString&lt;/li&gt;
&lt;li&gt;GetStringMapStringSlice&lt;/li&gt;
&lt;li&gt;GetStringSlice&lt;/li&gt;
&lt;li&gt;GetTime&lt;/li&gt;
&lt;li&gt;GetUint&lt;/li&gt;
&lt;li&gt;GetUint32&lt;/li&gt;
&lt;li&gt;GetUint64&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;viper.Get()&lt;/code&gt; function just simply returns an &lt;code&gt;interface{}&lt;/code&gt;, so if you can cast it, you can work with it.&lt;/p&gt;

&lt;p&gt;To get this to work, all you have to do it provide a file name (without the file extension) and the 🐍 magic just does it's thing:&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="o"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;viper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetConfigName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"config"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If you really, really wanted to only support a particular config file type, you can do that too:&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="o"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;viper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetConfigType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You also can assign any number of other locations to look for this configuration file, the common ones I tend to use are something like the following:&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="o"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;viper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddConfigPath&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;viper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddConfigPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./config"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;viper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddConfigPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&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;homeDirectory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;".my-awesome-app"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;viper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddConfigPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&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;homeDirectory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;".my-awesome-app/config"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;viper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddConfigPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/etc/my-awesome-app/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;viper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddConfigPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/etc/my-awesome-app/config"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;em&gt;Note: &lt;code&gt;homeDirectory&lt;/code&gt; is a variable, so I have to set that somewhere 😄&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can also set full config file location 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="o"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;viper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetConfigFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./config.yaml"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Or feel free to just provide this information via a CLI flag. Speaking of which...&lt;/p&gt;
&lt;h3&gt;
  
  
  Scenario 4: CLI Input
&lt;/h3&gt;

&lt;p&gt;I'll be real, I don't do much CLI stuff anymore without Viper's sister repo:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/spf13"&gt;
        spf13
      &lt;/a&gt; / &lt;a href="https://github.com/spf13/cobra"&gt;
        cobra
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A Commander for modern Go CLI interactions
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;My only exception here is for something that maybe needs to use &lt;code&gt;klog&lt;/code&gt; or some other very, very small app, but 9/10 times, Cobra all day.&lt;/p&gt;

&lt;p&gt;The pair make it very, very easy to add CLI elements to existing text config files. There are just a few elements (such as maybe a --debug/--config flag) that just live better on the CLI only and not in a config file that is automatically consumed by your app.&lt;/p&gt;

&lt;p&gt;Here is a quick snippet of what my CLI's paired with Viper tend to look 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="o"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;runCLI&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="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;configFileFlag&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;

        &lt;span class="n"&gt;vCfg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;viper&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="n"&gt;myAppCmd&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;cobra&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Use&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"my-awesome-app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Version&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;myVersionConstant&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Short&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;myShortDescriptionConstant&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Long&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;myLongDescriptionConstant&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;cobra&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NoArgs&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;PreRun&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;ccmd&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cobra&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&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;vCfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetConfigFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;configFileFlag&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;vCfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadInConfig&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;log&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;"unable to read in config due to error: %+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;span class="n"&gt;Run&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;ccmd&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cobra&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&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;svr&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;server&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="n"&gt;vCfg&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;log&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;"failed build server struct due to error: %+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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;svr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&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;log&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;"server failed to start due to error: %+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;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;myAppCmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Flags&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StringVarP&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;configFileFlag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"config"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"f"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"./config.yaml"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"The path to the config file to use."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;vCfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BindPFlags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"config"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;myAppCmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Flags&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"config"&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;myAppCmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Execute&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;log&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;"the CLI failed to run due to error: %+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;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Obviously, there is some crucial stuff missing from that, e.g. - my constant values, what my &lt;code&gt;server.New(vCfg)&lt;/code&gt; function looks like, etc..., so to that end, I direct you to my article specific repository:&lt;br&gt;
&lt;a href="https://gitlab.com/j4ng5y/how-i-write-go-configs-in-2020.git"&gt;https://gitlab.com/j4ng5y/how-i-write-go-configs-in-2020.git&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Scenario 5: All of the above
&lt;/h3&gt;

&lt;p&gt;I won't go through the specific examples again 😄, but please to check out my repository to see them all in action:&lt;br&gt;
&lt;a href="https://gitlab.com/j4ng5y/how-i-write-go-configs-in-2020.git"&gt;https://gitlab.com/j4ng5y/how-i-write-go-configs-in-2020.git&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Scenario 6: None of the above?
&lt;/h3&gt;

&lt;p&gt;Yeah, that is right, you don't really have to use any user modifiable way to do this and still have access to the same API that all your other apps use. You just have to set them up:&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="o"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;viper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetDefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MyConfigItem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"holla atcha boi"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;The choice for configuration is ultimately yours, but I have found that using Viper has greatly simplified my application boot-straping.&lt;/p&gt;

&lt;p&gt;This article was not to give you a fully thought out way of doing anything in particular, just sharing my experiences with the community as a whole.&lt;/p&gt;

&lt;p&gt;If you have any further questions Re: this or anything else really for that matter, please don't hesitate to comment here or reach out to me on twitter &lt;code&gt;@j4ng5y&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can find my on the Gopher slack &lt;code&gt;@Jordan Gregory&lt;/code&gt; as well.&lt;/p&gt;

</description>
      <category>go</category>
      <category>configuration</category>
    </item>
    <item>
      <title>Conditionals in Python</title>
      <dc:creator>Jordan Gregory</dc:creator>
      <pubDate>Thu, 20 Jun 2019 19:00:56 +0000</pubDate>
      <link>https://dev.to/codetips/conditionals-in-python-37p4</link>
      <guid>https://dev.to/codetips/conditionals-in-python-37p4</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DSo5oLPs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.codetips.co.uk/content/images/2019/06/apple-black-and-white-black-and-white-169573.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DSo5oLPs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.codetips.co.uk/content/images/2019/06/apple-black-and-white-black-and-white-169573.jpg" alt="Conditionals in Python" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the last article ( "&lt;a href="https://www.codetips.co.uk/languages/python/lists-and-loops-in-python/"&gt;Lists and Loops in Python&lt;/a&gt;" ), we created a programme that outputted our &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;age&lt;/code&gt;, &lt;code&gt;profession&lt;/code&gt;, &lt;code&gt;favoriteAnimal&lt;/code&gt; and a list of our &lt;code&gt;hobbies&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In this article, we're going to extend our programme to act differently depending on the &lt;code&gt;age&lt;/code&gt; variable. Before we get started, let's remove some code we won't be needing in this article:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/env python

# Start of our code

name = "Jordan"
# age = 31

hobbies = ["hiking", "playing music", "example1", "example2"]

print("Hello World. My name is {0}.".format(name))

print("I have {0} hobbies, and they are: ".format(len(hobbies)))

i = 0
while i &amp;lt; len(hobbies):
    print(hobbies[i])
    i+=1

# End of our code

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : We've commented out the age parameter. While not a hard rule of Python, it is best practice that you not declare any unused variables. If we had declared it ( &lt;code&gt;age = 29&lt;/code&gt; ) but not referenced it - it is considered unused, but you will not see an error when running the programme like you would with a more strict language; rather, the interpreter will just clean up the memory at the end of the programme run.&lt;/p&gt;

&lt;p&gt;Running the application now, you should see the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ python first.py
Hello World. My name is Jordan.
I have 4 hobbies, and they are: 
hiking
playing music
example1
example2

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

&lt;/div&gt;



&lt;p&gt;We're now going to bring back the &lt;code&gt;age&lt;/code&gt; variable and, depending on its value, we'll print one of the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If &lt;code&gt;age&lt;/code&gt; is less than 10, we will print "I am x years young".&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If &lt;code&gt;age&lt;/code&gt; is more than 10, we will print "I am x years old".&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To do this we're going to use an &lt;code&gt;if&lt;/code&gt; statement. The syntax for declaring an &lt;code&gt;if&lt;/code&gt; statement in Python is simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if expression:
    // Run this code if expression evaluates to true

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

&lt;/div&gt;



&lt;p&gt;To perform an action dependant on &lt;code&gt;age&lt;/code&gt;, we can simply add two &lt;code&gt;if&lt;/code&gt; statements to our code ( Note: we have omitted all of the code not related to &lt;code&gt;age&lt;/code&gt;, at this stage, to focus on what we're discussing )&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/env python

# Start of our code

age = 31

if age &amp;lt; 10:
    print("I am {0} years young".format(age))

if age &amp;gt; 10:
    print("I am {0} years old".format(age))

# End of our code

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

&lt;/div&gt;



&lt;p&gt;We are now performing two checks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Is &lt;code&gt;age&lt;/code&gt; less than ( &lt;code&gt;&amp;lt;&lt;/code&gt; ) 10? If it is, we print out the first message.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Is &lt;code&gt;age&lt;/code&gt; greater than ( &lt;code&gt;&amp;gt;&lt;/code&gt; ) 10? If it is, we print out the second message.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Perfect! Actually, unfortunately not. There are two things wrong with this code snippet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem 1&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We're checking if &lt;code&gt;age&lt;/code&gt; is less than ( &lt;code&gt;&amp;lt;&lt;/code&gt; ) and greater than ( &lt;code&gt;&amp;gt;&lt;/code&gt; ) 10, but what if &lt;code&gt;age&lt;/code&gt; is 10? It doesn't call either Print statements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python conditionals.py

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

&lt;/div&gt;



&lt;p&gt;To fix this we first need to decide what statement we should print if the persons &lt;code&gt;age&lt;/code&gt; is 10. I think 10 is still pretty young so let's print out the first statement. If you disagree, see if you can make it print out the second statement.&lt;/p&gt;

&lt;p&gt;We then need to change our "less than" ( &lt;code&gt;&amp;lt;&lt;/code&gt; ) condition, to be "less than or equal to" ( &lt;code&gt;&amp;lt;=&lt;/code&gt; ).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/env python

# Start of our code

age = 31

if age &amp;lt;= 10:
    print("I am {0} years young".format(age))

if age &amp;gt; 10:
    print("I am {0} years old".format(age))

# End of our code

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

&lt;/div&gt;



&lt;p&gt;Now if we run our programme with an &lt;code&gt;age&lt;/code&gt; of 10, we get our message printed!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ python conditionals.py
I am 10 years young

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Problem 2&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Regardless of what value is given to &lt;code&gt;age&lt;/code&gt;, we're always checking two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Is the value less than or equal to 10?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Is the value greater than 10?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this situation &lt;code&gt;age&lt;/code&gt; can only match one of these expressions, so we're asking the computer to do extra work. This might not seem like a big deal now, but if we grew our application to have thousands or millions of unnecessary checks we'd see a big performance hit.&lt;/p&gt;

&lt;p&gt;Instead of two &lt;code&gt;if&lt;/code&gt; statements, we can use an &lt;code&gt;if/else&lt;/code&gt; statement. The syntax for declaring an &lt;code&gt;if/else&lt;/code&gt; statement is very simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if expression:
    # Run this code if expression evaluates to true
else:
    # Run this code if expression evaluates to false

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

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;age&lt;/code&gt; variable is only ever going to be less than or equal to 10, or greater than 10, as we've previously stated. So we only need to check for one of those conditions, everything else fits in the &lt;code&gt;else&lt;/code&gt; statement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/env python

# Start of our code

age = 31

if age &amp;lt;= 10:
    print("I am {0} years young".format(age))
else:
    print("I am {0} years old".format(age))

# End of our code

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

&lt;/div&gt;



&lt;p&gt;Take some time to have a play with the code - we'll still be here when you're ready to continue.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Ready?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Excellent. Let's take this to the next level and make our programme more "age aware". This time we're going to check for four possible outcomes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If the &lt;code&gt;age&lt;/code&gt; variable is less than 13, we will print "I am considered a child"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the &lt;code&gt;age&lt;/code&gt; variable is between 13 and 19, we will print "I am considered a teenager"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the &lt;code&gt;age&lt;/code&gt; variable is between 20 and 67, we will print 'I am considered an adult'.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the &lt;code&gt;age&lt;/code&gt; variable is 68 or older, we will print "I am considered a senior".&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We already know having four separate &lt;code&gt;if&lt;/code&gt; statements isn't a good idea, but an &lt;code&gt;if/else&lt;/code&gt; statement can only handle two outcomes so what are we to do now? We can use the &lt;code&gt;if/elif/else&lt;/code&gt; statement!&lt;/p&gt;

&lt;p&gt;The syntax for declaring an &lt;code&gt;if/elif/else&lt;/code&gt; statement is very simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if expression:
    # Run this code if expression evaluates to true
elif anotherExpression:
    # Run this code if anotherExpression evaluates to true
elif yetAnotherExpression:
    # Run this code if yetAnotherExpression evaluates to true
else:
    # Run this code if none of the above expressions have evaluated to true

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

&lt;/div&gt;



&lt;p&gt;The difference between &lt;code&gt;else&lt;/code&gt; and &lt;code&gt;elif&lt;/code&gt; is the latter allows us to specify another expression.&lt;/p&gt;

&lt;p&gt;If the first expression hasn't evaluated to true, then the next expression is checked. This continues until an expression does evaluate to true, an &lt;code&gt;else&lt;/code&gt; statement or the conditional statement ends.&lt;/p&gt;

&lt;p&gt;If an expression does evaluate to true, it skips the rest of the &lt;code&gt;elif&lt;/code&gt; and &lt;code&gt;else&lt;/code&gt; statements.&lt;/p&gt;

&lt;p&gt;We can easily use this logic in our programme, without needing to learn many new concepts:&lt;br&gt;
&lt;/p&gt;

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

# Start of our code

age = 70

if age &amp;lt; 13:
    print("I am considered a child")
elif age &amp;gt;= 13 and age &amp;lt; 20:
    print("I am considered a teenager")
elif age &amp;gt;= 20 and age &amp;lt; 68:
    print("I am considered an adult")
else:
    print("I am considered a senior")

# End of our code

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

&lt;/div&gt;



&lt;p&gt;Let's run through these expressions, one by one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;if age &amp;lt; 13&lt;/code&gt; - we check if &lt;code&gt;age&lt;/code&gt; is less than ( &amp;lt; ) 13. If it is, we print out the "child" statement and don't have to perform any more checks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;elif age &amp;gt;= 13 and age &amp;lt; 20&lt;/code&gt; - we check if &lt;code&gt;age&lt;/code&gt; is greater than or equal to ( &amp;gt;= ) 13 and if &lt;code&gt;age&lt;/code&gt; is less than 20. This gives us a range of 13 - 19. If the expression evaluates to true we print out the "teenager" statement and don't have to perform any more checks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;elif age &amp;gt;= 20 and age &amp;lt; 68&lt;/code&gt; - we check if &lt;code&gt;age&lt;/code&gt; is greater than or equal to ( &amp;gt;= ) 20 and if &lt;code&gt;age&lt;/code&gt; is less than 68. This gives us a range of 20 - 67. If the expression evaluates to true we print out the "adult" statement, and don't have to perform any more checks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;else&lt;/code&gt; - if &lt;code&gt;age&lt;/code&gt; is any other value (i.e. 68 or above) we print out the "senior" statement.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let's add back the code from the beginning of this article:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/env python

# Start of our code

name = "Jordan"
age = 31
hobbies = ["hiking", "playing music", "example1", "example2"]

print("Hello World. My name is {0}.".format(name))

if age &amp;lt; 13:
    print("I am considered a child")
elif age &amp;gt;= 13 and age &amp;lt; 20:
    print("I am considered a teenager")
elif age &amp;gt;= 20 and age &amp;lt; 68:
    print("I am considered an adult")
else:
    print("I am considered a senior")

print("I have {} hobbies, and they are: ".format(len(hobbies)))

i = 0
while i &amp;lt; len(hobbies):
    print(hobbies[i])
    i+=1

# End of our code

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

&lt;/div&gt;



&lt;p&gt;That's it - we've now added an &lt;code&gt;if/elif/else&lt;/code&gt; statement to our Python programme!&lt;/p&gt;

&lt;p&gt;Before you go, see if you can complete the following challenge:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is possible to optimise the last &lt;code&gt;if/elif/else&lt;/code&gt; statement further, see if you can figure out how.
&lt;em&gt;Hint&lt;/em&gt;: we're still asking the computer to do more work than is necessary.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you need another hint, or want to show us your solution, get in touch with us on our &lt;a href="https://www.codetips.co.uk/contact-us/"&gt;Contact Us&lt;/a&gt; page.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://www.codetips.co.uk"&gt;CodeTips&lt;/a&gt; strives to help beginners, with zero or very little experience, learn to code.&lt;/p&gt;

&lt;p&gt;We do cross-post to other sites to reach a wider audience, but why not &lt;a href="https://mailchi.mp/92cccf7024b2/codetips"&gt;subscribe to our newsletter&lt;/a&gt; and get the newest articles straight to your mailbox? &lt;/p&gt;

&lt;p&gt;The original source for this content is &lt;a href="https://www.codetips.co.uk"&gt;CodeTips&lt;/a&gt;. The original content is kept up-to-date, but other sources may not be the latest version. &lt;/p&gt;

</description>
      <category>beginners</category>
      <category>tutorial</category>
      <category>learning</category>
      <category>python</category>
    </item>
    <item>
      <title>Lists and Loops in Python</title>
      <dc:creator>Jordan Gregory</dc:creator>
      <pubDate>Thu, 13 Jun 2019 15:51:55 +0000</pubDate>
      <link>https://dev.to/codetips/lists-and-loops-in-python-52n6</link>
      <guid>https://dev.to/codetips/lists-and-loops-in-python-52n6</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LYExTdS8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.codetips.co.uk/content/images/2019/06/loops.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LYExTdS8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.codetips.co.uk/content/images/2019/06/loops.jpg" alt="Lists and Loops in Python" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before reading this article, you should have read about &lt;a href="https://www.codetips.co.uk/beginner/what-are-arrays/"&gt;arrays&lt;/a&gt;, &lt;a href="https://www.codetips.co.uk/beginner/what-is-a-data-type/"&gt;types&lt;/a&gt; and &lt;a href="https://www.codetips.co.uk/beginner/what-are-loops/"&gt;loops&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As you will learn, Arrays are typically immutable and can hold information (usually of one particular type) and store them along with an index value.&lt;/p&gt;

&lt;p&gt;Python adds another layer on top of the typical array type, which makes them easier to work with, by allowing information of any type as well as making them mutable. This construct is called a List.&lt;/p&gt;

&lt;p&gt;In "&lt;a href="https://www.codetips.co.uk/languages/python/writing-your-first-python-program/"&gt;writing your first programme in Python&lt;/a&gt;", we wrote a programme that outputted your name, age and profession. In this article, we’re going to extend that programme and have it print out all of your hobbies as well.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: You were also asked to complete three challenges at the end of "&lt;a href="https://www.codetips.co.uk/languages/python/writing-your-first-python-program/"&gt;writing your first programme in Python&lt;/a&gt;". We’re going to assume you completed them. If you haven’t, this article shows you the solutions so make sure you at least try them.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After completing all three challenges, you should have ended up with something similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/env python

#Start of our code

name = "Jordan"
age = 31
profession = "Developer"
favoriteAnimal = "Penguin"

print("Welcome to my first Python programme. My name is {0}. I am {1} years old. I work as a {2}. My favourite animal is a {3}".format(
    name,
    age,
    profession,
    favoriteAnimal,
    )
)

# End of our code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We now want to add another piece of information; what our hobbies are.&lt;/p&gt;

&lt;p&gt;I have three main hobbies, so the obvious thing to do is to create three new variables and print them to the terminal as we did before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/env python

# Start of our code

name = "Jordan"
age = 31
profession = "Developer"
favoriteAnimal = "Penguin"

hobby1 := "Coding"
hobby2 := "Bass Guitar"
hobby3 := "Hiking"

print("Welcome to my first Python programme. My name is {0}. I am {1} years old. I work as a {2}. My favourite animal is a {3}".format(
    name,
    age,
    profession,
    favoriteAnimal,
    )
)

print("My hobbies are: {0}, {1}, {2}".format(hobby1, hobby2, hobby3))

# End of our code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've now added a second &lt;code&gt;print&lt;/code&gt; statement which prints our hobbies to the screen. Pretty neat huh? Well, actually, no.&lt;/p&gt;

&lt;p&gt;It may look acceptable to do this for three hobbies, but what if you had ten hobbies?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/env python

# Start of our code

name = "Jordan"
age = 31
profession = "Developer"
favoriteAnimal = "Penguin"

hobby1 = "example1"
hobby2 = "example2"
hobby3 = "example3"
hobby4 = "example4"
hobby5 = "example5"
hobby6 = "example6"
hobby7 = "example7"
hobby8 = "example8"
hobby9 = "example9"
hobby10 = "example10"

print("Welcome to my first Python programme. My name is {0}. I am {1} years old. I work as a {2}. My favourite animal is a {3}".format(
    name,
    age,
    profession,
    favoriteAnimal,
    )
)

print("My hobbies are: {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}".format(
    hobby1,
    hobby2,
    hobby3,
    hobby4,
    hobby5,
    hobby6,
    hobby7,
    hobby8,
    hobby9,
    hobby10
    )
)

# End of our code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's starting to look a bit messy, isn't it? What if we had 100 hobbies?&lt;/p&gt;

&lt;p&gt;There must be a better way! Thankfully, there is. Lists!&lt;/p&gt;

&lt;p&gt;In Python, lists can contain any type and are declared by simply using &lt;code&gt;variable = []&lt;/code&gt; to create an empty list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stringList = []
intList = []
boolList = []
multiTypeList = []
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can immediately add items into our list by simply adding items within the list declaration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stringList = ["string1", "string2"]
intList = [1, 2]
boolList = [True, False]
multiTypeList = ["string", 1, 3.14, True]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before we go any further, try to complete the following challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Take the ten hobby variables and convert them into one hobbies array.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Change the &lt;code&gt;print&lt;/code&gt; statement to print out the new list, instead of the ten variables.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Done? Excellent. You should have ended up with something similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/env python

# Start of our code
name = "Jordan"
age = 31
profession = "Developer"
favoriteAnimal = "Penguin"

hobbies = [
    "example1",
    "example2",
    "example3",
    "example4",
    "example5",
    "example6",
    "example7",
    "example8",
    "example9",
    "example10",
]

print("Welcome to my first Python programme. My name is {0}. I am {1} years old. I work as a {2}. My Favorite animal is a {3}.".format(
    name,
    age,
    profession,
    favoriteAnimal
    )
)

print("My hobbies are: {0}".format(hobbies))
# End of our code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running your application now ( &lt;code&gt;python main.py&lt;/code&gt; ) should give you the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Welcome to my first Go programme. My name is Jordan. I am 31 years old. I work as a Developer. My favorite animal is a Penguin.
My hobbies are: [example1 example2 example3 example4 example5 example6 example7 example8 example9 example10]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have our hobbies list and we can add and remove items easily, without having to create new variables or amend the &lt;code&gt;print&lt;/code&gt; statement.&lt;/p&gt;

&lt;p&gt;So our code is now looking nice and neat, but I'm still not very keen on what we're outputting to the terminal; we've got those ugly square brackets ( [] ) and what happens if we add a new hobby, which is made up of multiple words?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hobbies = ["example1", "mountain biking", "example2", "example3"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which would print:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;My hobbies are: [example1 mountain biking example2 example3]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Is it "mountain biking" or "mountain" and "biking"?&lt;/p&gt;

&lt;p&gt;So do we have to go back to separate variables? Thankfully not! We can use a loop!&lt;/p&gt;

&lt;p&gt;Before we change our programme, let's make a simple example of a loop to understand the concept.&lt;/p&gt;

&lt;p&gt;If we wanted to print the numbers 1-10 we could write 10 different &lt;code&gt;print&lt;/code&gt; statements, which is very manual, or we could write a loop to do it for us. In the following example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The init statement. Executed before the first iteration of the loop, we define a new variable ( i ) and assign the value 1 to it ( &lt;code&gt;i = 1&lt;/code&gt; ).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The condition expression. Executed before each iteration of the loop, it checks if the expression ( i &amp;lt;= 10 - is i less than or equal to 10? ) is true. If it is, it runs another iteration.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We then print the value of i during each iteration and then simply increment the value of i by 1 (e.g. if the value of i is 3, running i+=1 would increment it and it would now be 4)&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;i = 1
while i &amp;lt;= 10:
    print(i)
    i+=1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now use this new technique to print our hobbies. In the following example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;We have added a new &lt;code&gt;print&lt;/code&gt; statement that prints the number of hobbies we have. The &lt;code&gt;len&lt;/code&gt; method simply returns the length of the list; in this example 4.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We define our init statement and set the value of i to 0. We have set it to 0 instead of 1 because Python list indexes start at 0.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We define our conditional expression and set the condition to &lt;code&gt;i &amp;lt; len(hobbies)&lt;/code&gt; ( is i less than the length of hobbies ). We're using "less than" ( &lt;code&gt;&amp;lt;&lt;/code&gt; ) instead of "less than or equal" ( &lt;code&gt;&amp;lt;=&lt;/code&gt; ) because Python list indexes start at 0.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We define our post statement and increment the count of i as we did in our previous example.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We then print each element of hobbies.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/env python

# Start of our code

name = "Jordan"
age = 31
profession = "Developer"
favoriteAnimal = "Penguin"

hobbies = ["example1", "mountain biking", "example2", "example3"]

print("Welcome to my first Python programme. My name is {0}. I am {1} years old. I work as a {2}. My favourite animal is a {3}".format(
    name,
    age,
    profession,
    favoriteAnimal,
    )
)

print("I have {0} hobbies, and they are: ".format(len(hobbies)))

i = 0
while i &amp;lt; len(hobbies):
    print(hobbies[i])
    i=+1

# End of our code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following is an illustration of the link between our list index and values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;|     0    |        1        |     2    |    3     |
*----------*-----------------*----------*----------*
| example1 | mountain biking | example2 | example3 |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We appreciate this was a lot of information to take in, so feel free to &lt;a href="https://www.codetips.co.uk/contact-us/"&gt;reach out to us&lt;/a&gt; if anything isn't clear.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://www.codetips.co.uk"&gt;CodeTips&lt;/a&gt; strives to help beginners, with zero or very little experience, learn to code.&lt;/p&gt;

&lt;p&gt;We do cross-post to other sites to reach a wider audience, but why not &lt;a href="https://mailchi.mp/92cccf7024b2/codetips"&gt;subscribe to our newsletter&lt;/a&gt; and get the newest articles straight to your mailbox? &lt;/p&gt;

&lt;p&gt;The original source for this content is &lt;a href="https://www.codetips.co.uk"&gt;CodeTips&lt;/a&gt;. The original content is kept up-to-date, but other sources may not be the latest version. &lt;/p&gt;

</description>
      <category>beginners</category>
      <category>tutorial</category>
      <category>learning</category>
      <category>python</category>
    </item>
    <item>
      <title>Writing Your First Python Programme</title>
      <dc:creator>Jordan Gregory</dc:creator>
      <pubDate>Sat, 01 Jun 2019 11:31:03 +0000</pubDate>
      <link>https://dev.to/codetips/writing-your-first-python-programme-5clk</link>
      <guid>https://dev.to/codetips/writing-your-first-python-programme-5clk</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1JlQU4bl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.codetips.co.uk/content/images/2019/05/digital-dreams-1155366.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1JlQU4bl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.codetips.co.uk/content/images/2019/05/digital-dreams-1155366.jpg" alt="Writing Your First Python Programme" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;By the end of this article, you will have written a Python programme that outputs a sentence based on a number of variables.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you've made it to this article you should have read the &lt;a href="https://www.codetips.co.uk/languages/python/python-introduction/"&gt;Python Introduction&lt;/a&gt;, and be familiar with &lt;a href="https://www.codetips.co.uk/beginner/what-is-a-variable/"&gt;variables&lt;/a&gt; and &lt;a href="https://www.codetips.co.uk/beginner/what-is-a-data-type/"&gt;data-types&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As we stated in the &lt;a href="https://www.codetips.co.uk/languages/python/python-introduction/"&gt;Python Introduction&lt;/a&gt;, Python is an &lt;a href="https://www.codetips.co.uk/intermediate/translation-and-types/"&gt;interpreted&lt;/a&gt; language so its types are &lt;a href="https://www.codetips.co.uk/intermediate/translation-and-types/"&gt;inferred&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There is only one way to declare a variable in Python.&lt;/p&gt;

&lt;p&gt;In the following example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;x&lt;/code&gt; is assigned the value &lt;code&gt;"Hello World"&lt;/code&gt; and has an inferred type of &lt;code&gt;String&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;y&lt;/code&gt; is assigned the value &lt;code&gt;True&lt;/code&gt; and has an inferred type of &lt;code&gt;Bool&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;a&lt;/code&gt; is assigned the value &lt;code&gt;1&lt;/code&gt; and has an inferred type of &lt;code&gt;Int&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;b&lt;/code&gt; is assigned the value &lt;code&gt;3.14159&lt;/code&gt; and has an inferred type of &lt;code&gt;Float&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x = "Hello World"
y = True
a = 1
b = 3.14159
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As Python is a &lt;a href="https://www.codetips.co.uk/intermediate/translation-and-types/"&gt;dynamically typed language&lt;/a&gt;, there is no way to declare a variable as a specific &lt;a href="https://www.codetips.co.uk/beginner/what-is-a-data-type/"&gt;data-type&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It is, however, possible to perform logic based on the type, using the &lt;code&gt;type()&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;The following &lt;a href="https://www.codetips.co.uk/beginner/what-is-an-if-statement/"&gt;&lt;code&gt;if&lt;/code&gt; statement&lt;/a&gt; checks to see if the type of &lt;code&gt;y&lt;/code&gt; is &lt;code&gt;bool&lt;/code&gt; and, if &lt;code&gt;True&lt;/code&gt;, will run the &lt;code&gt;&amp;lt;do something&amp;gt;&lt;/code&gt; action. Otherwise, it will skip the indented section of code.&lt;br&gt;
&lt;/p&gt;

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

if type(y) is bool:
    &amp;lt;do something&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;It is also possible to perform "type casting" in Python. In the following example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The variable &lt;code&gt;x&lt;/code&gt; is assigned the value &lt;code&gt;1&lt;/code&gt; and has an inferred type of &lt;code&gt;Int&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The value of &lt;code&gt;x&lt;/code&gt; (&lt;code&gt;1&lt;/code&gt;) is "casted" to a &lt;code&gt;float&lt;/code&gt; and assigned to the variable &lt;code&gt;y&lt;/code&gt;. The type of &lt;code&gt;y&lt;/code&gt; is therefore &lt;code&gt;float&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x = 1
y = float(x)

print(type(x)) // =&amp;gt; outputs int 
print(type(y)) // =&amp;gt; outputs float

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  Your first Python programme
&lt;/h2&gt;

&lt;p&gt;It's finally time to write your first Python programme. You can write this anywhere on your machine, however, it is best practice to keep your development code in a specific place and well organized.&lt;/p&gt;

&lt;p&gt;Within your home directory (&lt;code&gt;$HOME&lt;/code&gt; on Linux and Mac, &lt;code&gt;%userprofile%&lt;/code&gt; on Windows) create a new directory called &lt;code&gt;python&lt;/code&gt; (e.g. the full Linux path would be &lt;code&gt;/home/codetips/python&lt;/code&gt; ). Navigate to this directory and create another directory called &lt;code&gt;firstApplication&lt;/code&gt; (e.g. the full Linux path would be &lt;code&gt;/home/codetips/python/firstApplication&lt;/code&gt;) and open it in your code editor of choice.&lt;/p&gt;

&lt;p&gt;We're going to leave out most of the specifics of Python best practices, so you're not overwhelmed with too much information, but everything will be explained in future articles.&lt;/p&gt;

&lt;p&gt;In your new &lt;code&gt;firstApplication&lt;/code&gt; directory, create a new file called &lt;code&gt;main.py&lt;/code&gt;, add the below code into it, and save the file.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/env python

# Start of our code

print("Welcome to my first Python programme!")

# End of our code

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

&lt;/div&gt;



&lt;p&gt;Now, open a terminal, navigate to your &lt;code&gt;firstApplication&lt;/code&gt; folder, and run the following command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;python main.py&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Your output should look very similar to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ [user@linux]: python main.py
Welcome to my first Python programme!

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

&lt;/div&gt;



&lt;p&gt;As you can see, the &lt;code&gt;print&lt;/code&gt; function outputs text to the terminal. Unfortunately, as a first programme goes, this is pretty boring. Let's make this more personal with &lt;a href="https://www.codetips.co.uk/beginner/what-is-a-variable/"&gt;Variables&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Replace the contents of &lt;code&gt;main.py&lt;/code&gt; with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/env python

# Start of our code

name = "Jordan"
age = 31
profession = "Developer"

print("""Welcome to my first Python programme!\n\
My name is {0}\n\
I am {1} years old\n\
I work as a {2}""".format(name, age, profession))

# End of our code

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

&lt;/div&gt;



&lt;p&gt;This time we're outputting four different sentences. One from the previous example and the other three are using the same &lt;code&gt;print&lt;/code&gt; function, but notice the &lt;code&gt;.format()&lt;/code&gt; function at the end of the string definition.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;"""&lt;/code&gt; statement in Python means that we are going to create a multi-line string.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;format&lt;/code&gt; function allows the programmer to pass variables through to the string. In the above example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;code&gt;name&lt;/code&gt; variable (in position &lt;code&gt;0&lt;/code&gt;, referenced in the string as &lt;code&gt;{0}&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;age&lt;/code&gt; variable (in position &lt;code&gt;1&lt;/code&gt;, referenced in the string as &lt;code&gt;{1}&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;profession&lt;/code&gt; variable (in position &lt;code&gt;2&lt;/code&gt;, referenced in the string as &lt;code&gt;{2}&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Knowing the position of the variables, also known as the &lt;code&gt;index&lt;/code&gt;, allows the programmer to repeat the same thing any number of times by simply referencing the position within the string. We will cover this in a future article.&lt;/p&gt;

&lt;p&gt;We can define strings in the following ways:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;string1 = "This is a string using double-qoutes"
string2 = 'This is a string using single-quotes"
string3 = `This is a string using back-ticks`
string4 = """This is a multi-line string \
using double-quotes"""
string5 = '''This is a multi-line string \
using single-quotes'''

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

&lt;/div&gt;



&lt;p&gt;It is best practice to use double-quotes by default, but all of the above are valid python syntax.&lt;/p&gt;

&lt;p&gt;Now see if you can complete the following challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Change the variables so the programme prints out &lt;strong&gt;your&lt;/strong&gt; name, age and profession.&lt;/li&gt;
&lt;li&gt;Change the programme to output everything on one line, instead of four lines.&lt;/li&gt;
&lt;li&gt;Add a new variable, &lt;code&gt;favoriteAnimal&lt;/code&gt; , and incorporate that into your outputted sentence.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tweet us at &lt;a href="https://twitter.com/realcodetips"&gt;@RealCodeTips&lt;/a&gt; and show us your solutions. If you get stuck along the way, reach out and we'll do our best to help.&lt;/p&gt;

&lt;p&gt;We've also set-up a Slack community to help people in more real-time. You can join us &lt;a href="https://join.slack.com/t/realcodetips/shared_invite/enQtNjQyNTg3MTM3MzAxLTc3ZmUzMDRmMzViNTUxZDdjOGVmMDM0YzVlYzI3ZGQ4NzM3ZWE2ZDk2NGU4ODBkMjIzZjdjOTUxZmU4Nzc3MjQ"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>tutorial</category>
      <category>learning</category>
      <category>python</category>
    </item>
  </channel>
</rss>
