<?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: David MacEachern</title>
    <description>The latest articles on DEV Community by David MacEachern (@davidmaceachern).</description>
    <link>https://dev.to/davidmaceachern</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%2F462158%2F2724ae2a-cbc7-4d9e-add1-011d9d2ec811.jpeg</url>
      <title>DEV Community: David MacEachern</title>
      <link>https://dev.to/davidmaceachern</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/davidmaceachern"/>
    <language>en</language>
    <item>
      <title>How do you work with someone else's fork?</title>
      <dc:creator>David MacEachern</dc:creator>
      <pubDate>Wed, 10 Feb 2021 13:34:51 +0000</pubDate>
      <link>https://dev.to/davidmaceachern/how-do-you-work-with-someone-else-s-fork-5fd7</link>
      <guid>https://dev.to/davidmaceachern/how-do-you-work-with-someone-else-s-fork-5fd7</guid>
      <description>&lt;p&gt;This might be useful if you want to work with a fork that someone else has started. I found a solution on Stackoverflow which described how to get their work into a branch that can be worked with. [1]&lt;/p&gt;

&lt;p&gt;They had forked the project we were &lt;a href="https://github.com/GREsau/rocket-lamb" rel="noopener noreferrer"&gt;talking&lt;/a&gt; about on Github, and in their local they checked out a branch of their own to work on, done some awesome work, and pushed their branch back to their &lt;a href="https://github.com/dbanty/rocket-lamb/tree/rocket-0.5" rel="noopener noreferrer"&gt;fork&lt;/a&gt; on Github.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Fork our own repository
&lt;/h2&gt;

&lt;p&gt;We can click on the fork button to make a repository of our own that we can work with.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Step 2: Clone our own repository to our local machine
&lt;/h2&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 bash
wsl@DESKTOP-DCRMGFD:~$ git clone git@github.com:davidmaceachern/rocket-lamb.git
Cloning into 'rocket-lamb'...
remote: Enumerating objects: 206, done.
remote: Total 206 (delta 0), reused 0 (delta 0), pack-reused 206
Receiving objects: 100% (206/206), 45.74 KiB | 564.00 KiB/s, done.
Resolving deltas: 100% (120/120), done.


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Step 3: Get the work that the other person has started into our fork
&lt;/h2&gt;

&lt;p&gt;I ran the following:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 bash
$ cd rocket-lamb
$ git remote add other git@github.com:dbanty/rocket-lamb.git
$ git fetch other
$ git checkout -b add-other-changes
$ git pull other rocket-0.5


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

&lt;/div&gt;

&lt;p&gt;The output looked like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 bash
wsl@DESKTOP-DCRMGFD:~$ cd rocket-lamb
wsl@DESKTOP-DCRMGFD:~/rocket-lamb$ git remote add other git@github.com:dbanty/rocket-lamb.git
wsl@DESKTOP-DCRMGFD:~/rocket-lamb$ git fetch other
remote: Enumerating objects: 15, done.
remote: Counting objects: 100% (15/15), done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 15 (delta 9), reused 15 (delta 9), pack-reused 0
Unpacking objects: 100% (15/15), 3.58 KiB | 215.00 KiB/s, done.
From github.com:dbanty/rocket-lamb
 * [new branch]      master     -&amp;gt; other/master
 * [new branch]      rocket-0.5 -&amp;gt; other/rocket-0.5
wsl@DESKTOP-DCRMGFD:~/rocket-lamb$ git checkout -b add-other-changes
 pull other rocket-0.5Switched to a new branch 'add-other-changes'
wsl@DESKTOP-DCRMGFD:~/rocket-lamb$ git pull other rocket-0.5
From github.com:dbanty/rocket-lamb
 * branch            rocket-0.5 -&amp;gt; FETCH_HEAD
Updating 6b28c56..6a995b1
Fast-forward
 Cargo.toml            |   9 +++--
 src/builder.rs        |  26 ++++++++-----
 src/handler.rs        | 220 ++++++++++++++++++++++++++++++++++++++++++++++---------------------------------------------------------
 src/request_ext.rs    |  56 +++++++++++++-------------
 tests/path_tests.rs   |   2 +-
 tests/rocket_tests.rs |  11 +++---
 6 files changed, 155 insertions(+), 169 deletions(-)


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Step 4: Make some changes then push to Github
&lt;/h2&gt;

&lt;p&gt;Once changes have been committed locally they can be pushed to our remote for others to benefit from. &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 bash
$ git push origin HEAD


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

&lt;/div&gt;

&lt;p&gt;They can then add our fork as an &lt;code&gt;other&lt;/code&gt; remote on their local so they make use of the work we did, if what we did was correct of course!&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Thoughts on this? Have you done something similar or maybe there is a better way to go about working with a fork?&lt;/p&gt;

&lt;p&gt;If this helped don't forget to go to Stackoverflow and upvote the solution provided there!&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;&lt;a id="1"&gt;[1]&lt;/a&gt; Git pull from someone else's fork &lt;a href="https://stackoverflow.com/questions/42156971/git-pull-from-someone-elses-fork#42157071" rel="noopener noreferrer"&gt;https://stackoverflow.com/questions/42156971/git-pull-from-someone-elses-fork#42157071&lt;/a&gt;&lt;/p&gt;

</description>
      <category>github</category>
      <category>opensource</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How understanding software versions can help you get unstuck</title>
      <dc:creator>David MacEachern</dc:creator>
      <pubDate>Fri, 15 Jan 2021 13:59:04 +0000</pubDate>
      <link>https://dev.to/davidmaceachern/how-understanding-sofware-versions-can-help-you-get-unstuck-33k7</link>
      <guid>https://dev.to/davidmaceachern/how-understanding-sofware-versions-can-help-you-get-unstuck-33k7</guid>
      <description>&lt;p&gt;Today I thought I would document how I got past a problem related to software versions that I encountered whilst using a tool on Windows Subsystem for Linux.&lt;/p&gt;

&lt;h2&gt;
  
  
  tl;dr
&lt;/h2&gt;

&lt;p&gt;In a more general sense, I remember when I started working with software tools 4 years ago, and it never occurred to me  that the problems we face working with software on a daily basis can often be solved by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Downgrading or upgrading the version we are using&lt;/li&gt;
&lt;li&gt;using workarounds provided by other individuals&lt;/li&gt;
&lt;li&gt;raising an issue ourselves with the maintainer, Stackoverflow, or asking elsewhere on the internet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example for the Rust ecosystem's package manager "Cargo" we can see the different versions available &lt;a href="https://github.com/rust-lang/cargo/releases"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;OK, so I recently ran into an issue &lt;a href="https://doc.rust-lang.org/cargo/reference/publishing.html"&gt;publishing&lt;/a&gt; a crate from Windows System for Linux (WSL) for the first time.&lt;/p&gt;

&lt;p&gt;It seems the &lt;code&gt;cargo publish&lt;/code&gt; command does not work when the repository is based in the mounted Windows directory.&lt;/p&gt;

&lt;p&gt;So the directories involved in this process look like.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;|-- ~/
|-- /mnt/c/Users/david/Documents/Github/nixy                                           
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see that my project is in the Windows user's documents folder.&lt;/p&gt;

&lt;h2&gt;
  
  
  Has someone else solved the problem?
&lt;/h2&gt;

&lt;p&gt;To avoid reinventing the wheel, also I didn't immediately think of where to go, I Googled the error message I received when I tried to run &lt;code&gt;cargo publish&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;There is an issue where this is being tracked &lt;a href="https://github.com/rust-lang/cargo/issues/8439"&gt;here&lt;/a&gt; and more technical detail about why this actually happens &lt;a href="https://github.com/rust-lang/cargo/pull/8950"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trying one of the workarounds
&lt;/h2&gt;

&lt;p&gt;Based on a comment in #8439 I took the following steps to fix my problem for the day.&lt;/p&gt;

&lt;p&gt;I checked whether the directory in the workaround existed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wsl@DESKTOP-DCRMGFD:/mnt/c/Users/david/Documents/GitHub/nixy&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I returned to the previous directory I was in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wsl@DESKTOP-DCRMGFD:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I went to the parent directory of the project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wsl@DESKTOP-DCRMGFD:/mnt/c/Users/david/Documents/Github/nixy&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ..
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I recursively copied the project to the WSL home folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;wsl@DESKTOP-DCRMGFD:/mnt/c/Users/david/Documents/Github/&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; ./nixy ~
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I navigated to the second project location in the WSL home folder and ran the publish command again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wsl@DESKTOP-DCRMGFD:/mnt/c/Users/david/Documents/Github&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~
wsl@DESKTOP-DCRMGFD:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls
&lt;/span&gt;nixy
wsl@DESKTOP-DCRMGFD:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;nixy
wsl@DESKTOP-DCRMGFD:~/nixy&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls
&lt;/span&gt;Cargo.toml  LICENSE  README.md  src  target  tests
wsl@DESKTOP-DCRMGFD:~/nixy&lt;span class="nv"&gt;$ &lt;/span&gt;cargo publish
    Updating crates.io index
   Packaging nixy v0.1.0 &lt;span class="o"&gt;(&lt;/span&gt;/home/wsl/nixy&lt;span class="o"&gt;)&lt;/span&gt;
   Verifying nixy v0.1.0 &lt;span class="o"&gt;(&lt;/span&gt;/home/wsl/nixy&lt;span class="o"&gt;)&lt;/span&gt;
   Compiling nixy v0.1.0 &lt;span class="o"&gt;(&lt;/span&gt;/home/wsl/nixy/target/package/nixy-0.1.0&lt;span class="o"&gt;)&lt;/span&gt;
    Finished dev &lt;span class="o"&gt;[&lt;/span&gt;unoptimized + debuginfo] target&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in &lt;/span&gt;2.53s
   Uploading nixy v0.1.0 &lt;span class="o"&gt;(&lt;/span&gt;/home/wsl/nixy&lt;span class="o"&gt;)&lt;/span&gt;
wsl@DESKTOP-DCRMGFD:~/nixy&lt;span class="nv"&gt;$ &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Do I have to use the workaround?
&lt;/h2&gt;

&lt;p&gt;No! You can now upgrade to the latest version of Cargo and this should work across the mounted &lt;code&gt;/mnt/c/&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;I did this by checking my installed Cargo version, which told me I'm on a version from 2020-10-14.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wsl@DESKTOP-DCRMGFD:~/nixy&lt;span class="nv"&gt;$ &lt;/span&gt;cargo &lt;span class="nt"&gt;--version&lt;/span&gt;
cargo 1.48.0 &lt;span class="o"&gt;(&lt;/span&gt;65cbdd2dc 2020-10-14&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I can see on #8950 that the fix was merged to master on 7th December.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QB-8VyLE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/9i0ww3n12wqpszioenoz.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QB-8VyLE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/9i0ww3n12wqpszioenoz.PNG" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So I update the rust toolchain, which in turn updates the &lt;code&gt;Cargo publish&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wsl@DESKTOP-DCRMGFD:/mnt/c/Users/david/Documents/Github&lt;span class="nv"&gt;$ &lt;/span&gt;rustup update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives me the following Rust version which is actually just before the fix was merged, might need to switch to the nightly channel to access 1.50 and any bug fixes associated with it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wsl@DESKTOP-DCRMGFD:/mnt/c/Users/david/Documents/Github&lt;span class="nv"&gt;$ &lt;/span&gt;cargo &lt;span class="nt"&gt;--version&lt;/span&gt;
cargo 1.49.0 &lt;span class="o"&gt;(&lt;/span&gt;d00d64df9 2020-12-05&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Thanks to those awesome people who contribute to the Rust ecosystem, mostly in their free time, to add fixes like the one I benefitted from in this post!&lt;/p&gt;

&lt;p&gt;I'll try to remember to update this post once I publish a new version of my Crate to test the problem.&lt;/p&gt;

&lt;p&gt;Feel free to join in the discussion below, until next time 👋.&lt;/p&gt;

</description>
      <category>github</category>
      <category>learning</category>
      <category>development</category>
      <category>rust</category>
    </item>
    <item>
      <title>It's time to unleash your social potential</title>
      <dc:creator>David MacEachern</dc:creator>
      <pubDate>Mon, 11 Jan 2021 18:12:47 +0000</pubDate>
      <link>https://dev.to/davidmaceachern/it-s-time-to-unleash-your-social-potential-17jg</link>
      <guid>https://dev.to/davidmaceachern/it-s-time-to-unleash-your-social-potential-17jg</guid>
      <description>&lt;p&gt;The issue I have had with social media in the past is only being able to see the negative aspects. I'm also someone that by default prefers to keep things fairly quiet, an air of mystery if ever that was a thing.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;social&lt;/strong&gt; &lt;em&gt;adjective&lt;/em&gt; - Of, relating to, or occupied with matters affecting human welfare. Of or relating to human society and its modes of organization. Interacting with other people and living in communities. [1]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The truth is all technology work is now online. I chose this career, and I have learned how to use technology to bring business value to organisations, why not to myself?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;potential&lt;/strong&gt; &lt;em&gt;adjective&lt;/em&gt; - Capable of being but not yet in existence; latent or undeveloped. &lt;em&gt;noun&lt;/em&gt; The inherent ability or capacity for growth, development, or future success. [2]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's time I opened my eyes to what has been staring me in my face the whole time. Having an online presence is important, it can demonstrate so many qualities in oneself but the most important one to me right now during Covid is connection. &lt;/p&gt;

&lt;p&gt;Working alone at home in quarantine, looking for a job is exhausting, and it's my first time tackling technical interviews. I have never done one, so have no idea how that is going to go. For now, my goal is to get to the interviews and see what companies expect. &lt;/p&gt;

&lt;p&gt;But &lt;strong&gt;how&lt;/strong&gt; can you connect with people?&lt;/p&gt;

&lt;h2&gt;
  
  
  Social media as a tool
&lt;/h2&gt;

&lt;p&gt;Like any tool, social media has potential, and success is made when we can use this potential to provide value. However when we forget to reason, "does this tool actually address a problem we are facing right now", this is when we don't get what we want.&lt;/p&gt;

&lt;p&gt;Too often I have reached to eliminate sources of distraction entirely but maybe there are other options we can consider. It actually might be more effective to understand how we want things to serve us, as Free solo famous Alex Honnold discusses in an interview about his work [3].&lt;/p&gt;

&lt;h2&gt;
  
  
  Is blogging social media?
&lt;/h2&gt;

&lt;p&gt;So let's talk about how this might go. Wikipedia describes a blog as consisting of "often informal diary-style text entries" [4]. And you can see on this &lt;a href="https://dev.to/"&gt;very blogging platform&lt;/a&gt; some &lt;a href="https://dev.to/softprops/dev-together-cno"&gt;cool&lt;/a&gt; &lt;a href="https://dev.to/saigowthamr/how-to-start-a-personal-blog-in-2020-and-grow-0-80k-views-15ja"&gt;examples&lt;/a&gt; of &lt;a href="https://dev.to/andrezzoid/remote-work-interviews-part-i-applying-519d"&gt;how&lt;/a&gt; you might &lt;a href="https://dev.to/aws-heroes/applying-the-well-architected-framework-small-edition-18fj"&gt;approach&lt;/a&gt; this &lt;a href="https://dev.to/davidmaceachern/learning-rust-collecting-data-from-an-api-2h51"&gt;opportunity&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ok great, so you have made your first blog post, so what? &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;validation&lt;/strong&gt; &lt;em&gt;noun&lt;/em&gt; The act of giving validity; a strengthening, enforcement, or confirming; an establishing or ratifying [5]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Validation gets a bad wrap, it can be an important element in the journey of discovering whether an idea is going to deliver some value. Will our customers like our product, will our developers enjoy their job, &lt;a href="https://dev.to/davidmaceachern/comment/194me"&gt;is my understanding of this subject correct&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;If we don't communicate with other human beings, then we miss out on a valuable chance to &lt;a href="https://github.com/softprops/devtogo/issues/8"&gt;improve&lt;/a&gt; our situation, there's always a way, right? &lt;/p&gt;

&lt;p&gt;We could think of blogging as a social media, a place we can connect with others.&lt;/p&gt;

&lt;h2&gt;
  
  
  But what about micro-blogging?
&lt;/h2&gt;

&lt;p&gt;Wikipedia, appears to explain microblogging[6] as a petite form of blogging, something that takes less time but allows you to share your thoughts all the same.&lt;/p&gt;

&lt;p&gt;Twitter is the atypical example of the microblog (I had a Myspace and a Bebo once upon a time but they might not be relevant anymore...). &lt;/p&gt;

&lt;p&gt;Yes you can use a microblog to kill time if that's what you really want, or you could build an inspiration machine, it's all a matter of perspective.&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;
      &lt;div class="ltag__twitter-tweet__media"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--z7wygos7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/media/ErZvl94W4AQRoo4.jpg" alt="unknown tweet media content"&gt;
      &lt;/div&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--jNUaBLNH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1045579977067024384/S0luKMwQ_normal.jpg" alt="Archillect profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Archillect
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        @archillect
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      21:54 PM - 10 Jan 2021
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1348387839235514369" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1348387839235514369" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1348387839235514369" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;Think of the ways that you could use a microblog to your &lt;a href="https://twitter.com/hashtag/MozillaLifeboat"&gt;advantage&lt;/a&gt;, maybe you can connect with people in ways you'd never imagined were possible. &lt;/p&gt;

&lt;p&gt;If you need more ideas for Twitter specifically, I can't find the tweet but &lt;a href="https://mobile.twitter.com/JoshWComeau"&gt;Josh W. Comeau&lt;/a&gt; shared a great guide, the link is in the references [7].&lt;/p&gt;

&lt;p&gt;For me, I'm starting here:&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Bk6xvP9m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1346475252851720193/aRvrK4ew_normal.jpg" alt="David MacEachern profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        David MacEachern
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        @maceacherndjh
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      A great listen if you're into Adventure, in essence, it's about finding what's challenging where you are as opposed to chasing what is expected by everyone else.&lt;br&gt;&lt;br&gt;&lt;a href="https://t.co/I8Tb1AmcfR"&gt;open.spotify.com/episode/1ZHPxY…&lt;/a&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      12:28 PM - 11 Jan 2021
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1348607648808259585" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1348607648808259585" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1348607648808259585" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;Let's see how this goes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Does this resonate with you? Are you looking for a job too? Or just feel like talking to someone? My messages are open, or comment down below so everyone else can join in!&lt;/p&gt;

&lt;p&gt;Have a great week!&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;&lt;a id="1"&gt;[1]&lt;/a&gt; Social &lt;a href="https://www.wordnik.com/words/social"&gt;https://www.wordnik.com/words/social&lt;/a&gt;&lt;br&gt;
&lt;a id="2"&gt;[2]&lt;/a&gt; Potential &lt;a href="https://www.wordnik.com/words/potential"&gt;https://www.wordnik.com/words/potential&lt;/a&gt;&lt;br&gt;
&lt;a id="3"&gt;[3]&lt;/a&gt; Alex Honnold talks about deleting social media amongst other things &lt;iframe width="710" height="399" src="https://www.youtube.com/embed/smi1wxnr0PI"&gt;
&lt;/iframe&gt;
&lt;br&gt;
&lt;a id="4"&gt;[4]&lt;/a&gt; Blogging &lt;a href="https://en.wikipedia.org/wiki/Blog"&gt;https://en.wikipedia.org/wiki/Blog&lt;/a&gt;&lt;br&gt;
&lt;a id="5"&gt;[5]&lt;/a&gt; Validation &lt;a href="https://www.wordnik.com/words/validation"&gt;https://www.wordnik.com/words/validation&lt;/a&gt;&lt;br&gt;
&lt;a id="6"&gt;[6]&lt;/a&gt; Microblogging &lt;a href="https://en.wikipedia.org/wiki/Microblogging"&gt;https://en.wikipedia.org/wiki/Microblogging&lt;/a&gt;&lt;br&gt;
&lt;a id="7"&gt;[7]&lt;/a&gt; Josh W. Comeau's helpful guide to Twitter &lt;a href="https://docs.google.com/document/d/1b7P71-OjEt5dHlgKEf9EbUBTkXRVrpDQaz7giXUd3n4"&gt;https://docs.google.com/document/d/1b7P71-OjEt5dHlgKEf9EbUBTkXRVrpDQaz7giXUd3n4&lt;/a&gt;&lt;/p&gt;

</description>
      <category>writing</category>
      <category>motivation</category>
      <category>learning</category>
    </item>
    <item>
      <title>How to generate Type Definitions for Distribution on NPM </title>
      <dc:creator>David MacEachern</dc:creator>
      <pubDate>Fri, 11 Dec 2020 13:35:31 +0000</pubDate>
      <link>https://dev.to/davidmaceachern/how-to-generate-type-definitions-for-distribution-on-npm-31mj</link>
      <guid>https://dev.to/davidmaceachern/how-to-generate-type-definitions-for-distribution-on-npm-31mj</guid>
      <description>&lt;h2&gt;
  
  
  tl;dr
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If in doubt create a toy application quickly using a project template, for Typescript this could be done using &lt;a href="https://tsdx.io/"&gt;tsdx&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A checklist of the things required to test from the point of view of the end user might be helpful, how will they consume the library in the end?&lt;/li&gt;
&lt;li&gt;It always helps to scroll through the docs to understand what the tools we are working with can do, to solve the problems I encountered whilst writing this I visited, &lt;a href="https://www.typescriptlang.org/docs/handbook/compiler-options.html"&gt;tsc&lt;/a&gt;, &lt;a href="https://babeljs.io/"&gt;babel&lt;/a&gt;, and &lt;a href="https://docs.npmjs.com/cli/v6"&gt;npm&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;I was recently testing out a web application, and in doing so I created a toy application and imported a small open-source library I had created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# main.ts
import { Nosozu } from 'nosozu';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;VS Code started giving me an error related to missing type definitions, despite having installed the package using npm before using &lt;code&gt;npm i nosozu&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;Cannot find module '@nosozu' or its corresponding type declarations.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What I did to generate type definitions
&lt;/h2&gt;

&lt;p&gt;In the tsconfig.json I added the field which tells the Typescript compiler to generate the type definition.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;{&lt;/span&gt;
+  "declaration": true,
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;package.json&lt;/code&gt; I checked what was declared as the &lt;code&gt;main&lt;/code&gt; entry point to the library, and then added a line for where the types will be located.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  "main": "dist/index.js",
&lt;span class="gi"&gt;+ "types": "dist/index.d.ts",
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Tidying up the NPM Package
&lt;/h2&gt;

&lt;p&gt;Checking the first version I published of &lt;code&gt;Nosozu&lt;/code&gt;, the user would install our package using &lt;code&gt;npm i nosozu@2.0.1-alpha&lt;/code&gt;, in doing so and checking what files are in &lt;code&gt;./node_modules/nosozu/&lt;/code&gt; they would find &lt;code&gt;49&lt;/code&gt; files totaling &lt;code&gt;63.6 kB&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Taking a look at other &lt;code&gt;node_module&lt;/code&gt; directories within the project, helped to understand what files are generally included when publishing a library like this.&lt;/p&gt;

&lt;p&gt;Then also reading about what the &lt;code&gt;.npmignore&lt;/code&gt; file is for over &lt;a href="https://docs.npmjs.com/cli/v6/using-npm/developers#testing-whether-your-npmignore-or-files-config-works"&gt;here&lt;/a&gt; helped in figuring out how to exclude sending things like test and example folders to npm.&lt;/p&gt;

&lt;p&gt;I then settled with adding the following allowed  list to the package.json&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gi"&gt;+  "files": [
+    "/dist"
+  ]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This led to a &lt;code&gt;node_modules&lt;/code&gt; directory structure like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
|-- node_modules
|   |-- nosozu
|   |   |-- LICENSE
|   |   |-- README.MD
|   |   |-- package.json
|   |   |-- CHANGELOG.md
|   |   |-- dist 
|   |   |   |-- command-builder.d.ts
|   |   |   |-- command-builder.js
|   |   |   |-- error.d.ts
|   |   |   |-- error.js
|   |   |   |-- index.d.ts
|   |   |   |-- index.js
|   |   |   |-- json-client.d.ts
|   |   |   |-- json-client.js
|   |   |   |-- protocol.d.ts
|   |   |   |-- protocol.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing the changes worked before publishing the fix
&lt;/h2&gt;

&lt;p&gt;Before publishing the new version I checked whether these changes fixed the original import issue. I did so by copying the contents of the &lt;code&gt;dist&lt;/code&gt; folder and the &lt;code&gt;package.json&lt;/code&gt; into the &lt;code&gt;node_modules/nosozu&lt;/code&gt; of the project I was testing in the beginning.&lt;/p&gt;

&lt;p&gt;In Bash this looked something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;playground-timber-nosozu/playground-timber-nosozu/
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ./node_modules/nosozu/                         &lt;span class="c"&gt;# remove the installed library&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; ./node_modules/nosozu                           &lt;span class="c"&gt;# make the folder again&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; ../../nosozu/dist/  ./node_modules/nosozu       &lt;span class="c"&gt;# copy the modified library with types&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; ../../nosozu/package.json  ./node_modules/nosozu   &lt;span class="c"&gt;# copy package.json so our application can see the "main" and "types" &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This could also be done using &lt;code&gt;npm link&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The changes to that project can be seen &lt;a href="https://github.com/davidmaceachern/playground-timber-nosozu/commit/f1b377c0e21c24e570664f9bb07581d2ec4ad94c"&gt;here&lt;/a&gt;, I did change the package name before publishing it to NPM, as well as messing around with unpublishing versions on NPM. If you do make mistakes it's possible to undo them but consider if there are any users that this might affect!&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Checking the &lt;a href="https://www.npmjs.com/package/nosozu"&gt;package&lt;/a&gt; again, the size has increased to &lt;code&gt;123 kB&lt;/code&gt; however the number of files has reduced to &lt;code&gt;15&lt;/code&gt;. I reinstalled this in the toy project and found everything appeared to be working, except for an error being thrown inside the library itself, work for another day!&lt;/p&gt;

&lt;p&gt;Maybe you want to learn more about Typescript, or maybe you know something I don't! &lt;/p&gt;

&lt;p&gt;Contributions of any sort are more than welcome, you can see open issues over &lt;a href="https://github.com/davidmaceachern/nosozu/issues"&gt;here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>npm</category>
      <category>typescript</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to query JSON data in the terminal</title>
      <dc:creator>David MacEachern</dc:creator>
      <pubDate>Tue, 24 Nov 2020 17:12:43 +0000</pubDate>
      <link>https://dev.to/davidmaceachern/how-to-query-json-data-in-the-terminal-3gin</link>
      <guid>https://dev.to/davidmaceachern/how-to-query-json-data-in-the-terminal-3gin</guid>
      <description>&lt;p&gt;Today we will be using &lt;code&gt;jq&lt;/code&gt; to work with JSON data, you should be able to get it &lt;a href="https://stedolan.github.io/jq/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  tl;dr
&lt;/h2&gt;

&lt;p&gt;Return top-level keys from multiple json files in present working directory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jq &lt;span class="nt"&gt;-rs&lt;/span&gt; &lt;span class="s1"&gt;'reduce .[] as $item ({}; . * $item) | keys[]'&lt;/span&gt; ./&lt;span class="k"&gt;*&lt;/span&gt;.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Get the data
&lt;/h2&gt;

&lt;p&gt;Go ahead and clone the assets if you want to work with this too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/davidmaceachern/playground-query-json.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Navigate to where the JSON documents are.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;playground-query-json/assets/requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Have a look at the JSON document names if you wish.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;add_backend.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prints the following as the contents.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"id"&lt;/span&gt;: &lt;span class="s2"&gt;"ID_TEST"&lt;/span&gt;,
  &lt;span class="s2"&gt;"version"&lt;/span&gt;: 0,
  &lt;span class="s2"&gt;"type"&lt;/span&gt;: &lt;span class="s2"&gt;"PROXY"&lt;/span&gt;,
  &lt;span class="s2"&gt;"data"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"type"&lt;/span&gt;: &lt;span class="s2"&gt;"ADD_BACKEND"&lt;/span&gt;,
    &lt;span class="s2"&gt;"data"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"app_id"&lt;/span&gt;: &lt;span class="s2"&gt;"xxx"&lt;/span&gt;,
      &lt;span class="s2"&gt;"backend_id"&lt;/span&gt;: &lt;span class="s2"&gt;"xxx-0"&lt;/span&gt;,
      &lt;span class="s2"&gt;"ip_address"&lt;/span&gt;: &lt;span class="s2"&gt;"127.0.0.1"&lt;/span&gt;,
      &lt;span class="s2"&gt;"port"&lt;/span&gt;: 8080
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Ok so FYI this is test data for a project I am working on.&lt;/p&gt;

&lt;p&gt;I need to decide on which properties I need the application to generate. The goal is to reduce them down as much as possible so the user only provides the items which they need to control and the application handles the rest.&lt;/p&gt;

&lt;p&gt;At this stage, each of these files can be considered 1 single dataset.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-1q&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;json | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we run the above command we should find there are &lt;code&gt;16&lt;/code&gt; files that match a '.json' ending.&lt;/p&gt;

&lt;h2&gt;
  
  
  Combine all the documents into a single dataset
&lt;/h2&gt;

&lt;p&gt;First we can print as we did using &lt;code&gt;cat&lt;/code&gt; before but using &lt;code&gt;jq&lt;/code&gt; instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jq &lt;span class="nb"&gt;.&lt;/span&gt; add_backend.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;jq&lt;/code&gt; is the application we are invoking. The &lt;code&gt;.&lt;/code&gt; represents the first argument &lt;code&gt;jq&lt;/code&gt; needs which is a filter, or a thing we want to do to change our input, which right now is nothing. The third item is the filename which is our input.&lt;/p&gt;

&lt;p&gt;Exactly the same but prettier:&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ID_TEST"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PROXY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&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;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ADD_BACKEND"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"data"&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;"app_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"backend_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxx-0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"ip_address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"127.0.0.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8080&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;Let's combine two files and see what that looks like.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jq &lt;span class="nb"&gt;.&lt;/span&gt; add_backend.json remove_backend.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which returns:&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ID_TEST"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PROXY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&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;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ADD_BACKEND"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"data"&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;"app_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"backend_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxx-0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"ip_address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"127.0.0.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8080&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="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ID_TEST"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PROXY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&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;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"REMOVE_BACKEND"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"data"&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;"app_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"backend_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxx-0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"ip_address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"127.0.0.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8080&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;Ok great but we want to merge all the files together, along with handling nested&lt;br&gt;
structures:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jq &lt;span class="nt"&gt;-rs&lt;/span&gt; &lt;span class="s1"&gt;'reduce .[] as $item ({}; . * $item)'&lt;/span&gt; ./&lt;span class="k"&gt;*&lt;/span&gt;.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which returns:&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ID_TEST"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"UPGRADE_MASTER"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&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;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"STATUS"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"data"&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;"app_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"hostname"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"yyy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"path_begin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"fingerprint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ab2618b674e15243fd02a5618c66509e4840ba60e7d64cebec84cdbfeceee0c5"&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;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./config_dump.json"&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;"proxy_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&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;We can output that result to a file to use later if we wish.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jq &lt;span class="nt"&gt;-rs&lt;/span&gt; &lt;span class="s1"&gt;'reduce .[] as $item ({}; . * $item)'&lt;/span&gt; ./&lt;span class="k"&gt;*&lt;/span&gt;.json &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ../aggregate.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For now though I only care about keys, so inside the &lt;code&gt;jq&lt;/code&gt; filter we can add a pipe&lt;br&gt;
which only returns the keys.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jq &lt;span class="nt"&gt;-rs&lt;/span&gt; &lt;span class="s1"&gt;'reduce keys[] as $item ({}; . * $item) | keys[]'&lt;/span&gt; ./&lt;span class="k"&gt;*&lt;/span&gt;.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which prints the unique top-level keys:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;data
&lt;span class="nb"&gt;id
&lt;/span&gt;proxy_id
&lt;span class="nb"&gt;type
&lt;/span&gt;version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great, now I might encounter more issues with the JSON request format further into development, but for now a quick look at these keys is exactly what I&lt;br&gt;
needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what?
&lt;/h2&gt;

&lt;p&gt;Ok so, if we were actually writing a bash script this might be helpful, or using a language such as Python we can actually use &lt;code&gt;jq&lt;/code&gt; queries inside our code using a package such as found &lt;a href="https://pypi.org/project/jq/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;jq&lt;/code&gt; is a great way to work with JSON data in the terminal, picking up knowledge of a couple of filters can come in handy. I've enjoyed using it in the past to explore JSON data and it can be handy for helping to make decisions. &lt;/p&gt;

&lt;p&gt;You can achieve similar things manually in VSCode, with JSON linting and copy/paste and find/replace but if it's a task you do over and over again it can be worthwhile to use tools like &lt;code&gt;jq&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I'm writing a Javascript application, so I could have done this type of thing inside my unit tests, as Javascript is great when it comes to JSON, but I thought to share this approach today.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.json.org/json-en.html"&gt;Introducing JSON&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/19529688/how-to-merge-2-json-objects-from-2-files-using-jq"&gt;How to merge 2 json objects from two files using jq&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>bash</category>
      <category>tip</category>
      <category>json</category>
    </item>
    <item>
      <title>How to fix Github Docker Containers Built with Actions</title>
      <dc:creator>David MacEachern</dc:creator>
      <pubDate>Thu, 12 Nov 2020 13:11:39 +0000</pubDate>
      <link>https://dev.to/davidmaceachern/how-to-fix-github-docker-containers-built-with-actions-162k</link>
      <guid>https://dev.to/davidmaceachern/how-to-fix-github-docker-containers-built-with-actions-162k</guid>
      <description>&lt;p&gt;Following on from having set up the Github Container Registry &lt;a href="https://dev.to/davidmaceachern/using-github-container-registry-15m0"&gt;in my previous post&lt;/a&gt; I look at how I can combine Github Actions with the Registry to automate the build step of my application.&lt;/p&gt;

&lt;h2&gt;
  
  
  tl;dr
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;You can use Github Actions to build containers based on Dockerfiles in your repository.&lt;/li&gt;
&lt;li&gt;Have a Google for the answer but don't hesitate to run your problematic containers interactively.&lt;/li&gt;
&lt;li&gt;You can build and interact with your Docker images locally &lt;code&gt;docker build .&lt;/code&gt; then &lt;code&gt;docker run -it $IMAGE_ID /bin/bash&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;I have a Dockerfile I am building to package up my application to be deployed somewhere, I do so using a Github Action upon pushing changes&lt;br&gt;
to Github.&lt;/p&gt;

&lt;p&gt;Github Actions have many example templates to base workflows on if you already have a project you can navigate to: &lt;code&gt;"https://github.com/" + $YOUR_USERNAME + "/" + $REPOSITORY_NAME + "/actions/new&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;When I create a Dockerfile, I develop locally and commit changes to the repository. Upon a push to Github my Action Workflow is triggered, this is &lt;a href="https://en.wikipedia.org/wiki/Continuous_integration"&gt;continuous integration (CI)&lt;/a&gt; at it's best, but when we need to look inside a container things can get a little tricky.&lt;/p&gt;

&lt;p&gt;What follows are some notes about how you might fix your CI container build.&lt;/p&gt;
&lt;h2&gt;
  
  
  Lessons learnt
&lt;/h2&gt;

&lt;p&gt;When I attempt to build this &lt;a href="https://github.com/davidmaceachern/rust-web-template/blob/9a9cce4215c5b875563bd2e14c6f73ad76829e5d/collector/Dockerfile"&gt;Dockerfile&lt;/a&gt;, which looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; rustlang/rust:nightly-slim AS build&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /src/rust-web-template&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ./collector &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cargo build &lt;span class="nt"&gt;--release&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; ..
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; ubuntu:18.04&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /src/rust-web-template/target/release/collector /usr/local/bin/collector&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["usr/local/bin/client"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here are some issues I ran into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;pkg-config&lt;/code&gt; is required for locating dependencies such as SSL within the container's linux.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;It looks like you&lt;span class="s1"&gt;'re compiling on Linux and also targeting Linux. Currently this
requires the `pkg-config` utility to find OpenSSL but unfortunately `pkg-config`
could not be found. If you have OpenSSL installed you can likely fix this by
installing `pkg-config`.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Docker container builds steps that require approval must have a yes flag passed to them &lt;code&gt;apt-get install -y pkg-config&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Do you want to &lt;span class="k"&gt;continue&lt;/span&gt;? &lt;span class="o"&gt;[&lt;/span&gt;Y/n] Abort.
The &lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="s1"&gt;'/bin/sh -c apt-get update &amp;amp;&amp;amp;     apt-get install pkg-config'&lt;/span&gt; returned a non-zero code: 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;We need to run &lt;code&gt;apt-get update&lt;/code&gt; to ensure our container knows where to get packages we want to install.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;E: Package &lt;span class="s1"&gt;'pkg-config'&lt;/span&gt; has no installation candidate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Dependencies such as Openssl need to be installed as well to be available when compiling an application that depends on it.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;run pkg_config fail: &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;pkg-config&lt;span class="se"&gt;\"&lt;/span&gt; &lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="nt"&gt;--libs&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt; &lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="nt"&gt;--cflags&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt; &lt;span class="se"&gt;\"&lt;/span&gt;openssl&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="s2"&gt; did not exit successfully: exit code: 1&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;--- stderr&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Package openssl was not found in the pkg-config search path.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Perhaps you should add the directory containing &lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;openssl.pc&lt;span class="se"&gt;\'\n&lt;/span&gt;to the PKG_CONFIG_PATH environment variable&lt;span class="se"&gt;\n&lt;/span&gt;No package &lt;span class="se"&gt;\'&lt;/span&gt;openssl&lt;span class="se"&gt;\'&lt;/span&gt; found&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How can we debug a Docker container without Googling?
&lt;/h2&gt;

&lt;p&gt;So our Dockerfile now looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; rustlang/rust:nightly-slim AS build&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /src/rust-web-template&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . ./collector&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; pkg-config &lt;span class="se"&gt;\
&lt;/span&gt;    libssl-dev
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ./collector &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cargo build &lt;span class="nt"&gt;--release&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; ..
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; ubuntu:18.04&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /src/rust-web-template/target/release/collector /usr/local/bin/collector&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["usr/local/bin/client"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I received the following error, which tells me that a directory path was not correct.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; COPY failed: &lt;span class="nb"&gt;stat&lt;/span&gt; /var/lib/docker/overlay2/640cf4644f3f681a1b78f9507d80e70f3cae1a189a65dfd6a1f26f7313748161/merged/src/rust-web-template/target/release/collector: no such file or directory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To fix this I comment out the code, as we need to build the container and then interact with it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;FROM rustlang/rust:nightly-slim AS build
WORKDIR /src/rust-web-template
COPY . ./collector
RUN apt-get update -y &amp;amp;&amp;amp; \
&lt;/span&gt;    apt-get install -y pkg-config \
    libssl-dev
&lt;span class="p"&gt;RUN cd ./collector &amp;amp;&amp;amp; cargo build --release &amp;amp;&amp;amp; cd ..
&lt;/span&gt;&lt;span class="gi"&gt;+ #FROM ubuntu:18.04
+ #COPY --from=build /src/rust-web-template/target/release/collector /usr/local/bin/collector
+ #CMD ["usr/local/bin/client"]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we build it by running &lt;code&gt;$ docker build -t debugimage .&lt;/code&gt;, and then we can run the container interactively to explore it &lt;code&gt;docker run -it --name debugimage:latest /bin/bash&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once inside we can run our bash commands to investigate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;t@d0e323387e63:/src/rust-web-template# &lt;span class="nb"&gt;ls
&lt;/span&gt;collector
root@d0e323387e63:/src/rust-web-template# &lt;span class="nb"&gt;cd &lt;/span&gt;collector/
root@d0e323387e63:/src/rust-web-template/collector# &lt;span class="nb"&gt;ls
&lt;/span&gt;Cargo.lock  Cargo.toml  Dockerfile  src  target
root@d0e323387e63:/src/rust-web-template/collector# &lt;span class="nb"&gt;cd tar
&lt;/span&gt;bash: &lt;span class="nb"&gt;cd&lt;/span&gt;: &lt;span class="nb"&gt;tar&lt;/span&gt;: No such file or directory
root@d0e323387e63:/src/rust-web-template/collector# &lt;span class="nb"&gt;cd &lt;/span&gt;target
root@d0e323387e63:/src/rust-web-template/collector/target# &lt;span class="nb"&gt;ls
&lt;/span&gt;CACHEDIR.TAG  release
root@d0e323387e63:/src/rust-web-template/collector/target# &lt;span class="nb"&gt;cd &lt;/span&gt;release/
root@d0e323387e63:/src/rust-web-template/collector/target/release# &lt;span class="nb"&gt;pwd&lt;/span&gt;
/src/rust-web-template/collector/target/release
root@d0e323387e63:/src/rust-web-template/collector/target/release# &lt;span class="nb"&gt;ls
&lt;/span&gt;build  collector  collector.d  deps  examples  incremental
root@d0e323387e63:/src/rust-web-template/collector/target/release# &lt;span class="nb"&gt;pwd&lt;/span&gt;
/src/rust-web-template/collector/target/release
root@d0e323387e63:/src/rust-web-template/collector/target/release#
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then update the path in the Docker container, and uncomment out lines that were not working.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- COPY --from=build /src/rust-web-template/target/release/collector /usr/local/bin/collector
&lt;/span&gt;&lt;span class="gi"&gt;+ COPY --from=build /src/rust-web-template/collector/target/release/collector /usr/local/bin/collector
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then we can &lt;code&gt;$ exit&lt;/code&gt; our interactive container session.&lt;/p&gt;

&lt;p&gt;Upon building the image again the path problem shouldn't cause the build to fail!&lt;/p&gt;

&lt;p&gt;The working code for this can be found &lt;a href="https://github.com/davidmaceachern/rust-web-template/blob/3b6d6566ebd0a5b1e445d3736ef6d7198360dabf/collector/Dockerfile"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;So that's a couple of common problems building linux containers, hopefully it won't happen again!&lt;/p&gt;

&lt;p&gt;Do you have better ways to resolve build problems?&lt;/p&gt;

&lt;p&gt;Feel free to share any thoughts or findings of your own down below 🙏🏻.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>actions</category>
      <category>github</category>
    </item>
    <item>
      <title>Using Github Container Registry</title>
      <dc:creator>David MacEachern</dc:creator>
      <pubDate>Sat, 07 Nov 2020 13:11:35 +0000</pubDate>
      <link>https://dev.to/davidmaceachern/using-github-container-registry-15m0</link>
      <guid>https://dev.to/davidmaceachern/using-github-container-registry-15m0</guid>
      <description>&lt;p&gt;Using Docker is common place, it's useful in various points of the SDLC, and solves some headaches when it comes to reproducing a code build on different architectures.&lt;/p&gt;

&lt;p&gt;I've been looking at setting up a container registry to enable some experimentation with Kubernetes, which requires having a registry for custom images, whether I will actually do anything with Kubernetes&lt;br&gt;
we will see.&lt;/p&gt;

&lt;p&gt;Today I discovered Github has a container registry service (or 'GHCR'), for personal use this is appealing with limits that are not so low that we cannot experiment with them.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Plan&lt;/th&gt;
&lt;th&gt;Storage&lt;/th&gt;
&lt;th&gt;Datatransfer out within Actions&lt;/th&gt;
&lt;th&gt;Datatransfer out without Actions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;500MB&lt;/td&gt;
&lt;td&gt;Unlimited&lt;/td&gt;
&lt;td&gt;1GB per month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pro&lt;/td&gt;
&lt;td&gt;2GB&lt;/td&gt;
&lt;td&gt;Unlimited&lt;/td&gt;
&lt;td&gt;10GB per month&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Luckily I have Pro plan so let's have a look at what we can do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Storing a container in the GHCR
&lt;/h2&gt;

&lt;p&gt;First we need to register our github container registry with our Docker client:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a token &lt;a href="https://github.com/settings/tokens"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Navigate to &lt;code&gt;"https://github.com/" + $YOUR_GITHUB_USER + "?package_type=Docker&amp;amp;tab=packages"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Read the instruction titled &lt;code&gt;# Step 1: Authenticate&lt;/code&gt; and understand what it needs, then run
this in your shell locally.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Next thing we need is a custom Dockerfile that we can upload to the registry, you can refer to this &lt;a href="https://github.com/davidmaceachern/playground-ghcr"&gt;repository&lt;/a&gt; if you're not sure how to proceed.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new Dockerfile in a local directory.&lt;/li&gt;
&lt;li&gt;Add the build you want, or stick in hello world build steps to keep it simple, remember we're
just here to test out GHCR.&lt;/li&gt;
&lt;li&gt;Build the image, if you used the repository I created then you might run &lt;code&gt;docker build -t playground-ghcr:latest .&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Then we will want to get the container image id, &lt;code&gt;docker image list&lt;/code&gt;, my image was 118MB in size,
which is within the limits mentioned previously.&lt;/li&gt;
&lt;li&gt;Continue with &lt;code&gt;# Step 2: Tag&lt;/code&gt; don't forget to understand what these commands will do that you're being asked to run!&lt;/li&gt;
&lt;li&gt;Piping &lt;code&gt;docker image list | grep ghcr&lt;/code&gt; should return the image with two tags now (or even more if you made mistakes like me!).&lt;/li&gt;
&lt;li&gt;Continue with &lt;code&gt;# Step 3: Publish&lt;/code&gt;, as I mentioned before I made a mistake where I didn't swap out the &lt;code&gt;/repository-name/&lt;/code&gt;, silly me!&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Reviewing usage
&lt;/h2&gt;

&lt;p&gt;So I uploaded an image that was 118MB in size and it took 6m 28s on my slow network speed.&lt;/p&gt;

&lt;p&gt;Pulling the image back down should begin using the quota we have on our Github plan.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We can remove the image we have locally &lt;code&gt;docker image rm -f $IMAGE_ID&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Then we can request the image we uploaded before from GHCR &lt;code&gt;docker pull docker.pkg.github.com/davidmaceachern/playground-ghcr/playground-ghcr:latest&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;After we can verify if we wish that this is indeed our Docker image &lt;code&gt;docker container run $IMAGE_ID&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Finally we can navigate &lt;a href="https://github.com/settings/billing"&gt;here&lt;/a&gt; to view billing details.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So a little disappointing, it appears that billing data might not be available until the quota resets &lt;code&gt;Data transfer quota resets in 4 days&lt;/code&gt;,&lt;br&gt;
or not at all given that the service is still in public beta:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;During the beta, storage and bandwidth is free.&lt;br&gt;
— &lt;a href="https://docs.github.com/en/free-pro-team@latest/packages/getting-started-with-github-container-registry/about-github-container-registry"&gt;Github&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Checking the recently released github cli &lt;a href="https://cli.github.com/manual/"&gt;docs&lt;/a&gt; there is no sign of a billing function. Maybe this data could be grabbed using the &lt;a href="https://cli.github.com/manual/gh_api"&gt;graphql&lt;/a&gt; feature?&lt;/p&gt;

&lt;h2&gt;
  
  
  What about Dockerhub?
&lt;/h2&gt;

&lt;p&gt;&lt;del&gt;When we compare the experience with Dockerhub for a second, the limits for private repositories appear to be much lower than those provided with the free tier of Dockerhub even after they &lt;a href="https://www.docker.com/increase-rate-limits"&gt;announced&lt;/a&gt; new rate limits for their service.&lt;/del&gt;&lt;/p&gt;

&lt;p&gt;Vincent kindly pointed out in the comments, that the billing details I referred to are for hidden repositories, Github is offering a very appealing pricing model.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The limits that you cite are only for private. If your containers are public then there are no limits, even for free accounts."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Docker has however provided a better way to obtain how much usage you have incurred which they explained &lt;a href="https://www.docker.com/blog/checking-your-current-docker-pull-rate-limits-and-status/"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So I will probably continue using the service until the official pricing is announced.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;So there ends a little investigation into using Github Container Registry, it seems like it's still a work in progress for Github but it should do the job for projects going forward.&lt;/p&gt;

&lt;p&gt;Feel free to share any thoughts or findings of your own down below if you want 🙏🏻.&lt;/p&gt;

</description>
      <category>git</category>
      <category>github</category>
    </item>
    <item>
      <title>Learning Rust: Collecting Data from an API</title>
      <dc:creator>David MacEachern</dc:creator>
      <pubDate>Fri, 11 Sep 2020 08:21:52 +0000</pubDate>
      <link>https://dev.to/davidmaceachern/learning-rust-collecting-data-from-an-api-2h51</link>
      <guid>https://dev.to/davidmaceachern/learning-rust-collecting-data-from-an-api-2h51</guid>
      <description>&lt;p&gt;Wondering where to begin with programming? Why not give Rust a try, and collect some data from an API as we go!&lt;/p&gt;

&lt;p&gt;In this article we will cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Find some data to use&lt;/li&gt;
&lt;li&gt;Query an API and handle some HTTP &lt;/li&gt;
&lt;li&gt;Collect some data saving it locally as JSON&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rust</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
