<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[<EQuimper />]]></title><description><![CDATA[A blog about full-stack web development.]]></description><link>https://equimper.com</link><generator>GatsbyJS</generator><lastBuildDate>Sat, 08 Aug 2020 14:51:21 GMT</lastBuildDate><item><title><![CDATA[Hey, I am Emanuel. Happy to see you there.]]></title><link>https://equimper.com/blog/about</link><guid isPermaLink="false">https://equimper.com/blog/about</guid><content:encoded>&lt;h4&gt;Intro&lt;/h4&gt;&lt;p&gt;I’m from Quebec, a city in the beautiful country call Canada. My current position it&amp;#x27;s &lt;strong&gt;Full-Stack Web &amp;amp; Mobile Developer&lt;/strong&gt; at &lt;a href=&quot;https://appandflow.com/&quot;&gt;AppAndFlow&lt;/a&gt;. I work mainly with this techs&lt;/p&gt;&lt;ul&gt;&lt;li&gt;React&lt;/li&gt;&lt;li&gt;React-Native&lt;/li&gt;&lt;li&gt;NodeJS&lt;/li&gt;&lt;li&gt;Laravel&lt;/li&gt;&lt;li&gt;GraphQL&lt;/li&gt;&lt;li&gt;Golang&lt;/li&gt;&lt;li&gt;MongoDB&lt;/li&gt;&lt;li&gt;PostgreSQL&lt;/li&gt;&lt;li&gt;Vue&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I’ve been doing this for more than 5 years now. Before that, I was in the Canadian Forces. I also work at &lt;a href=&quot;https://www.thinkful.com/&quot;&gt;Thinkful&lt;/a&gt; and &lt;a href=&quot;https://bloc.io&quot;&gt;Bloc&lt;/a&gt; where I am a mentor who helps student getting into the web development industry.&lt;/p&gt;&lt;p&gt;Besides that, I own a &lt;a href=&quot;https://www.youtube.com/channel/UC7R7bcH9-KEBDiGNP1mZnmw&quot;&gt;Youtube Channel&lt;/a&gt; where I teach web development. I try my best to give a good insight into how I think about working with certain problems. I help then getting into Javascript as well with server-side stuff.&lt;/p&gt;&lt;p&gt;When I&amp;#x27;m not working I still code some of my personal projects. Programming is more than just a work for me, this is a hobby, it&amp;#x27;s a &lt;strong&gt;passion&lt;/strong&gt;. But if I&amp;#x27;m not in front of a computer I pass all my time with my beautiful fiance and our two dogs. At the end of the year, a small little person will joins the family 😃.&lt;/p&gt;&lt;h4&gt;Why having this blog?&lt;/h4&gt;&lt;p&gt;This blog is a place for me to write down what I think. This helps me first with my English who is not my native language, and that also help me empty my brain. By doing this I hope I can help people with some of the thinking, tutorial or whatever stuff I wrote here.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[No title]]></title><link>https://equimper.com/blog/tailwind-ui-application</link><guid isPermaLink="false">https://equimper.com/blog/tailwind-ui-application</guid><content:encoded>&lt;blockquote&gt;&lt;p&gt;Hello, my name is &lt;strong&gt;Emanuel Quimper&lt;/strong&gt;. I’m from Quebec, Canada.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;A little bit about myself. First I was in the &lt;em&gt;Army&lt;/em&gt; for 7 years before starting to program in 2015.
I’m very passionate and programming has become more than a job for me, a hobby.
I code all the time if I’m not with my family &lt;code&gt;I’m the father of a 1 year old little boy&lt;/code&gt;.
From the start I was already sharing my knowledge to everyone who wanted it.
I became a mentor at &lt;a href=&quot;https://www.thinkful.com/&quot;&gt;Thinkful&lt;/a&gt; and &lt;a href=&quot;https://www.bloc.io/&quot;&gt;Bloc&lt;/a&gt; in 2016.
, just one year later, because I was programming &lt;strong&gt;80+ hrs a week&lt;/strong&gt; and when I was not working I was studying.
I was always helping students on slack too so it did help me to get a bit more knowledge for my little experience at the time.&lt;/p&gt;&lt;p&gt;I also started around this time a &lt;a href=&quot;https://youtube.com/c/equimper&quot;&gt;Youtube channel&lt;/a&gt; where I make tutorial
on anything on react/react native/javascript. The plan here is that everyone can help people on with programming.
You always have more experience than some people.&lt;/p&gt;&lt;p&gt;I’ve been into node from the start of my career but Adam did change it when
I did look at his youtube video on Kitetail etc. TDD was new for me and I was amazed by
his working flow. In node it is so hard to do this without plugin so many things together.
So I decided to give &lt;strong&gt;Laravel&lt;/strong&gt; a chance. From this day for my own client cause yes
I work at a react/react-native/node agency,
I do use Laravel with vue and react native if mobile need. When tailwind came I was an early adopter.
Of course I like using new stuff even if not version 1 but Tailwind was so promising.
I even did created a &lt;a href=&quot;https://github.com/EQuimper/react-native-design-utility&quot;&gt;library&lt;/a&gt; to make use of the idea of Tailwind for react-native. I do use
this one on many of my client projects
like &lt;a href=&quot;https://point.app&quot;&gt;Point&lt;/a&gt;, &lt;a href=&quot;https://www.tryfixit.ca/&quot;&gt;Fixit&lt;/a&gt; and &lt;a href=&quot;https://www.jiveworld.com/&quot;&gt;Jiveworld&lt;/a&gt;.&lt;/p&gt;&lt;h3&gt;Why would I be a good fit for Tailwind UI?&lt;/h3&gt;&lt;p&gt;I’m someone who &lt;strong&gt;loves to work and give his maximum&lt;/strong&gt; but at the same time, I know how important is it to enjoy lifetime with my family, friends etc.
From what I saw from you online its look like you have the same mindset as me.
I’m also a &lt;strong&gt;quick learner&lt;/strong&gt;, and when I’m passionate about something
I can’t stop looking and playing with it. I remember in one of your &lt;code&gt;Full stack radio&lt;/code&gt; episodes you mention you are
the same. Yes I&amp;#x27;m a listener of your podcast for the past 2 years now and listen to all episodes.
I’m also someone who want to &lt;strong&gt;get more into open source&lt;/strong&gt;. But the projects  that I look at are
not something I want to get into. Tailwind was something I wanted to help in the past
but didn’t have the time at this moment because my clients of last year were all mobile and the brand new baby.
I think I can also help Adam on how to use Tailwind UI etc by doing &lt;strong&gt;livestream and tutorial using it&lt;/strong&gt;.
I want to spread how it’s a joy working with it.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;I am convinced that I am the person you need to grow your business.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;P.S Yes this blog use Tailwind, didn&amp;#x27;t update it but that was pre v1 :)&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Build a REST API with AdonisJs and TDD Part 4]]></title><description><![CDATA[Want to learn how to use AdonisJs by building a rest api using TDD approach? This is the tutorial you want]]></description><link>https://equimper.com/blog/build-a-rest-api-with-adonisjs-and-tdd-part-4</link><guid isPermaLink="false">https://equimper.com/blog/build-a-rest-api-with-adonisjs-and-tdd-part-4</guid><category><![CDATA[tutorial]]></category><category><![CDATA[adonisjs]]></category><category><![CDATA[tdd]]></category><category><![CDATA[javascript]]></category><category><![CDATA[testing]]></category><pubDate>Thu, 21 Nov 2019 00:00:00 GMT</pubDate><content:encoded>&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://equimper.com/blog/build-a-rest-api-with-adonisjs-and-tdd-part-1&quot;&gt;Part 1&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://equimper.com/blog/build-a-rest-api-with-adonisjs-and-tdd-part-2&quot;&gt;Part 2&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://equimper.com/blog/build-a-rest-api-with-adonisjs-and-tdd-part-3&quot;&gt;Part 3&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/EQuimper/adonis-tdd-tutorial-demo&quot;&gt;Source Code&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Intro&lt;/h2&gt;&lt;p&gt;In this part number 4, we will continue working on our API. But now we will also make a request to another service call &lt;a href=&quot;https://www.themoviedb.org&quot;&gt;TheMovieDB Api&lt;/a&gt;.
This is finally an API where we can get info about a certain movie. In this part, we will create a new controller where the user will able to search
for a certain movie title. We first check if the movie already exists in our database. If not we then query the 3rd party API to get the info. When we got
that info we will persist them in our own database.&lt;/p&gt;&lt;p&gt;First, we will create a test call &lt;code&gt;SearchMovie&lt;/code&gt; this will be another functional one.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;adonis make:test SearchMovie
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The first few tests will be just about the fact those movies are already inside our
database. This will make this simpler. Later for the test, we will mock &lt;strong&gt;TheMovieDB&lt;/strong&gt;
so this way we will not exceed our request quotas.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// test/functional/search-movie.spec.js

&amp;#x27;use strict&amp;#x27;

const Factory = use(&amp;#x27;Factory&amp;#x27;)
const { test, trait } = use(&amp;#x27;Test/Suite&amp;#x27;)(&amp;#x27;Search Movie&amp;#x27;)

trait(&amp;#x27;Test/ApiClient&amp;#x27;)
trait(&amp;#x27;Auth/Client&amp;#x27;)

test(&amp;#x27;can query for a certain movie title&amp;#x27;, async ({ assert, client }) =&amp;gt; {
  await Factory.model(&amp;#x27;App/Models/Movie&amp;#x27;).create({ title: &amp;#x27;Joker&amp;#x27; })

  const response = await client.get(&amp;#x27;/api/movies?title=Joker&amp;#x27;).end();

  response.assertStatus(200)
  response.assertJSONSubset([{
    title: &amp;#x27;Joker&amp;#x27;,
  }])
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you run the test you will get an error like this&lt;/p&gt;&lt;pre&gt;&lt;code&gt;can query for a certain movie title
  TypeError: Cannot read property &amp;#x27;name&amp;#x27; of undefined
    at Factory.model
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This means we didn&amp;#x27;t define yet our factory for the movie.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; metastring=&quot;{34-39}&quot;&gt;// database/factory.js

&amp;#x27;use strict&amp;#x27;

/*
|--------------------------------------------------------------------------
| Factory
|--------------------------------------------------------------------------
|
| Factories are used to define blueprints for database tables or Lucid
| models. Later you can use these blueprints to seed your database
| with dummy data.
|
*/

/** @type {import(&amp;#x27;@adonisjs/lucid/src/Factory&amp;#x27;)} */
const Factory = use(&amp;#x27;Factory&amp;#x27;)

Factory.blueprint(&amp;#x27;App/Models/User&amp;#x27;, faker =&amp;gt; {
  return {
    username: faker.username(),
    email: faker.email(),
    password: &amp;#x27;password123&amp;#x27;
  }
})

Factory.blueprint(&amp;#x27;App/Models/Challenge&amp;#x27;, faker =&amp;gt; {
  return {
    title: faker.sentence(),
    description: faker.sentence()
  }
})

Factory.blueprint(&amp;#x27;App/Models/Movie&amp;#x27;, (faker, index, data) =&amp;gt; {
  return {
    title: faker.sentence(),
    ...data
  }
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you check, the factory take 3 arguments and the third one is for getting data from when you call the factory. So you can overide value just like that.&lt;/p&gt;&lt;p&gt;If you rerun the test with &lt;code&gt;npm t&lt;/code&gt; you will get now a new error. This error is about the fact then we
do not have yet a model &lt;code&gt;Movie&lt;/code&gt; and our factory tries to create one with it. For this run the command&lt;/p&gt;&lt;pre&gt;&lt;code&gt;adonis make:model Movie -m
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you remember the &lt;code&gt;-m&lt;/code&gt; means give me a migration file at the same time. We will just win some time with this.&lt;/p&gt;&lt;p&gt;Now the test will show this&lt;/p&gt;&lt;pre&gt;&lt;code&gt;Error: SQLITE_ERROR: table movies has no column named title
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Pretty self explain the error, we try to add a title to but no column yet is defined. Time to add this to the migration file we just did create.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; metastring=&quot;{11}&quot;&gt;&amp;#x27;use strict&amp;#x27;

/** @type {import(&amp;#x27;@adonisjs/lucid/src/Schema&amp;#x27;)} */
const Schema = use(&amp;#x27;Schema&amp;#x27;)

class MovieSchema extends Schema {
  up () {
    this.create(&amp;#x27;movies&amp;#x27;, (table) =&amp;gt; {
      table.increments()

      table.string(&amp;#x27;title&amp;#x27;).notNullable()

      table.timestamps()
    })
  }

  down () {
    this.drop(&amp;#x27;movies&amp;#x27;)
  }
}

module.exports = MovieSchema
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After this we get&lt;/p&gt;&lt;pre&gt;&lt;code&gt;expected 404 to equal 200
404 =&amp;gt; 200
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Normal the route is not created yet. Add this to your &lt;code&gt;routes.js&lt;/code&gt; file&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// start/routes.js

Route.group(() =&amp;gt; {
  Route.get(&amp;#x27;/&amp;#x27;, &amp;#x27;MovieController.index&amp;#x27;)
}).prefix(&amp;#x27;/api/movies&amp;#x27;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now almost the same error but if you check carefully you will see now the error is about a &lt;code&gt;500&lt;/code&gt; error not &lt;code&gt;404&lt;/code&gt; like before. It&amp;#x27;s because the controller does not exist yet.&lt;/p&gt;&lt;p&gt;Time to make an &lt;strong&gt;HTTP&lt;/strong&gt; controller&lt;/p&gt;&lt;pre&gt;&lt;code&gt;adonis make:controller Movie
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ooooh, same error? Yes, we did use a method called &lt;code&gt;index&lt;/code&gt; but our controller is empty.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; metastring=&quot;{6-8}&quot;&gt;// app/Controllers/Http/MovieController.js

&amp;#x27;use strict&amp;#x27;

class MovieController {
  async index({}) {

  }
}

module.exports = MovieController
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It&amp;#x27;s time now to do some stuff to fix the new error about &lt;code&gt;204&lt;/code&gt; for &lt;code&gt;no-content&lt;/code&gt;.
We first need to get the query title and after this fetch our database with this and return that with a &lt;code&gt;200&lt;/code&gt; status code.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; metastring=&quot;{8-14}&quot;&gt;// app/Controllers/Http/MovieController.js

&amp;#x27;use strict&amp;#x27;

const Movie = use(&amp;#x27;App/Models/Movie&amp;#x27;)

class MovieController {
  async index({ request, response }) {
    const movies = await Movie.query()
      .where(&amp;#x27;title&amp;#x27;, request.input(&amp;#x27;title&amp;#x27;))
      .fetch()

    return response.ok(movies)
  }
}

module.exports = MovieController
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The input method in the request object gives us a way to fetch the query argument we want. In this case that was the title where we did put &lt;code&gt;Joker&lt;/code&gt; in it. If you run your test at this point this will work.
But... I don&amp;#x27;t like that. First, in this way of doing, we need a match of 100% the title. What happens if the user just put &lt;code&gt;jok&lt;/code&gt; and not the full &lt;code&gt;Joker&lt;/code&gt; title. Time to create a new test for this case.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;test(&amp;#x27;can query with a subset of the title&amp;#x27;, async ({ assert, client }) =&amp;gt; {
  await Factory.model(&amp;#x27;App/Models/Movie&amp;#x27;).create({ title: &amp;#x27;Joker&amp;#x27; })

  const response = await client.get(&amp;#x27;/api/movies?title=jok&amp;#x27;).end();

  response.assertStatus(200)
  response.assertJSONSubset([{
    title: &amp;#x27;Joker&amp;#x27;,
  }])
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now when you run the test we see that fail. Time to make use of a real query search&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; metastring=&quot;{9,12}&quot;&gt;// app/Controllers/Http/MovieController.js

&amp;#x27;use strict&amp;#x27;

const Movie = use(&amp;#x27;App/Models/Movie&amp;#x27;)

class MovieController {
  async index({ request, response }) {
    const title = request.input(&amp;#x27;title&amp;#x27;)

    const movies = await Movie.query()
      .where(&amp;#x27;title&amp;#x27;, &amp;#x27;LIKE&amp;#x27;, `%${title}%`)
      .fetch()

    return response.ok(movies)
  }
}

module.exports = MovieController
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now this works with this change. This will make sure if a subset of the title is present at least we still give the movie to the user.&lt;/p&gt;&lt;p&gt;Time to force the user to provide a title pretty simple one here too&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;test(&amp;#x27;should throw 400 if no title is pass&amp;#x27;, async ({ assert, client }) =&amp;gt; {
  const response = await client.get(&amp;#x27;/api/movies&amp;#x27;).end()

  response.assertStatus(400)
})
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; metastring=&quot;{11-13}&quot;&gt;// app/Controllers/Http/MovieController.js

&amp;#x27;use strict&amp;#x27;

const Movie = use(&amp;#x27;App/Models/Movie&amp;#x27;)

class MovieController {
  async index({ request, response }) {
    const title = request.input(&amp;#x27;title&amp;#x27;)

    if (!title) {
      return response.status(400).json({ error: &amp;#x27;title is required&amp;#x27; })
    }

    const movies = await Movie.query()
      .where(&amp;#x27;title&amp;#x27;, &amp;#x27;LIKE&amp;#x27;, `%${title}%`)
      .fetch()

    return response.ok(movies)
  }
}

module.exports = MovieController
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;In the next part, we will jump on the &lt;code&gt;TheMovieDB&lt;/code&gt; API stuff. We will learn how we can mock an external API so it&amp;#x27;s easier to test.&lt;/p&gt;&lt;p&gt;I hope you enjoy the post. Don&amp;#x27;t hesitate to comment below.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Golang Rest API for NodeJS developer - Part 2]]></title><description><![CDATA[How to create a Golang Rest API coming from a NodeJS background. How to setup Register logic.]]></description><link>https://equimper.com/blog/golang-rest-api-for-nodejs-developer-part-2</link><guid isPermaLink="false">https://equimper.com/blog/golang-rest-api-for-nodejs-developer-part-2</guid><category><![CDATA[nodejs]]></category><category><![CDATA[tutorial]]></category><category><![CDATA[golang]]></category><pubDate>Mon, 18 Nov 2019 00:00:00 GMT</pubDate><content:encoded>&lt;style data-emotion-css=&quot;5ssy5t&quot;&gt;.css-5ssy5t{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;margin-left:auto;margin-right:auto;width:100%;}@media (min-width:1200px){.css-5ssy5t{width:75%;}}&lt;/style&gt;&lt;div class=&quot;css-5ssy5t&quot;&gt;&lt;iframe width=&quot;100%&quot; height=&quot;500&quot; src=&quot;https://www.youtube.com/embed/QAkoaVMCS0k&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot;&gt;&lt;/iframe&gt;&lt;style data-emotion-css=&quot;1s7ndt1&quot;&gt;.css-1s7ndt1{border-radius:.25rem;margin-top:2rem;padding-top:1rem;padding-bottom:1rem;padding-left:2rem;padding-right:2rem;-webkit-align-self:flex-end;-ms-flex-item-align:end;align-self:flex-end;box-shadow:0 2px 4px 0 rgba(0,0,0,.1);color:#fff;font-weight:700;text-align:center;-webkit-text-decoration:none;text-decoration:none;background-color:#ff0000;}&lt;/style&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noreferrer&quot; href=&quot;https://www.youtube.com/equimper?sub_confirmation=1&quot; class=&quot;css-1s7ndt1&quot;&gt;Subscribe&lt;/a&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://equimper.com/blog/golang-rest-api-for-nodejs-developer-intro&quot;&gt;Intro&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://equimper.com/blog/golang-rest-api-for-nodejs-developer-part-1&quot;&gt;Part 1&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Golang Rest API for NodeJS developer - Part 2&lt;/h2&gt;&lt;p&gt;In part 1 we did set up the foundation of our REST API. In this part, we will set up the Register logic for our authentication portion of the app.
Authentication is a big part of almost every app we need to build as a developer. One thing it&amp;#x27;s because is so common you can almost translate the knowledge
earn in other languages. In our case for this tutorial, we will use a simple JWT authentication with an email/password combination.
Later I maybe plan to add Google OAuth.&lt;/p&gt;&lt;p&gt;The first thing to do is to create the &lt;code&gt;User&lt;/code&gt; struct. Pretty standard stuff. An id who will be auto-increment by PostgreSQL. Some timestamps so we know when the user did get created or updated.
You can also see the JSON tag. If you look at the &lt;code&gt;password&lt;/code&gt; I use &lt;code&gt;-&lt;/code&gt;, this means we do not want the password to get return to the JSON client.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;// domain/users.go

package domain

import &amp;quot;time&amp;quot;

type User struct {
    ID       int64  `json:&amp;quot;id&amp;quot;`
    Username string `json:&amp;quot;username&amp;quot;`
    Email    string `json:&amp;quot;email&amp;quot;`
    Password string `json:&amp;quot;-&amp;quot;`

    CreatedAt time.Time `json:&amp;quot;createdAt&amp;quot;`
    UpdatedAt time.Time `json:&amp;quot;updatedAt&amp;quot;`
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After this, we will create 3 instances of error. This will make our life easier in the long run of the app.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;// domain/errors.go

package domain

import &amp;quot;errors&amp;quot;

var (
    ErrNoResult = errors.New(&amp;quot;no result&amp;quot;)
    ErrUserWithEmailAlreadyExist = errors.New(&amp;quot;user with email already exist&amp;quot;)
    ErrUserWithUsernameAlreadyExist = errors.New(&amp;quot;user with username already exist&amp;quot;)
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;One thing I like when I work with Go is creating the interface need to make the app work before even starting writing the logic. The interface
will be like a contract and make sure my code will follow this. Time to jump on the &lt;code&gt;UserRepo&lt;/code&gt; interface who will be our layer to the database
for the user stuff. I also create a Domain struct who will keep the DB instance. So we can make sure we have only one instance of this last one.
This will also make life easier and no cycle dependencies issue.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;// domain/domain.go
package domain

type UserRepo interface {
    GetByEmail(email string) (*User, error)
    GetByUsername(username string) (*User, error)
    Create(user *User) (*User, error)
}

type DB struct {
    UserRepo UserRepo
}

type Domain struct {
    DB DB
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;With that, we can start creating the auth domain logic. First, we create a payload struct who will capture the client data request.
After this, the Register method will do the logic for creating a user to our app. This one will also handle the error if a user exists for both the
email or username, we want those to be unique. Finally, we create a method setPassword that will be filled in later part.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;// domain/auth.go
package domain

type RegisterPayload struct {
    Email           string `json:&amp;quot;email&amp;quot;`
    Password        string `json:&amp;quot;password&amp;quot;`
    ConfirmPassword string `json:&amp;quot;confirmPassword&amp;quot;`
    Username        string `json:&amp;quot;username&amp;quot;`
}

func (d *Domain) Register(payload RegisterPayload) (*User, error) {
    userExist, _ := d.DB.UserRepo.GetByEmail(payload.Email)
    if userExist != nil {
        return nil, ErrUserWithEmailAlreadyExist
    }

    userExist, _ = d.DB.UserRepo.GetByUsername(payload.Username)
    if userExist != nil {
        return nil, ErrUserWithUsernameAlreadyExist
    }

    password, err := d.setPassword(payload.Password)
    if err != nil {
        return nil, err
    }

    data := &amp;amp;User{
        Username: payload.Username,
        Email:    payload.Email,
        Password: *password,
    }

    user, err := d.DB.UserRepo.Create(data)
    if err != nil {
        return nil, err
    }

    return user, nil
}

func (d *Domain) setPassword(password string) (*string, error) {
    return nil, nil
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After this, we can add the domain to your server struct. This will make the domain available to this one inside the handlers.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot; metastring=&quot;{11,15,28,29,32,33}&quot;&gt;// handlers/handlers.go

package handlers

import (
    &amp;quot;time&amp;quot;

    &amp;quot;github.com/go-chi/chi&amp;quot;
    &amp;quot;github.com/go-chi/chi/middleware&amp;quot;

    &amp;quot;todo/domain&amp;quot;
)

type Server struct {
    domain *domain.Domain
}

func setupMiddleware(r *chi.Mux) {
    r.Use(middleware.RequestID)
    r.Use(middleware.RealIP)
    r.Use(middleware.Compress(6, &amp;quot;application/json&amp;quot;))
    r.Use(middleware.Logger)
    r.Use(middleware.Recoverer)
    r.Use(middleware.URLFormat)
    r.Use(middleware.Timeout(60 * time.Second))
}

func NewServer(domain *domain.Domain) *Server {
    return &amp;amp;Server{domain: domain}
}

func SetupRouter(domain *domain.Domain) *chi.Mux {
    server := NewServer(domain)

    r := chi.NewRouter()

    setupMiddleware(r)

    server.setupEndpoints(r)

    return r
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we can create our &lt;code&gt;users&lt;/code&gt; handlers. Think of it as a controller. I like a thin controller in other frameworks like &lt;code&gt;Laravel&lt;/code&gt; so here I follow
the same idea.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;// handlers/users.go

package handlers

import &amp;quot;net/http&amp;quot;

func (s *Server) registerUser() http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        user, err := s.domain.Register()
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can jump after this to our data layer. Remember in the intro I did say we will use Postgres. So we will add a &lt;code&gt;UserRepo&lt;/code&gt; to this Postgres package.
This one will follow the &lt;code&gt;UserRepo&lt;/code&gt; interface from our domain. This will be standard ORM stuff.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;// postgres/user.go

package postgres

import (
    &amp;quot;errors&amp;quot;

    &amp;quot;github.com/go-pg/pg/v9&amp;quot;

    &amp;quot;todo/domain&amp;quot;
)

type UserRepo struct {
    DB *pg.DB
}

func (u *UserRepo) GetByEmail(email string) (*domain.User, error) {
    user := new(domain.User)

    err := u.DB.Model(user).Where(&amp;quot;email = ?&amp;quot;, email).First()
    if err != nil {
        if errors.Is(err, pg.ErrNoRows) {
            return nil, domain.ErrNoResult
        }

        return nil, err
    }

    return user, nil
}

func (u *UserRepo) GetByUsername(username string) (*domain.User, error) {
    user := new(domain.User)

    err := u.DB.Model(user).Where(&amp;quot;username = ?&amp;quot;, username).First()
    if err != nil {
        if errors.Is(err, pg.ErrNoRows) {
            return nil, domain.ErrNoResult
        }

        return nil, err
    }

    return user, nil
}

func (u *UserRepo) Create(user *domain.User) (*domain.User, error) {
    _, err := u.DB.Model(user).Returning(&amp;quot;*&amp;quot;).Insert()
    if err != nil {
        return nil, err
    }

    return user, nil
}

func NewUserRepo(DB *pg.DB) *UserRepo {
    return &amp;amp;UserRepo{DB: DB}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Time to update our &lt;code&gt;main.go&lt;/code&gt; with the latest change needed.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot; metastring=&quot;{13,27-29,31,33}&quot;&gt;// main.go

package main

import (
    &amp;quot;fmt&amp;quot;
    &amp;quot;log&amp;quot;
    &amp;quot;net/http&amp;quot;
    &amp;quot;os&amp;quot;

    &amp;quot;github.com/go-pg/pg/v9&amp;quot;

    &amp;quot;todo/domain&amp;quot;
    &amp;quot;todo/handlers&amp;quot;
    &amp;quot;todo/postgres&amp;quot;
)

func main() {
    DB := postgres.New(&amp;amp;pg.Options{
        User:     &amp;quot;postgres&amp;quot;,
        Password: &amp;quot;postgres&amp;quot;,
        Database: &amp;quot;todo_dev&amp;quot;,
    })

    defer DB.Close()

    domainDB := domain.DB{
        UserRepo: postgres.NewUserRepo(DB),
    }

    d := &amp;amp;domain.Domain{DB: domainDB}

    r := handlers.SetupRouter(d)

    port := os.Getenv(&amp;quot;PORT&amp;quot;)
    if port == &amp;quot;&amp;quot; {
        port = &amp;quot;8081&amp;quot;
    }

    err := http.ListenAndServe(fmt.Sprintf(&amp;quot;:%s&amp;quot;, port), r)
    if err != nil {
        log.Fatalf(&amp;quot;cannot start server %v&amp;quot;, err)
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;If you did like this tutorial don&amp;#x27;t forget to subscribe to my newsletter below. Also, the video link is at the top of the post.
If you have any question don&amp;#x27;t hesitate to ask in the comment section below.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://bit.ly/2QyhHIN&quot;&gt;Code for this part&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Happy Coding :)&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Golang Rest API for NodeJS developer - Part 1]]></title><description><![CDATA[How to create a Golang Rest API coming from a NodeJS background]]></description><link>https://equimper.com/blog/golang-rest-api-for-nodejs-developer-part-1</link><guid isPermaLink="false">https://equimper.com/blog/golang-rest-api-for-nodejs-developer-part-1</guid><category><![CDATA[nodejs]]></category><category><![CDATA[tutorial]]></category><category><![CDATA[golang]]></category><pubDate>Wed, 06 Nov 2019 00:00:00 GMT</pubDate><content:encoded>&lt;style data-emotion-css=&quot;5ssy5t&quot;&gt;.css-5ssy5t{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;margin-left:auto;margin-right:auto;width:100%;}@media (min-width:1200px){.css-5ssy5t{width:75%;}}&lt;/style&gt;&lt;div class=&quot;css-5ssy5t&quot;&gt;&lt;iframe width=&quot;100%&quot; height=&quot;500&quot; src=&quot;https://www.youtube.com/embed/3NLUbS7jy5Q&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot;&gt;&lt;/iframe&gt;&lt;style data-emotion-css=&quot;1s7ndt1&quot;&gt;.css-1s7ndt1{border-radius:.25rem;margin-top:2rem;padding-top:1rem;padding-bottom:1rem;padding-left:2rem;padding-right:2rem;-webkit-align-self:flex-end;-ms-flex-item-align:end;align-self:flex-end;box-shadow:0 2px 4px 0 rgba(0,0,0,.1);color:#fff;font-weight:700;text-align:center;-webkit-text-decoration:none;text-decoration:none;background-color:#ff0000;}&lt;/style&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noreferrer&quot; href=&quot;https://www.youtube.com/equimper?sub_confirmation=1&quot; class=&quot;css-1s7ndt1&quot;&gt;Subscribe&lt;/a&gt;&lt;/div&gt;&lt;h2&gt;Golang Rest API for NodeJS developer - Part 1&lt;/h2&gt;&lt;p&gt;In part 1, we will set up the foundation of our project. First, make sure you do have Go v1.13 install. On Mac, I recommend using Homebrew for that.&lt;/p&gt;&lt;h3&gt;Go module init&lt;/h3&gt;&lt;p&gt;First, create a folder where you will put the code for this project. Inside this folder run the command &lt;code&gt;go mod init todo&lt;/code&gt; todo here will be the name of the project. In &lt;strong&gt;NodeJS&lt;/strong&gt; we do &lt;code&gt;npm init&lt;/code&gt;.&lt;/p&gt;&lt;h3&gt;Setup the db connection&lt;/h3&gt;&lt;p&gt;In this project, we will use the library &lt;a href=&quot;https://github.com/go-pg/pg&quot;&gt;go-pg&lt;/a&gt; so for that, we need to install it by running &lt;code&gt;go get github.com/go-pg/pg&lt;/code&gt;. This will install the library and all the dependency.
Coming from a &lt;strong&gt;NodeJS&lt;/strong&gt; background this is the equivalent of &lt;code&gt;npm install&lt;/code&gt;. Create a folder called &lt;code&gt;postgres&lt;/code&gt; in the root of your project and a file with the same name with go as the extension.&lt;/p&gt;&lt;p&gt;In this file, we will create a function New where the only job of this one is returning a &lt;strong&gt;pointer&lt;/strong&gt; to a DB instance&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;// postgres/postgres.go

package postgres

import (
    &amp;quot;github.com/go-pg/pg/v9&amp;quot;
    _ &amp;quot;github.com/lib/pq&amp;quot;
)

func New(opts *pg.Options) *pg.DB {
    db := pg.Connect(opts)

    return db
}
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;I like to keep the root of the package the same name as the folder, It&amp;#x27;s a convention I like to follow and make life easier&lt;/p&gt;&lt;/blockquote&gt;&lt;h3&gt;Setup the basic handlers/endpoint&lt;/h3&gt;&lt;p&gt;Handlers will be like our controller ish stuff. This will be where the logic of the app are bound with the client, in this case, rest API.
We will also set up middlewares and bind them to the router instance. For the routing, we use &lt;a href=&quot;https://github.com/go-chi/chi&quot;&gt;Chi&lt;/a&gt; and we can install it with &lt;code&gt;go get github.com/go-chi/chi&lt;/code&gt;.
I found &lt;code&gt;Chi&lt;/code&gt; to be the best routing library in &lt;strong&gt;Go&lt;/strong&gt;. The reason is first for me to look like Express who is the routing library I use each time in &lt;strong&gt;NodeJS&lt;/strong&gt;.
Also, this library follows the signature of the standard library. And in the &lt;strong&gt;Go&lt;/strong&gt; community this is something they want.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;// handlers/handlers.go

package handlers

import (
    &amp;quot;time&amp;quot;

    &amp;quot;github.com/go-chi/chi&amp;quot;
    &amp;quot;github.com/go-chi/chi/middleware&amp;quot;
)

type Server struct {

}

func setupMiddleware(r *chi.Mux) {
    r.Use(middleware.RequestID)
    r.Use(middleware.RealIP)
    r.Use(middleware.Compress(6, &amp;quot;application/json&amp;quot;))
    r.Use(middleware.Logger)
    r.Use(middleware.Recoverer)
    r.Use(middleware.URLFormat)
    r.Use(middleware.Timeout(60 * time.Second))
}

func NewServer() *Server {
    return &amp;amp;Server{}
}

func SetupRouter() *chi.Mux {
    server := NewServer()

    r := chi.NewRouter()

    setupMiddleware(r)

    server.setupEndpoints(r)

    return r
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After this, we want some base endpoint. For this part-1 we will make just the barebone of it.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;// handlers/endpoint.go

package handlers

import &amp;quot;github.com/go-chi/chi&amp;quot;

func (s *Server) setupEndpoints(r *chi.Mux) {
    r.Route(&amp;quot;/api/v1&amp;quot;, func(r chi.Router) {
        r.Route(&amp;quot;/users&amp;quot;, func(r chi.Router) {

        })
    })
}
&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Setup the Main function&lt;/h3&gt;&lt;p&gt;In &lt;strong&gt;Go&lt;/strong&gt; everything starts from the Main function. So in our, we will finally initialize the database plus the routing.
We also gonna make sure the router is running on a certain port. We check if the env variables provide a &lt;code&gt;PORT&lt;/code&gt; variables else we use &lt;code&gt;8081&lt;/code&gt;.
This is the equivalent in &lt;strong&gt;NodeJS&lt;/strong&gt; of&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const port = process.env.PORT || 8081;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So create a file &lt;code&gt;main.go&lt;/code&gt; in the root of the project and this should look like this.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;// main.go

package main

import (
    &amp;quot;fmt&amp;quot;
    &amp;quot;log&amp;quot;
    &amp;quot;net/http&amp;quot;
    &amp;quot;os&amp;quot;

    &amp;quot;github.com/go-pg/pg/v9&amp;quot;

    &amp;quot;todo/handlers&amp;quot;
    &amp;quot;todo/postgres&amp;quot;
)

func main() {
    DB := postgres.New(&amp;amp;pg.Options{
        User:     &amp;quot;postgres&amp;quot;,
        Password: &amp;quot;postgres&amp;quot;,
        Database: &amp;quot;todo_dev&amp;quot;,
    })

    defer DB.Close()

    r := handlers.SetupRouter()

    port := os.Getenv(&amp;quot;PORT&amp;quot;)
    if port == &amp;quot;&amp;quot; {
        port = &amp;quot;8081&amp;quot;
    }

    err := http.ListenAndServe(fmt.Sprintf(&amp;quot;:%s&amp;quot;, port), r)
    if err != nil {
        log.Fatalf(&amp;quot;cannot start server %v&amp;quot;, err)
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;If you did like this tutorial don&amp;#x27;t forget to subscribe to my newsletter below. Also, the video link is at the top of the post.
If you have any question don&amp;#x27;t hesitate to ask in the comment section below.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://bit.ly/2CnDJpi&quot;&gt;Code for this part&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Happy Coding :)&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Golang Rest API for NodeJS developer - Intro]]></title><description><![CDATA[How to create a Golang Rest API coming from a NodeJS background]]></description><link>https://equimper.com/blog/golang-rest-api-for-nodejs-developer-intro</link><guid isPermaLink="false">https://equimper.com/blog/golang-rest-api-for-nodejs-developer-intro</guid><category><![CDATA[nodejs]]></category><category><![CDATA[tutorial]]></category><category><![CDATA[golang]]></category><pubDate>Mon, 04 Nov 2019 00:00:00 GMT</pubDate><content:encoded>&lt;style data-emotion-css=&quot;5ssy5t&quot;&gt;.css-5ssy5t{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;margin-left:auto;margin-right:auto;width:100%;}@media (min-width:1200px){.css-5ssy5t{width:75%;}}&lt;/style&gt;&lt;div class=&quot;css-5ssy5t&quot;&gt;&lt;iframe width=&quot;100%&quot; height=&quot;500&quot; src=&quot;https://www.youtube.com/embed/Uuy9J33iG0E&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot;&gt;&lt;/iframe&gt;&lt;style data-emotion-css=&quot;1s7ndt1&quot;&gt;.css-1s7ndt1{border-radius:.25rem;margin-top:2rem;padding-top:1rem;padding-bottom:1rem;padding-left:2rem;padding-right:2rem;-webkit-align-self:flex-end;-ms-flex-item-align:end;align-self:flex-end;box-shadow:0 2px 4px 0 rgba(0,0,0,.1);color:#fff;font-weight:700;text-align:center;-webkit-text-decoration:none;text-decoration:none;background-color:#ff0000;}&lt;/style&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noreferrer&quot; href=&quot;https://www.youtube.com/equimper?sub_confirmation=1&quot; class=&quot;css-1s7ndt1&quot;&gt;Subscribe&lt;/a&gt;&lt;/div&gt;&lt;h2&gt;Golang Rest API for NodeJS developer - Intro&lt;/h2&gt;&lt;p&gt;In the past few months, I&amp;#x27;ve been working on some Golang projects. Loving it, but did get some issues. One of them is the lack of tutorials.
I mean you can find a lot of Golang tutorials online like on Youtube or Udemy etc.
But I didn&amp;#x27;t find one where I can learn how to build a full rest API or something like that.
A lot of them were just about Golang in general. Some about Golang as a full-stack solution, so you use Golang as the templating etc.
But didn&amp;#x27;t find one focussing on making Rest API.&lt;/p&gt;&lt;h4&gt;What this tutorial will teach?&lt;/h4&gt;&lt;p&gt;So this tutorial will be about making a Rest API but from a NodeJS developer perspective. This is a tutorial for those coming from the stack I was already showing in my channel. Those who use express etc.
We will learn how to make endpoint using &lt;a href=&quot;https://github.com/go-chi/chi&quot;&gt;Chi&lt;/a&gt;, how to use postgresql as the database. How to use &lt;a href=&quot;https://github.com/go-pg/pg&quot;&gt;go-pg&lt;/a&gt; as the orm. Also how to deal with user authentication and JWT. How
to hash and save a password etc. The basic yes, but enough so you can build a project after this tutorial. The repos will be available &lt;a href=&quot;http://bit.ly/2qMyrBj&quot;&gt;here&lt;/a&gt; and the playlist &lt;a href=&quot;https://www.youtube.com/playlist?list=PLzQWIQOqeUSPFPVfticl-CsmUv82Gb5W-&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;I&amp;#x27;m not saying what I show will be better than others, but I feel this tutorial can fill a gap I get when coming to Golang&lt;/p&gt;&lt;/blockquote&gt;&lt;h4&gt;Conclusion&lt;/h4&gt;&lt;p&gt;I hope you will enjoy this tutorial, let me know in the comments if you have any question&lt;/p&gt;&lt;p&gt;P.S If I see people like Golang tutorial on my youtube channel, I&amp;#x27;m planning to make one for GraphQL + Golang after&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Create and Test a Hook in React-Native]]></title><description><![CDATA[React Hooks are awesome, but how can we test them? How can we build Hook and use Native API in React-Native?]]></description><link>https://equimper.com/blog/create-and-test-hook-in-react-native</link><guid isPermaLink="false">https://equimper.com/blog/create-and-test-hook-in-react-native</guid><category><![CDATA[jest]]></category><category><![CDATA[javascript]]></category><category><![CDATA[testing]]></category><category><![CDATA[react]]></category><category><![CDATA[react-native]]></category><category><![CDATA[react-hook]]></category><pubDate>Sun, 13 Oct 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://reactjs.org/docs/hooks-intro.html&quot;&gt;In React 16.8 Hook was introduced&lt;/a&gt;. This was kind of mind-blowing for me. First time I did see those I was like ok
this is just some kind of syntax sugar etc. But after playing with Hooks for like months I&amp;#x27;m loving this. The first thing they makes is to let sharing code easier.
In the past &lt;code&gt;Class&lt;/code&gt; component was great, but did you try to share some code with that? It&amp;#x27;s not easy. For me hook even give me a lot of love back to React.&lt;/p&gt;&lt;p&gt;So why this post? One thing I did find online is how to create Hook. Perfect great, but how can I test them? Also, one thing I
find missing in React-Native&amp;#x27;s tutorial is testing. I have a &lt;a href=&quot;https://youtube.com/c/equimper&quot;&gt;youtube channel&lt;/a&gt;
and like others React-Native developer on this platform &amp;quot;even Udemy etc&amp;quot; we don&amp;#x27;t show testing. It&amp;#x27;s normal too, cause testing take lot of time. So when
doing example like me a big tutorial series of already 40+ videos imagine adding testing.&lt;/p&gt;&lt;p&gt;So here I will try to show you how you can start doing a bit more test in React-Native and also how to do this with Hook.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;P.S I&amp;#x27;m not saying I&amp;#x27;m an expert here, just want to help you to get more into testing.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;First thing, a library that will make our lives easier is &lt;a href=&quot;https://github.com/testing-library/react-hooks-testing-library&quot;&gt;react-hooks-testing-library&lt;/a&gt;.
This will help us a lot in this process. One reason is the fact then this will help us testing Hook without mounting components.
So the unit testing of the Hook will be painless.&lt;/p&gt;&lt;h4&gt;useStatusBar&lt;/h4&gt;&lt;p&gt;For the first demo, we will make a simple Hook who will set the statusBar color when the screen is focused. For this we will also use the library
&lt;a href=&quot;https://github.com/react-navigation/hooks&quot;&gt;react-navigation-hooks&lt;/a&gt;&lt;/p&gt;&lt;p&gt;This use &lt;code&gt;typescript&lt;/code&gt; but can use plain &lt;code&gt;javascript&lt;/code&gt; just remove the types :)&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;import { useEffect } from &amp;#x27;react&amp;#x27;;
import { StatusBar, StatusBarStyle } from &amp;#x27;react-native&amp;#x27;;
import { useFocusState } from &amp;#x27;react-navigation-hooks&amp;#x27;;

const useStatusBar = (style: StatusBarStyle, animated = true) =&amp;gt; {
  const { isFocused } = useFocusState();

  useEffect(() =&amp;gt; {
    if (isFocused) {
      StatusBar.setBarStyle(style, animated);
    }
  }, [isFocused]);
};

export default useStatusBar;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here as you can see it&amp;#x27;s a pretty simple case. The Hook will run a effect when the &lt;code&gt;isFocused&lt;/code&gt; boolean value will change.
This will happen when the sceen get focused.&lt;/p&gt;&lt;p&gt;Now how can we test that?&lt;/p&gt;&lt;p&gt;The first thing we will need is to create a file call &lt;code&gt;useStatusBar.test.ts&lt;/code&gt; Inside this one we will need to render the hook first&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-ts&quot; metastring=&quot;{1,7}&quot;&gt;import { renderHook } from &amp;#x27;@testing-library/react-hooks&amp;#x27;;

import useStatusBar from &amp;#x27;../useStatusBar&amp;#x27;;

describe(&amp;#x27;useStatusBar&amp;#x27;, () =&amp;gt; {
  it(&amp;#x27;should set the status bar style as light-content when screen is focused&amp;#x27;, () =&amp;gt; {
    renderHook(() =&amp;gt; useStatusBar(&amp;#x27;light-content&amp;#x27;))
  });
});
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The hook first argument is the style we do want. Here, in this case, we want &lt;code&gt;light-content&lt;/code&gt; the second argument is a default animated value to true.
As you can see render the Hook is simple. Time to add some testing. The first thing we need to
do for accomplishing the &lt;strong&gt;Unit Test&lt;/strong&gt; is to mock dependencies. In this one we have 2 deps to mock. The StatusBar native API and the react-navigation hook.&lt;/p&gt;&lt;p&gt;How can we do this? &lt;a href=&quot;https://jestjs.io&quot;&gt;Jest&lt;/a&gt; to the rescue!!!&lt;/p&gt;&lt;p&gt;Jest came with Spy + Mock and this is all we need. So first time to spy on the StatusBar API.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-tsx&quot; metastring=&quot;{1,8}&quot;&gt;import { StatusBar } from &amp;#x27;react-native&amp;#x27;;
import { renderHook } from &amp;#x27;@testing-library/react-hooks&amp;#x27;;

import useStatusBar from &amp;#x27;../useStatusBar&amp;#x27;;

describe(&amp;#x27;useStatusBar&amp;#x27;, () =&amp;gt; {
  it(&amp;#x27;should set the status bar style as light-content when screen is focused&amp;#x27;, () =&amp;gt; {
    const setBarStyleSpy = jest.spyOn(StatusBar, &amp;#x27;setBarStyle&amp;#x27;);

    renderHook(() =&amp;gt; useStatusBar(&amp;#x27;light-content&amp;#x27;))
  });
});
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As you can see, we create a variable call &lt;code&gt;setBarStyleSpy&lt;/code&gt; who will be a spy on the method from the StatusBar &lt;code&gt;setBarStyle&lt;/code&gt;. We
will spy on this one so we can make sure we do call this method once with the value we expected.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-tsx&quot; metastring=&quot;{12-13}&quot;&gt;import { StatusBar } from &amp;#x27;react-native&amp;#x27;;
import { renderHook } from &amp;#x27;@testing-library/react-hooks&amp;#x27;;

import useStatusBar from &amp;#x27;../useStatusBar&amp;#x27;;

describe(&amp;#x27;useStatusBar&amp;#x27;, () =&amp;gt; {
  it(&amp;#x27;should set the status bar style as light-content when screen is focused&amp;#x27;, () =&amp;gt; {
    const setBarStyleSpy = jest.spyOn(StatusBar, &amp;#x27;setBarStyle&amp;#x27;);

    renderHook(() =&amp;gt; useStatusBar(&amp;#x27;light-content&amp;#x27;))

    expect(setBarStyleSpy).toHaveBeenCalledTimes(1);
    expect(setBarStyleSpy).toHaveBeenCalledWith(&amp;#x27;light-content&amp;#x27;, true);
  });
});
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here we do check &lt;code&gt;setBarStyle&lt;/code&gt; did get called only once and the value provided was &lt;code&gt;light-content&lt;/code&gt; and &lt;code&gt;true&lt;/code&gt; who is the default value pass.&lt;/p&gt;&lt;p&gt;In the last step we do need to mock the &lt;code&gt;react-navigation-hooks&lt;/code&gt;.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-tsx&quot; metastring=&quot;{10-12}&quot;&gt;import { StatusBar } from &amp;#x27;react-native&amp;#x27;;
import { renderHook } from &amp;#x27;@testing-library/react-hooks&amp;#x27;;

import useStatusBar from &amp;#x27;../useStatusBar&amp;#x27;;

describe(&amp;#x27;useStatusBar&amp;#x27;, () =&amp;gt; {
  it(&amp;#x27;should set the status bar style as light-content when screen is focused&amp;#x27;, () =&amp;gt; {
    const setBarStyleSpy = jest.spyOn(StatusBar, &amp;#x27;setBarStyle&amp;#x27;);

    jest
      .spyOn(reactNavigationHooks, &amp;#x27;useFocusState&amp;#x27;)
      .mockImplementation(() =&amp;gt; ({ isFocused: true }));

    renderHook(() =&amp;gt; useStatusBar(&amp;#x27;light-content&amp;#x27;))

    expect(setBarStyleSpy).toHaveBeenCalledTimes(1);
    expect(setBarStyleSpy).toHaveBeenCalledWith(&amp;#x27;light-content&amp;#x27;, true);
  });
});
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here we mock only once the &lt;code&gt;useFocusState&lt;/code&gt; method to return an object who contain &lt;code&gt;isFocused: true&lt;/code&gt; this one will trigger
the useEffect of our hook who then will cause the StatusBar &lt;code&gt;setBarStyle&lt;/code&gt; to get a call.&lt;/p&gt;&lt;p&gt;That&amp;#x27;s it this is how we can use jest and mock/spy on dependencies of our code so we can &lt;strong&gt;Unit Test&lt;/strong&gt; easily.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Table driven test with jest]]></title><description><![CDATA[How can we use table driven test with jest. How can that make your life easier.]]></description><link>https://equimper.com/blog/table-driven-test-with-jest</link><guid isPermaLink="false">https://equimper.com/blog/table-driven-test-with-jest</guid><category><![CDATA[jest]]></category><category><![CDATA[javascript]]></category><category><![CDATA[testing]]></category><pubDate>Thu, 03 Oct 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I&amp;#x27;ve been doing some Golang lately, and kind of really like there idea about how they make the tests so simple. One of the ways to make a test in Go is what they call &lt;a href=&quot;https://github.com/golang/go/wiki/TableDrivenTests&quot;&gt;Table Driven Tests&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;This is nice when you want to test something that is kind of tedious to right. Example, you create a function where you want to test a lot of input and see if the result is the expected one. You can go this way.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;describe(&amp;#x27;sum&amp;#x27;, () =&amp;gt; {
  it(&amp;#x27;should return 2 if input is 1 and 1&amp;#x27;, () =&amp;gt; {
    expect(sum(1, 1)).toBe(2)
  })

  it(&amp;#x27;should return 5 if input is 2 and 3&amp;#x27;, () =&amp;gt; {
    expect(sum(2, 3)).toBe(5)
  })
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As you can see, this becomes a lot of repeated code. As a programmer, we are kind of lazy, but in a good way. We don&amp;#x27;t like to copy the same code again. First it&amp;#x27;s time-consuming and secondly, this is error-prone.&lt;/p&gt;&lt;p&gt;So how can we rewrite this in a better way? This is where &lt;a href=&quot;https://jestjs.io/docs/en/api#testeachtable-name-fn-timeout&quot;&gt;jest each&lt;/a&gt; comes to the rescue. If you read the first sentence this will make sense&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Use test.each if you keep duplicating the same test with different data. test.each allows you to write the test once and pass data in.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;So how can I use this? Quite easy, first I will show you an example and I will explain right after.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;describe(&amp;#x27;sum&amp;#x27;, () =&amp;gt; {
  test.each`
    inputA | inputB | expected
    ${1}   | ${1}   | ${2}
    ${2}   | ${3}   | ${5}
  `(
    &amp;#x27;should return $expected if input is $inputA and $inputB&amp;#x27;,
    ({ inputA, inputB, expected }) =&amp;gt; {
      expect(sum(inputA, inputB)).toBe(expected)
    }
  )
})
&lt;/code&gt;&lt;/pre&gt;&lt;iframe src=&quot;https://codesandbox.io/embed/amazing-poincare-nf7b1?autoresize=1&amp;amp;fontsize=14&amp;amp;previewwindow=tests&quot; title=&quot;amazing-poincare-nf7b1&quot; allow=&quot;geolocation; microphone; camera; midi; vr; accelerometer; gyroscope; payment; ambient-light-sensor; encrypted-media; usb&quot; style=&quot;width:100%;height:500px;border:0;border-radius:4px;overflow:hidden;margin:30px 0&quot; sandbox=&quot;allow-modals allow-forms allow-popups allow-scripts allow-same-origin&quot;&gt;&lt;/iframe&gt;&lt;p&gt;So first we can write a table inside the tagged template literal. The second argument is the name of the test. As you can see you do have access to your table header variables. You just need to prefix those with &lt;code&gt;$&lt;/code&gt; here we have &lt;code&gt;$inputA&lt;/code&gt; example for the first table header. The 3rd argument is the test function, the same thing as what you do in any other test. As you can see the beauty of this, it&amp;#x27;s you can add test to that so easily. The only issue, I did get with that is almost the naming, but a tip is &lt;strong&gt;keep the naming of your arguments&lt;/strong&gt;.&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;I feel this is something you can add to your testing arsenal. This is not for every test for sure. But this can clean up a lot of duplicate code in those tests where this makes sense.&lt;/p&gt;&lt;p&gt;Let me know what you think about it in the chat below.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Build a REST API with AdonisJs and TDD Part 3]]></title><description><![CDATA[Want to learn how to use AdonisJs by building a rest api using TDD approach? This is the tutorial you want]]></description><link>https://equimper.com/blog/build-a-rest-api-with-adonisjs-and-tdd-part-3</link><guid isPermaLink="false">https://equimper.com/blog/build-a-rest-api-with-adonisjs-and-tdd-part-3</guid><category><![CDATA[tutorial]]></category><category><![CDATA[adonisjs]]></category><category><![CDATA[tdd]]></category><category><![CDATA[javascript]]></category><category><![CDATA[testing]]></category><pubDate>Sun, 02 Jun 2019 00:00:00 GMT</pubDate><content:encoded>&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://equimper.com/blog/build-a-rest-api-with-adonisjs-and-tdd-part-1&quot;&gt;Part 1&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://equimper.com/blog/build-a-rest-api-with-adonisjs-and-tdd-part-2&quot;&gt;Part 2&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://equimper.com/blog/build-a-rest-api-with-adonisjs-and-tdd-part-4&quot;&gt;Part 4&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/EQuimper/adonis-tdd-tutorial-demo&quot;&gt;Source Code&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Intro&lt;/h2&gt;&lt;p&gt;In this part, we jump straight back to our challenges API endpoint where we will add
a way to a user to fetch all his own challenges. Also would be nice if the user can update and delete an own challenge.&lt;/p&gt;&lt;h2&gt;Get /api/me/challenges&lt;/h2&gt;&lt;p&gt;First thing create a new functional test by running&lt;/p&gt;&lt;pre&gt;&lt;code&gt;adonis make:test GetUserChallenges
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In the test, we will write it in one go.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;&amp;#x27;use strict&amp;#x27;

const Factory = use(&amp;#x27;Factory&amp;#x27;)
const { test, trait } = use(&amp;#x27;Test/Suite&amp;#x27;)(&amp;#x27;Get User Challenges&amp;#x27;)

trait(&amp;#x27;Test/ApiClient&amp;#x27;)
trait(&amp;#x27;Auth/Client&amp;#x27;)

test(&amp;#x27;can get all the user challenges&amp;#x27;, async ({ assert, client }) =&amp;gt; {
  const user = await Factory.model(&amp;#x27;App/Models/User&amp;#x27;).create()
  const otherUser = await Factory.model(&amp;#x27;App/Models/User&amp;#x27;).create();
  const challenges = await Factory.model(&amp;#x27;App/Models/Challenge&amp;#x27;).makeMany(2)
  const otherChallenges = await Factory.model(&amp;#x27;App/Models/Challenge&amp;#x27;).makeMany(2)

  await user.challenges().saveMany(challenges)
  await otherUser.challenges().saveMany(otherChallenges)

  const response = await client
    .get(&amp;#x27;/api/me/challenges&amp;#x27;)
    .loginVia(user, &amp;#x27;jwt&amp;#x27;)
    .end()

  response.assertStatus(200)

  assert.equal(response.body.length, 2);

  response.assertJSONSubset([
    { title: challenges[0].title },
    { title: challenges[1].title }
  ])
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This test start we 2 user. One who will be our, and one different user. We also make 2 challenges for us and 2 for the other user.&lt;/p&gt;&lt;p&gt;We make sure here don&amp;#x27;t save it right to the DB. We want to be able to add the relation with the user.&lt;/p&gt;&lt;p&gt;So we add the challenges to the user with the saveMany method who batch save those challenges. We do the same
with the other user.&lt;/p&gt;&lt;p&gt;We create a response where we log the user with JWT. After this, we check for a status 200 Ok. Also, we want to make sure
I just receive 2 challenges, no more, no less. I don&amp;#x27;t want this endpoint to return me challenges from a others user.
I add the last check to make sure the 2 challenges we got are the one in the challenges variables.&lt;/p&gt;&lt;p&gt;If you run the test with &lt;code&gt;adonis test&lt;/code&gt; or &lt;code&gt;yarn test&lt;/code&gt; you will get 404 error. Remember this mean routes not exist. So jump to the file &lt;code&gt;routes.js&lt;/code&gt; and add this line.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;Route.get(&amp;#x27;/api/me/challenges&amp;#x27;, &amp;#x27;MeController.challenges&amp;#x27;).middleware([&amp;#x27;auth&amp;#x27;])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here this route is nothing too strange, we make sure user is authenticated by using the middleware auth. &lt;em&gt;We did that already :)&lt;/em&gt; Only thing change is I make use of another controller call MeController. I can have put it inside the ChallengeController but the thing is I like the controller to look like the route&amp;#x27;s path.&lt;/p&gt;&lt;p&gt;You can create a controller by running&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;adonis make:controller Me
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Go inside the new file created and add this code to the class&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;async challenges() {

}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now your test will have error cause we return nothing etc. Time to add the logic, and wow Adonis make your life soooo easy.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;class MeController {
  async challenges({ response ,auth}) {
    const user = await auth.getUser();

    const challenges = await user.challenges().fetch();

    return response.ok(challenges.toJSON());
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;First, we need to get the current user. By using the auth.getUser function we can get it. After this to get the challenges we can then
ask the user to fetch all the challenges owned. This is possible cause of the user model we have done in the first part.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;challenges() {
  return this.hasMany(&amp;#x27;App/Models/Challenge&amp;#x27;)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This challenges method inside the User model gives us the one owned by the user. The thing is those challenges will not be in JSON format so that&amp;#x27;s why inside the response
we ask the toJSON method.&lt;/p&gt;&lt;p&gt;Now if you run your test all should be green :)&lt;/p&gt;&lt;h2&gt;Put /api/challenges/:id&lt;/h2&gt;&lt;p&gt;Now time to work on the update endpoint. First, create a new test&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;adonis make:test UpdateChallenge
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We will need to test here, the first one is to make sure a user who is the author of the challenge can update it and see the change. The second test is to make
sure we don&amp;#x27;t let other users update a challenge.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;&amp;#x27;use strict&amp;#x27;

const Factory = use(&amp;#x27;Factory&amp;#x27;)
const { test, trait } = use(&amp;#x27;Test/Suite&amp;#x27;)(&amp;#x27;Update Challenge&amp;#x27;)

trait(&amp;#x27;Test/ApiClient&amp;#x27;)
trait(&amp;#x27;Auth/Client&amp;#x27;)

test(&amp;#x27;a user can update a challenge owned&amp;#x27;, async ({ client }) =&amp;gt; {
  const user = await Factory.model(&amp;#x27;App/Models/User&amp;#x27;).create()
  const challenge = await Factory.model(&amp;#x27;App/Models/Challenge&amp;#x27;).make()

  await user.challenges().save(challenge)

  const data = {
    title: &amp;#x27;This is my new title&amp;#x27;
  }

  const response = await client
    .put(`/api/challenges/${challenge.id}`)
    .loginVia(user, &amp;#x27;jwt&amp;#x27;)
    .send(data)
    .end()

  response.assertStatus(200)

  response.assertJSONSubset({
    id: challenge.id,
    title: data.title
  })
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For the first test, this is pretty simple. We first create a user and link the challenge. We then create a data object who will contain the new title. We then use the client and send to the endpoint this data. We check the response to make sure this is 200 ok and also the JSON contains the same id and the new title.&lt;/p&gt;&lt;p&gt;Run test, see it fail. Time to create the route first.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;Route.put(&amp;#x27;/api/challenges/:id&amp;#x27;, &amp;#x27;ChallengeController.update&amp;#x27;)
  .validator(&amp;#x27;UpdateChallenge&amp;#x27;)
  .middleware([&amp;#x27;auth&amp;#x27;])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The route is pretty simple, but we add a validator. I will not do the test for this cause this is pretty easy and I want to give you more on the business logic.&lt;/p&gt;&lt;p&gt;For creating the validator just run&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;adonis make:validator UpdateChallenge
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And inside this one paste that&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;&amp;#x27;use strict&amp;#x27;

class UpdateChallenge {
  get rules() {
    return {
      title: &amp;#x27;string&amp;#x27;,
      description: &amp;#x27;string&amp;#x27;
    }
  }

  get messages() {
    return {
      string: &amp;#x27;{{ field }} is not a valid string&amp;#x27;
    }
  }

  get validateAll() {
    return true
  }

  async fails(errorMessages) {
    return this.ctx.response.status(400).json(errorMessages)
  }
}

module.exports = UpdateChallenge
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is like the CreateChallenge validator but nothing is required.&lt;/p&gt;&lt;p&gt;Inside your ChallengeController now add this method&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;async update({ response, request, params, auth }) {
  const user = await auth.getUser()

  const challenge = await Challenge.findOrFail(params.id)

  if (challenge.user_id !== user.id) {
    throw new UnauthorizedException();
  }

  challenge.merge(request.only([&amp;#x27;title&amp;#x27;, &amp;#x27;description&amp;#x27;]));

  await challenge.save();

  return response.ok(challenge)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This update method will first get the user. Then find the challenge. This will return a free 404 if the challenge doesn&amp;#x27;t exist. After this, we check for the
user_id key in the challenge to see if that match the current user. If not we throw an Exception.&lt;/p&gt;&lt;p&gt;Time to make the exception&lt;/p&gt;&lt;pre&gt;&lt;code&gt;adonis make:exception UnauthorizedException
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;&amp;#x27;use strict&amp;#x27;

const { LogicalException } = require(&amp;#x27;@adonisjs/generic-exceptions&amp;#x27;)

class UnauthorizedException extends LogicalException {
  handle(error, { response }) {
    response.status(401).send(&amp;#x27;Not authorized&amp;#x27;)
  }
}

module.exports = UnauthorizedException
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This one will return a 401 with the message Not authorized.&lt;/p&gt;&lt;p&gt;After this, if the user is the author we merge the request object for only title and description. Only fields we accept an update.&lt;/p&gt;&lt;p&gt;We make sure to save the challenge, if not this will not persist. And finally, we return this challenge with the status 200.&lt;/p&gt;&lt;p&gt;If you run the test all should be green. But we need to make sure a nonauthor cannot update.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;test(&amp;#x27;cannot update challenge if not the author&amp;#x27;, async ({
  assert,
  client
}) =&amp;gt; {
  const user = await Factory.model(&amp;#x27;App/Models/User&amp;#x27;).create()
  const otherUser = await Factory.model(&amp;#x27;App/Models/User&amp;#x27;).create()
  const challenge = await Factory.model(&amp;#x27;App/Models/Challenge&amp;#x27;).make()

  await otherUser.challenges().save(challenge)

  const data = {
    title: &amp;#x27;This is my new title&amp;#x27;
  }

  const response = await client
    .put(`/api/challenges/${challenge.id}`)
    .loginVia(user, &amp;#x27;jwt&amp;#x27;)
    .send(data)
    .end()

  response.assertStatus(401)

  const _challenge = await use(&amp;#x27;App/Models/Challenge&amp;#x27;).find(challenge.id)

  // check if the title really didn&amp;#x27;t change
  assert.notEqual(_challenge.title, data.title)
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;All should be green :)&lt;/p&gt;&lt;p&gt;Time to work on the delete portion&lt;/p&gt;&lt;pre&gt;&lt;code&gt;adonis make:test DeleteUserChallenge
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You must be good now with the basic stuff :) Lot of repetitive think here, but you win a lot of trust in your project.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;&amp;#x27;use strict&amp;#x27;

const Factory = use(&amp;#x27;Factory&amp;#x27;)
const { test, trait } = use(&amp;#x27;Test/Suite&amp;#x27;)(&amp;#x27;Delete Challenge&amp;#x27;)

trait(&amp;#x27;Test/ApiClient&amp;#x27;)
trait(&amp;#x27;Auth/Client&amp;#x27;)

test(&amp;#x27;a user can delete a challenge owned&amp;#x27;, async ({ client }) =&amp;gt; {
  const user = await Factory.model(&amp;#x27;App/Models/User&amp;#x27;).create()
  const challenge = await Factory.model(&amp;#x27;App/Models/Challenge&amp;#x27;).make()

  await user.challenges().save(challenge)

  const response = await client
    .delete(`/api/challenges/${challenge.id}`)
    .loginVia(user, &amp;#x27;jwt&amp;#x27;)
    .end()

  response.assertStatus(204)
})

test(&amp;#x27;cannot delete challenge if not the author&amp;#x27;, async ({
  assert,
  client
}) =&amp;gt; {
  const user = await Factory.model(&amp;#x27;App/Models/User&amp;#x27;).create()
  const otherUser = await Factory.model(&amp;#x27;App/Models/User&amp;#x27;).create()
  const challenge = await Factory.model(&amp;#x27;App/Models/Challenge&amp;#x27;).make()

  await otherUser.challenges().save(challenge)

  const response = await client
    .delete(`/api/challenges/${challenge.id}`)
    .loginVia(user, &amp;#x27;jwt&amp;#x27;)
    .end()

  response.assertStatus(401)

  const _challenge = await use(&amp;#x27;App/Models/Challenge&amp;#x27;).find(challenge.id)

  assert.isNotNull(_challenge)
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;First, we will test a current user who owns the challenge can delete it. It&amp;#x27;s almost a copy and paste of the update method. Same for the version where the user cannot delete a challenge if not own.&lt;/p&gt;&lt;p&gt;For the routes now you should add&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;Route
  .delete(&amp;#x27;/api/challenges/:id&amp;#x27;, &amp;#x27;ChallengeController.delete&amp;#x27;)
  .middleware([
    &amp;#x27;auth&amp;#x27;
  ])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And for your controller, it&amp;#x27;s easy like that&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;  async destroy({ response, params, auth }) {
    const user = await auth.getUser()

    const challenge = await Challenge.findOrFail(params.id)

    if (challenge.user_id !== user.id) {
      throw new UnauthorizedException();
    }

    await challenge.delete()

    return response.noContent();
  }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Remember findOrFail give you a free 404 if the challenge doesn&amp;#x27;t exist. We need to just throw 401 exceptions if the user is not the author.&lt;/p&gt;&lt;hr/&gt;&lt;h2&gt;The routes file&lt;/h2&gt;&lt;p&gt;If you look right now at your routes file this will look something like that&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;Route.get(&amp;#x27;/api/challenges&amp;#x27;, &amp;#x27;ChallengeController.all&amp;#x27;)
Route.get(&amp;#x27;/api/challenges/:id&amp;#x27;, &amp;#x27;ChallengeController.show&amp;#x27;)
Route.put(&amp;#x27;/api/challenges/:id&amp;#x27;, &amp;#x27;ChallengeController.update&amp;#x27;)
  .validator(&amp;#x27;UpdateChallenge&amp;#x27;)
  .middleware([&amp;#x27;auth&amp;#x27;])
Route.post(&amp;#x27;/api/challenges&amp;#x27;, &amp;#x27;ChallengeController.store&amp;#x27;)
  .validator(&amp;#x27;CreateChallenge&amp;#x27;)
  .middleware([&amp;#x27;auth&amp;#x27;])
Route.delete(&amp;#x27;/api/challenges/:id&amp;#x27;, &amp;#x27;ChallengeController.destroy&amp;#x27;).middleware([
  &amp;#x27;auth&amp;#x27;
])

Route.get(&amp;#x27;/api/me/challenges&amp;#x27;, &amp;#x27;MeController.challenges&amp;#x27;).middleware([&amp;#x27;auth&amp;#x27;])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Must be another way of doing this repetetive task ? And yes we can make use of &lt;a href=&quot;https://adonisjs.com/docs/4.1/routing#_route_groups&quot;&gt;grouping&lt;/a&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; metastring=&quot;{1,4,5,9}&quot;&gt;Route.group(() =&amp;gt; {
  Route.get(&amp;#x27;/&amp;#x27;, &amp;#x27;ChallengeController.all&amp;#x27;)
  Route.get(&amp;#x27;/:id&amp;#x27;, &amp;#x27;ChallengeController.show&amp;#x27;)
}).prefix(&amp;#x27;/api/challenges&amp;#x27;)
Route.group(() =&amp;gt; {
  Route.post(&amp;#x27;/&amp;#x27;, &amp;#x27;ChallengeController.store&amp;#x27;).validator(&amp;#x27;CreateChallenge&amp;#x27;)
  Route.put(&amp;#x27;/:id&amp;#x27;, &amp;#x27;ChallengeController.update&amp;#x27;).validator(&amp;#x27;UpdateChallenge&amp;#x27;)
  Route.delete(&amp;#x27;/:id&amp;#x27;, &amp;#x27;ChallengeController.destroy&amp;#x27;)
}).prefix(&amp;#x27;/api/challenges&amp;#x27;).middleware([&amp;#x27;auth&amp;#x27;])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you ask why do we don&amp;#x27;t nested them, it&amp;#x27;s because right now we can&amp;#x27;t with the version we run. This is the error you will get&lt;/p&gt;&lt;pre&gt;&lt;code&gt;RuntimeException: E_NESTED_ROUTE_GROUPS: Nested route groups are not allowed
&lt;/code&gt;&lt;/pre&gt;&lt;hr/&gt;&lt;p&gt;I hope you enjoy this post :) And we talk in part 4 where we will start to add a bit more interaction with the API :)&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Build a REST API with AdonisJs and TDD Part 2]]></title><description><![CDATA[Want to learn how to use AdonisJs by building a rest api using TDD approach? This is the tutorial you want]]></description><link>https://equimper.com/blog/build-a-rest-api-with-adonisjs-and-tdd-part-2</link><guid isPermaLink="false">https://equimper.com/blog/build-a-rest-api-with-adonisjs-and-tdd-part-2</guid><category><![CDATA[tutorial]]></category><category><![CDATA[adonisjs]]></category><category><![CDATA[tdd]]></category><category><![CDATA[javascript]]></category><category><![CDATA[testing]]></category><pubDate>Mon, 01 Apr 2019 00:00:00 GMT</pubDate><content:encoded>&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://equimper.com/blog/build-a-rest-api-with-adonisjs-and-tdd-part-1&quot;&gt;Part 1&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://equimper.com/blog/build-a-rest-api-with-adonisjs-and-tdd-part-3&quot;&gt;Part 3&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://equimper.com/blog/build-a-rest-api-with-adonisjs-and-tdd-part-4&quot;&gt;Part 4&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/EQuimper/adonis-tdd-tutorial-demo&quot;&gt;Source Code&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Intro&lt;/h2&gt;&lt;p&gt;Been a long time since &lt;a href=&quot;https://equimper.com/blog/build-a-rest-api-with-adonisjs-and-tdd-part-1&quot;&gt;part 1&lt;/a&gt;, sorry about that.&lt;/p&gt;&lt;p&gt;In this part, we will continue our Movies rest API with TDD. We will go a bit faster cause we now know the step we need to make in order to follow the TDD approach.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;Fail -&amp;gt; Pass -&amp;gt; Refactor
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Quick Fixes&lt;/h2&gt;&lt;p&gt;In the last part, we make use, in testing env, of the DB postgres. Nothing bad with that, it&amp;#x27;s ok to use it. But I think will be faster in the long run if we make use of SQLite.&lt;/p&gt;&lt;p&gt;Don&amp;#x27;t worry again Adonis have made it easy for us :)&lt;/p&gt;&lt;p&gt;First, run&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;npm i -D sqlite3
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will install the drive we need for SQLite as a Dev Dependencies.&lt;/p&gt;&lt;p&gt;Now go inside your .env.testing file and put those lines&lt;/p&gt;&lt;pre&gt;&lt;code&gt;DB_CONNECTION=sqlite
DB_HOST=127.0.0.1
DB_PORT=3306
DB_USER=root
DB_PASSWORD=
DB_DATABASE=movies_challenges_test
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Don&amp;#x27;t forget to remove the other one who touches the db.&lt;/p&gt;&lt;p&gt;Now if you rerun the test with &lt;code&gt;adonis test&lt;/code&gt; you should see all test pass&lt;/p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1035px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/fb44a7fb134feb68ca12f1a9a6f5f3cd/74085/sqlite-test.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:46.63978494623656%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAABYlAAAWJQFJUiTwAAABOklEQVQoz5WSa07DMBCEfRUETeI8HefpJHaaJqUFCX7CAZC4/w2GtUMrVJUKfnyaXUce78Rm6WGP3eEFy/EVndlD1hqyMchJi2aEqAa0wwxR9vBCiSAu4UeF02uwu6HD/dCDDwbhtEWkR8TT5EiGEVGvkRrqRXs2PHHNmNkJ9PyEVi8wyzNka7CJJPykhEcb/LhYleBJ5fTE1QkDUUNud1D9Dp2eUZGhpENqNSKnmLYuKH7ZaLeW5i1N25wnvIR5XILTx0IoZGUHURCkJ+OMemucU21NM6mQiNU0ymqicbVdC9MazDcG4vMd4XEBD9dYnOKuellXtOlbf/TWyGJ7FpBh/vEG/jjDp2n9X6L8FZbGNYqE/slGuOgJRQho0uDG07gFC7RGqA0e6Ol4qkOsBviNcrccuFv+n+EX4gkbpBj35EAAAAAASUVORK5CYII=&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;sqlite test&quot; title=&quot;sqlite test&quot; src=&quot;/static/fb44a7fb134feb68ca12f1a9a6f5f3cd/17fa4/sqlite-test.png&quot; srcSet=&quot;/static/fb44a7fb134feb68ca12f1a9a6f5f3cd/f4a45/sqlite-test.png 259w,/static/fb44a7fb134feb68ca12f1a9a6f5f3cd/ef0f6/sqlite-test.png 518w,/static/fb44a7fb134feb68ca12f1a9a6f5f3cd/17fa4/sqlite-test.png 1035w,/static/fb44a7fb134feb68ca12f1a9a6f5f3cd/74085/sqlite-test.png 1488w&quot; sizes=&quot;(max-width: 1035px) 100vw, 1035px&quot; loading=&quot;lazy&quot;/&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;p&gt;If you compare this to before you can see we get a bit faster. This will get faster more and more test we will add. SQLite is a in-memory db.&lt;/p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1035px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/4d530d636c7c71743529140275b44688/ace41/pg-benchmark.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:45.53686934023286%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAABYlAAAWJQFJUiTwAAABI0lEQVQoz5WSy27DIBBF/TGJX+AYG2IM2BA7aaO+1GVX/Yb+/+oW7MiSq8RSF1czIOZo7gxR7hz66xvGp3eY0zNKYVA3Papjh8pH5mNjRhSsRUI4UiqWeE/RTmvsbAfaO9DzCNJb0GFAEaQtiHVgbgA5NCtQyO+BI1q1MMMVsjvDXl7B1Qkx9Y8LgTgU+UfhnFK+CVqAobDsHKQZoLy1RjnwYLN1qIJ9n3NvXchZhW+AMrmA/ypK8tAFR+VnxG4AJrQvttMcGdcrcFmrCRpmSko5wUMe7qYOY6nAf75Bvz4QZ/VDK1vKilmz5Vri8PmCbDitthi6fmRrSxGhRwimkKU1MiJQeBsp2f4aW4pipZFZi70x2HcGuTJItJm2m962/B/gL93gGwegHoEWAAAAAElFTkSuQmCC&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;pg benchmark&quot; title=&quot;pg benchmark&quot; src=&quot;/static/4d530d636c7c71743529140275b44688/17fa4/pg-benchmark.png&quot; srcSet=&quot;/static/4d530d636c7c71743529140275b44688/f4a45/pg-benchmark.png 259w,/static/4d530d636c7c71743529140275b44688/ef0f6/pg-benchmark.png 518w,/static/4d530d636c7c71743529140275b44688/17fa4/pg-benchmark.png 1035w,/static/4d530d636c7c71743529140275b44688/ace41/pg-benchmark.png 1546w&quot; sizes=&quot;(max-width: 1035px) 100vw, 1035px&quot; loading=&quot;lazy&quot;/&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;h2&gt;Get /api/challenges&lt;/h2&gt;&lt;p&gt;Here, as the title says, we will work on the GET request who gonna give us all the challenges in our API. For now and for the purpose of the tutorial, we don&amp;#x27;t gonna worry about the pagination, etc.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;adonis make:test GetChallenges
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And choose Functional test&lt;/p&gt;&lt;p&gt;Go to the new file&lt;/p&gt;&lt;pre&gt;&lt;code&gt;test/functional/get-challenges.spec.js
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Like in the past test file we need to import the Factory and get the trait&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;&amp;#x27;use strict&amp;#x27;

const Factory = use(&amp;#x27;Factory&amp;#x27;)
const { test, trait } = use(&amp;#x27;Test/Suite&amp;#x27;)(&amp;#x27;Get Challenges&amp;#x27;)

trait(&amp;#x27;Test/ApiClient&amp;#x27;)
trait(&amp;#x27;Auth/Client&amp;#x27;)

test(&amp;#x27;make sure 2 + 2 is 4&amp;#x27;, async ({ assert, client }) =&amp;gt; {
  assert.equal(2 + 2, 4)
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Time to write the first test. First, what do we want to achieve here? For this endpoints, we want to make sure we can get all the challenges we have to save inside the database. This will be quite simple here.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;&amp;#x27;use strict&amp;#x27;

const Factory = use(&amp;#x27;Factory&amp;#x27;)
const { test, trait } = use(&amp;#x27;Test/Suite&amp;#x27;)(&amp;#x27;Get Challenges&amp;#x27;)

trait(&amp;#x27;Test/ApiClient&amp;#x27;)
trait(&amp;#x27;Auth/Client&amp;#x27;)

test(&amp;#x27;can get all the challenges&amp;#x27;, async ({ assert, client }) =&amp;gt; {
  const challenges = await Factory.model(&amp;#x27;App/Models/Challenge&amp;#x27;).createMany(3)

  const response = await client.get(&amp;#x27;/api/challenges&amp;#x27;).end()

  response.assertStatus(200)

  response.assertJSONSubset([
    { title: challenges[0].title },
    { title: challenges[1].title },
    { title: challenges[2].title },
  ])
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here we first create 3 challenges by using the createMany method on Factory. After we check the response status equal 200 and also the JSON response have all 3 titles inside the return array.&lt;/p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:880px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/d85acdaefc7656bb96a262c68123aae3/47573/error-1.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:52.5%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAABYlAAAWJQFJUiTwAAABWUlEQVQoz4VS206DQBTst2hsgaVQdrcXe7Ep2FiSKtiHxhoSf9PExCdf9KfGoSwFC7EPk909e84wO0MnSfeI1lvs9hk22x32hzes4wQ9R8JytYFCT2gDdaqX+3qtEwZjxN4QUTBBzP1KTRENxhiTJCTuiIhYEY99hQlXT8+gR4sG2ZHwJldC5IqE2TuEzUvBYYdwDTxzzgft/rCdUFGd9EeQbLB52cubTGP5zO7ZWtyp9id/Jgk+sgzvmxihkLjOv+4Wg6V31lFVHbrhY6WQ6hQ9k96Iz6ka7BpZFcjfc53oRGg7NJ7K5kRIslsOzIklMTOB5OE8ELHxslLdQhh7ReOGCd778jg4NeluWVuYdWUCsS8RpqkLOQywDH28Zg48n42iSNg1JI7xrivOvW0h1IFiypo+avQHecrNdOv+WZcU/iTP+H454OspRcj/70oUKVtCNdL9j6jEL2LuXKAWa/beAAAAAElFTkSuQmCC&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;error 1&quot; title=&quot;error 1&quot; src=&quot;/static/d85acdaefc7656bb96a262c68123aae3/47573/error-1.png&quot; srcSet=&quot;/static/d85acdaefc7656bb96a262c68123aae3/f4a45/error-1.png 259w,/static/d85acdaefc7656bb96a262c68123aae3/ef0f6/error-1.png 518w,/static/d85acdaefc7656bb96a262c68123aae3/47573/error-1.png 880w&quot; sizes=&quot;(max-width: 880px) 100vw, 880px&quot; loading=&quot;lazy&quot;/&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;p&gt;If you run the test this is what you see.&lt;/p&gt;&lt;p&gt;Make sense we didn&amp;#x27;t create the route yet. Go to the route file and add&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;Route.get(&amp;#x27;/api/challenges&amp;#x27;, &amp;#x27;ChallengeController.all&amp;#x27;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now if you add this line to your test file&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;console.log(&amp;#x27;error&amp;#x27;, response.error)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After the response promise resolve you will see.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&amp;#x27;RuntimeException: E_UNDEFINED_METHOD: Method all missing on App/Controllers/Http/ChallengeController\n&amp;gt; More details: https://err.sh/adonisjs/errors/E_UNDEFINED_METHOD&amp;#x27;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is normal, we make use of a method in controller who do not exist.&lt;/p&gt;&lt;p&gt;Go inside your ChallengeController and add this method&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;async all({ response, request }) {
  const challenges = await Challenge.all()

  return response.ok(challenges)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now after running the test, all should be green :)&lt;/p&gt;&lt;p&gt;This call the all method from your Challenge model and this will return an array of all the challenge available. The response.ok will return a JSON object with the status &lt;code&gt;200 OK&lt;/code&gt; :)&lt;/p&gt;&lt;h2&gt;Get /api/challenges/:id&lt;/h2&gt;&lt;p&gt;Time to work on getting a single challenge by his id.&lt;/p&gt;&lt;p&gt;Pretty simple work again, just need to follow those step.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;adonis make:test GetChallenge
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can copy and paste the last test we create about to get all challenges this will look almost the same.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;&amp;#x27;use strict&amp;#x27;

const Factory = use(&amp;#x27;Factory&amp;#x27;)
const { test, trait } = use(&amp;#x27;Test/Suite&amp;#x27;)(&amp;#x27;Get Challenge&amp;#x27;)

trait(&amp;#x27;Test/ApiClient&amp;#x27;)
trait(&amp;#x27;Auth/Client&amp;#x27;)

test(&amp;#x27;can get a challenge by id&amp;#x27;, async ({ assert, client }) =&amp;gt; {
  const challenges = await Factory.model(&amp;#x27;App/Models/Challenge&amp;#x27;).createMany(3)

  const challenge = challenges[0]

  const response = await client.get(`/api/challenges/${challenge.id}`).end()

  response.assertStatus(200)

  response.assertJSONSubset({ title: challenge.title, id: challenge.id })
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A pretty simple one, we create 3 challenges just to make it a bit more realistic. We after that create a variable challenge who will be the first one in the array. We then add the id to the URL. In the end, we check for the status 200 and also the JSON will need to have both title and id who match this challenge.&lt;/p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:926px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/dd0bb8c2a86020b0f0d04bf9f7f732da/e1ed5/error-2.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:47.94816414686826%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAABYlAAAWJQFJUiTwAAABK0lEQVQoz42R3XKCMBCFeZhaJUCkCUQpo6DtjD+1XDB60b5gO9P2pi94esLfoINTLz42OckeNrvO2iywD2dIZYSFmSPWBobkZMl9pmLkU2p+hLmvIVUCzRyP2tjTmFDv47hCYcoDSZSoo0U3exvDRpNMENLAZwFuEA8bBvz4PPD593uuW0Y9Op33rEkbrcGlqfO5e8HP2zs+NjuknsIdRbc61OcMVDNYYRYa9inBktFrqmxNxlWSrayndetoEMd3NRL2MSUr9szw8pqsyIY8k4wkRJHRf4aFVthLzUlrbKMHPAUaj43JoVm/MgaXLbhmuC0EvCjELJcoTx5EUD/LZZLoGVitfW4drxiWcYpjlKAkQTXBtuHn3NzDb07593jC16HopjwZmvINZpY/jgU7Zbxb8o8AAAAASUVORK5CYII=&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;error 2&quot; title=&quot;error 2&quot; src=&quot;/static/dd0bb8c2a86020b0f0d04bf9f7f732da/e1ed5/error-2.png&quot; srcSet=&quot;/static/dd0bb8c2a86020b0f0d04bf9f7f732da/f4a45/error-2.png 259w,/static/dd0bb8c2a86020b0f0d04bf9f7f732da/ef0f6/error-2.png 518w,/static/dd0bb8c2a86020b0f0d04bf9f7f732da/e1ed5/error-2.png 926w&quot; sizes=&quot;(max-width: 926px) 100vw, 926px&quot; loading=&quot;lazy&quot;/&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;p&gt;Follow the same step we have made before, so go to routes and add the route for this one.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;Route.get(&amp;#x27;/api/challenges/:id&amp;#x27;, &amp;#x27;ChallengeController.show&amp;#x27;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After this, your test will say we don&amp;#x27;t have the method in your controller. Time to add this&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;async show({ response }) {
  return response.ok({})
}
&lt;/code&gt;&lt;/pre&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1035px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/47a9bd75cb8afacbff5c62aa8b358661/53472/error-3.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:31.02189781021898%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAABYlAAAWJQFJUiTwAAAA0ElEQVQY033RTQ6CMBQE4B7EhYACIiCUVkr9xWjcGD2JG++fjAOCEmNcfJn2pWn7WqFjhUd9wlVZOJHElPNeQH6XQ+GPWk+kcYGbNDinGnJewJIhTXOKu2xEFH6LBkkiSTQKFhQ3LhIFs9AoU9XKSZNkLc80MmZEPgW9bPlJrhF+WcE71/D2G7g0Pu7g1FuMD1u45JkKE66ZNGksphy/LcmuXuPKtkSQlxipEg5PCZPX+7SZdvNBO3/NupY1W76vD7hI3oCf0m44eKPgzwf88gReCbroRWpkmwAAAABJRU5ErkJggg==&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;error 3&quot; title=&quot;error 3&quot; src=&quot;/static/47a9bd75cb8afacbff5c62aa8b358661/17fa4/error-3.png&quot; srcSet=&quot;/static/47a9bd75cb8afacbff5c62aa8b358661/f4a45/error-3.png 259w,/static/47a9bd75cb8afacbff5c62aa8b358661/ef0f6/error-3.png 518w,/static/47a9bd75cb8afacbff5c62aa8b358661/17fa4/error-3.png 1035w,/static/47a9bd75cb8afacbff5c62aa8b358661/d6f0c/error-3.png 1553w,/static/47a9bd75cb8afacbff5c62aa8b358661/53472/error-3.png 1644w&quot; sizes=&quot;(max-width: 1035px) 100vw, 1035px&quot; loading=&quot;lazy&quot;/&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;p&gt;The next error is important, is the one who checks if the return object matches what we supposed. It&amp;#x27;s pretty normal it failed here we return an empty object. So time to make it work.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;async show({ response, params }) {
  const challenge = await Challenge.find(params.id)

  return response.ok(challenge)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For getting access of the params id we make use of the params object and we then call find from the Challenge Model.&lt;/p&gt;&lt;p&gt;If you run all the test now all will be green.&lt;/p&gt;&lt;p&gt;But we need one more test for this endpoint. What will happen if the id do not exist?&lt;/p&gt;&lt;p&gt;If you try it this will fail. A pretty easy test to write&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;test(&amp;#x27;status 404 if id do not exist&amp;#x27;, async ({ assert, client }) =&amp;gt; {
  const response = await client.get(&amp;#x27;/api/challenges/999&amp;#x27;).end()

  response.assertStatus(404)
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Does the error say 204 should equal 404? Umh strange, time to fix it.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;async show({ response, params }) {
  const challenge = await Challenge.findOrFail(params.id)

  return response.ok(challenge)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Yes, only one thing to change, findOrFail like the name says will return 404 if the object is not found :) Really nice and easy :)&lt;/p&gt;&lt;p&gt;Source code: &lt;a href=&quot;https://github.com/EQuimper/adonis-tdd-tutorial-demo/tree/part-2&quot;&gt;https://github.com/EQuimper/adonis-tdd-tutorial-demo/tree/part-2&lt;/a&gt;&lt;/p&gt;&lt;h2&gt;End word&lt;/h2&gt;&lt;p&gt;Hope you enjoy this one, not too much, but we start to understand the flow and see how TDD help us going faster on the implementation of the API.&lt;/p&gt;&lt;p&gt;In the next part, we will add a way for a user to get all of his challenges. And also a way to update and delete the challenge if you are the author.&lt;/p&gt;&lt;p&gt;Happy coding :)&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Attempting to learn Dart and Flutter: Part 3]]></title><description><![CDATA[In the past week I've been working on a personnal project using Flutter and Firestore. In this post will show how I did match the BLoC pattern with Firestore]]></description><link>https://equimper.com/blog/attempting-to-learn-dart-and-flutter-part-3</link><guid isPermaLink="false">https://equimper.com/blog/attempting-to-learn-dart-and-flutter-part-3</guid><category><![CDATA[tutorial]]></category><category><![CDATA[flutter]]></category><category><![CDATA[dart]]></category><category><![CDATA[firestore]]></category><category><![CDATA[firebase]]></category><pubDate>Fri, 29 Mar 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Intro&lt;/h2&gt;&lt;p&gt;So &lt;a href=&quot;https://firebase.google.com/docs/firestore/&quot;&gt;Firestore&lt;/a&gt; a NoSQL database, is kind of like the second generation of &lt;a href=&quot;https://firebase.google.com/&quot;&gt;Firebase&lt;/a&gt;. Nice product, I liked it, even if you need to rethink about a lot of stuff. Lately, I&amp;#x27;ve been playing with a personal project &lt;em&gt;&amp;quot;I will have more info about this one in the next month :)&amp;quot;&lt;/em&gt; with Flutter and Firestore. Here some stuff I found with this experiment.&lt;/p&gt;&lt;p&gt;First Firestore/Firebase give you quite a lot, analytics, authentication, email verification, real-time data, etc. So for an MVP of the product, I want to build it&amp;#x27;s the way to go I think. Autoscale, dashboard, etc, all came with that. Pretty nice for a one-man army. Also, the &lt;a href=&quot;https://pub.dartlang.org/packages/cloud_firestore&quot;&gt;integration with Flutter&lt;/a&gt; is really great. For sure it&amp;#x27;s a help when both products are own by the same company.&lt;/p&gt;&lt;h2&gt;BLoC (Business Logic Component)&lt;/h2&gt;&lt;p&gt;So after reading a lot online, and see a lot of conference on &lt;a href=&quot;https://youtu.be/RS36gBEp8OI&quot;&gt;Youtube&lt;/a&gt; I see Google encouraged the developer to use the &lt;strong&gt;BLoC Pattern&lt;/strong&gt;. Yes at the beginning that was quite hard to understand the flow and everything. But remind me a lot of what I was doing when I was using redux observable with react-native. So finally the BLoC pattern is kind of like React Context + RxJS. First, you create a BLoC who is a simple class. And after that, you create a provider who is an &lt;code&gt;InheritedWidget&lt;/code&gt;. This lets you have access to the BLoC himself from anywhere in the app if you wrap the full app with the provider.&lt;/p&gt;&lt;p&gt;&lt;code&gt;youtube:RS36gBEp8OI&lt;/code&gt;&lt;/p&gt;&lt;p&gt;Like React Context this let you jump some Widget. So no need to do props drill. But what is a BLoC? For me, because of my Redux or Mobx experience, I think of it like a Reducer or a Store. The UI trigger some action in this BLoC and this one past down the new state. I know maybe not the best way of thinking about this, but hey I&amp;#x27;m not a master on Flutter, I learn on my free time :)&lt;/p&gt;&lt;h2&gt;How to use BLoC with Firestore&lt;/h2&gt;&lt;p&gt;So Firestore gives you already a stream when you retrieved data from the DB. Really nice you can pass this directly to the StreamBuilder if you want.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;return StreamBuilder(
  stream: Firestore.instance.collection(&amp;#x27;my collections&amp;#x27;).snapshots()
);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But what should I do if I want to move out of Firestore later? My UI depends too much of this if I wrap all the listener like that. So for me, I like to remove the business logic from the UI to keep it clean, and easier to refactor later.&lt;/p&gt;&lt;p&gt;The thing is it&amp;#x27;s easy to say perfect go and use BLoC + Firestore, but you don&amp;#x27;t gonna find too much documentation online. And the tutorials I found is not quite like I really want.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;What do I want?&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Using BLoC&lt;/li&gt;&lt;li&gt;But getting the typing working for me so I want model class.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;What do I mean by &lt;em&gt;But getting the typing working for me so I want model class.&lt;/em&gt;? If you use Firestore you receive from the stream a QuerySnapshot or DocumentSnaphot. This thing will return you a Map who can be used in Dart. The thing is a Map is too much dynamic for me. I&amp;#x27;m not coming to a typing language to start doing dynamic stuff.&lt;/p&gt;&lt;p&gt;In Dart you can have multiple Constructor, it&amp;#x27;s a really good place if you want to create a model class who can parse himself from json or map.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;class TodoModel {
  final String title;
  final bool completed;

  TodoModel({
    this.title,
    this.completed = false,
  });

  TodoModel.fromMap(Map&amp;lt;dynamic, dynamic&amp;gt; map)
      : title = map[&amp;#x27;title&amp;#x27;],
        completed = map[&amp;#x27;completed&amp;#x27;];
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As you can see here my constructor fromMap will take the map and parsed it to my object. You see the &lt;code&gt;map[&amp;#x27;title&amp;#x27;]&lt;/code&gt; stuff? I want that to just stay here, I don&amp;#x27;t want to start using this everywhere in my app. So that&amp;#x27;s why I say I want it type to an object. So how can we make Firestore working this way? I mean I want to be able to do inside my UI something like that.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;return Text(todo.title);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here what I did.&lt;/p&gt;&lt;h2&gt;My solution&lt;/h2&gt;&lt;p&gt;&lt;em&gt;P.S this is just based on some experimentation, and for my use case, I&amp;#x27;m still learning flutter so please, I know this is surely not optimum :)&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;P.S I use rxdart&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;The Repository is just a wrapper around my FirestoreProvider&lt;/em&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;class TodosBloc {
  final _repository = Repository();
  final _todos = BehaviorSubject&amp;lt;QuerySnapshot&amp;gt;();

  Observable&amp;lt;List&amp;lt;TodoModel&amp;gt;&amp;gt; get todos =&amp;gt; _todos.stream.transform(_todosTransformer());

  void dispose() async {
    await _todos.drain();
    _todos.close();
  }

  void getTodos() {
    _repository.getTodos().listen(_todos.sink.add);
  }

  StreamTransformer&amp;lt;QuerySnapshot, List&amp;lt;TodoModel&amp;gt;&amp;gt; _todosTransformer() {
    return StreamTransformer.fromHandlers(handleData: (
        QuerySnapshot data,
        EventSink&amp;lt;List&amp;lt;TodoModel&amp;gt;&amp;gt; sink,
        ) {

        final todos = data.documents.map((snap) =&amp;gt; TodoModel.fromMap(snap.data)).toList();

        sink.add(todos);
    }, handleError: (error, stackTrace, sink) {
      sink.addError(error);
    });
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here is nothing crazy, &lt;strong&gt;I will make another post about a tutorial about it maybe later, here it&amp;#x27;s just to show you how I did&lt;/strong&gt; the main point here is I listen to my stream from Firestore who is the stream who return a list of map to a new stream who transform his values to a list of TodoModel. Now when I want to use it I can do that.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;return StreamBuilder(
  stream: todosBloc.todos,
  builder: (BuildContext context, AsyncSnapshot&amp;lt;List&amp;lt;TodoModel&amp;gt;&amp;gt; snapshot) {
    switch (snapshot.connectionState) {
      case ConnectionState.waiting:
        return Center(
          child: CircularProgressIndicator(),
        );
      default:
        return ListView.builder(
          itemBuilder: (BuildContext context, int index) {
            final todo = snapshot.data[index];
            return Container(
              child: Text(todo.title),
            );
          },
          itemCount: snapshot.data.length,
       );
    }
  },
);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So now I can use my data like I want, as my class model. The autocomplete is there, and the linting also. So I cannot misspell something everywhere, the only place where I need to make sure I don&amp;#x27;t make type is the class model himself.&lt;/p&gt;&lt;h2&gt;End word&lt;/h2&gt;&lt;p&gt;I hope you enjoy this little post, and maybe even learn something. Let me know in the comments if you have any question :)&lt;/p&gt;&lt;p&gt;Happy Coding :)&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Attempting to learn Dart and Flutter: Part 2]]></title><description><![CDATA[Second post of my series Attempting to learn Dart and Flutter, in this one we will talk about how I'm able to dismissed the keyboard and how to close a modal.]]></description><link>https://equimper.com/blog/attempting-to-learn-dart-and-flutter-part-2</link><guid isPermaLink="false">https://equimper.com/blog/attempting-to-learn-dart-and-flutter-part-2</guid><category><![CDATA[tutorial]]></category><category><![CDATA[flutter]]></category><category><![CDATA[dart]]></category><category><![CDATA[react-native]]></category><pubDate>Mon, 25 Mar 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Intro&lt;/h2&gt;&lt;p&gt;Flutter has so many widgets, they are all so awesome, you have one for almost everything.
I really like that, this lets you create your app so much faster, and you have less code to write.
Less code less bug :) But sometimes, in Flutter, I find stuff pretty hidden, I mean the docs are really really great.
But in the case I want to show here, I was quite confused about how I will use this.&lt;/p&gt;&lt;h2&gt;Dismissed the keyboard.&lt;/h2&gt;&lt;p&gt;So for those coming from react-native, we can use the component &lt;a href=&quot;https://github.com/APSL/react-native-keyboard-aware-scroll-view&quot;&gt;react-native-keyboard-aware-scroll-view&lt;/a&gt; who follow the input and also handle the dismiss of the keyboard.
Love this package, but at the same time, I ask myself why this one is not built in. I know you have the &lt;a href=&quot;https://facebook.github.io/react-native/docs/keyboardavoidingview&quot;&gt;KeyboardAvoidingView&lt;/a&gt; but it&amp;#x27;s
not the same quality as this community package. For dismissing a keyboard programmatically, we can do&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;Keyboard.dismiss()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Easy enough. I like this. Now time to see how to do this in Flutter.&lt;/p&gt;&lt;p&gt;In Flutter, the keyboard will follow with the input, at least in android. It&amp;#x27;s pretty nice, so no need to have a third-party library or doing any effort to have this keyboard not showing on top of the input.
But the thing is how can I dismiss the keyboard. Yes, it&amp;#x27;s not already built.
So what I found is that. &lt;strong&gt;PS&lt;/strong&gt; I don&amp;#x27;t know if this is the best solution but for my case, it&amp;#x27;s work pretty good.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;return GestureDetector(
  onTap: () {
    // Dismiss keyboard on outside tap
    FocusScope.of(context).requestFocus(new FocusNode());
  },
  child: Scaffold(
    body: SingleChildScrollView(
      child: Container(),
    ),
  ),
);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As you can see I wrap the full &lt;code&gt;Scaffold&lt;/code&gt; widget with a &lt;code&gt;GestureDetector&lt;/code&gt; and I check for the &lt;code&gt;onTap&lt;/code&gt; event.
When press I can then request the focus on something else.
This way I can dismiss the keyboard.
Not as straight forward as react-native but not that bad.&lt;/p&gt;&lt;h2&gt;Close the ModalBottomSheet&lt;/h2&gt;&lt;p&gt;Flutter give us for free an awesome &lt;code&gt;ModalBottomSheet&lt;/code&gt; who can be used to help a user see action at the bottom of the screen.
I love this thing so much. If you want to show this to the user you only need to call &lt;code&gt;showModalBottomSheet&lt;/code&gt; and that&amp;#x27;s it.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;_onFabPress(BuildContext context) {
  showModalBottomSheet(
    context: context,
    builder: (BuildContext context) {
      return SafeArea(
        child: Container(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: &amp;lt;Widget&amp;gt;[
              new ListTile(
                leading: Icon(Icons.directions_run),
                title: Text(&amp;#x27;New Workout&amp;#x27;),
                onTap: () {
                  Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (BuildContext context) {
                        return WorkoutScreen(
                          workout: WorkoutModel(
                            title: &amp;#x27;New Workout&amp;#x27;,
                            date: DateTime.now(),
                          ),
                        );
                      },
                    ),
                  );
                },
              ),
            ],
          ),
        ),
      );
    });
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here I can show the modal with 1 list tile. The modal will then dismiss on outside press, can be swipe down etc. But if use this like that, when I click on an item and open a new screen, and after I go back the modal will still open.
I need to implicitly tell the navigation to dismiss this one. How can I do this? Pretty easy, I just added &lt;code&gt;Navigator.pop(context);&lt;/code&gt; before the navigation inside the &lt;code&gt;onTap()&lt;/code&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;_onFabPress(BuildContext context) {
  showModalBottomSheet(
    context: context,
    builder: (BuildContext context) {
      return SafeArea(
        child: Container(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: &amp;lt;Widget&amp;gt;[
              new ListTile(
                leading: Icon(Icons.directions_run),
                title: Text(&amp;#x27;New Workout&amp;#x27;),
                onTap: () {
                  // This will dismiss the modal
                  Navigator.pop(context);
                  Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (BuildContext context) {
                        return WorkoutScreen(
                          workout: WorkoutModel(
                            title: &amp;#x27;New Workout&amp;#x27;,
                            date: DateTime.now(),
                          ),
                        );
                      },
                    ),
                  );
                },
              ),
            ],
          ),
        ),
      );
    });
}
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;End word&lt;/h2&gt;&lt;p&gt;Right now, I really liked Flutter, I&amp;#x27;m building my first real app with this and just wow. So many great things.
Yes is not all Pros, I have some Cons.
Lot of them is because I know how to make it in react-native and need to search a lot for the Flutter version.
But at the same time, so many thing are much easier.&lt;/p&gt;&lt;p&gt;Hope you enjoy.&lt;/p&gt;&lt;p&gt;Happy Coding :) &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Attempting to learn Dart and Flutter: Part 1]]></title><description><![CDATA[I've been playing with Flutter for the past month and just wow. So I would like to keep track of what I learn here about Flutter and Dart, maybe that can help other.]]></description><link>https://equimper.com/blog/attempting-to-learn-dart-and-flutter-part-1</link><guid isPermaLink="false">https://equimper.com/blog/attempting-to-learn-dart-and-flutter-part-1</guid><category><![CDATA[tutorial]]></category><category><![CDATA[flutter]]></category><category><![CDATA[dart]]></category><category><![CDATA[react-native]]></category><pubDate>Mon, 18 Mar 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Intro&lt;/h2&gt;&lt;p&gt;I&amp;#x27;ve been playing with &lt;a href=&quot;https://flutter.dev/&quot;&gt;Flutter&lt;/a&gt; for the past month and just wow. So here would be kind of a journal of my progress in the path of learning Flutter and Dart.&lt;/p&gt;&lt;h2&gt;Why doing this ?&lt;/h2&gt;&lt;p&gt;After &lt;a href=&quot;https://dev.to/shindakun/attempting-to-learn-go---building-a-downloader-part-01-44gl&quot;&gt;reading this awesome series&lt;/a&gt; where Steve show how he learn Go I figured out why not doing this also. I learn a lot just from those post and maybe some people can learn from mine here.&lt;/p&gt;&lt;h2&gt;What this series is about ?&lt;/h2&gt;&lt;p&gt;So for those who know me, I&amp;#x27;m a React/React-Native developer for the past 3+ years. I loved &lt;a href=&quot;https://reactjs.org/&quot;&gt;React&lt;/a&gt; and &lt;a href=&quot;https://facebook.github.io/react-native/&quot;&gt;React-Native&lt;/a&gt;. But as a developer who is always curious and also who loved to learn I decided why not giving a chance to Flutter.&lt;/p&gt;&lt;p&gt;So I&amp;#x27;ve watch lot of videos on Youtube about it, tutorial, &lt;a href=&quot;https://www.youtube.com/playlist?list=PLOU2XLYxmsIL0pH0zWe_ZOHgGhZ7UasUE&quot;&gt;widget of the week&lt;/a&gt; etc... . I even start to created a playlist about those must watch video &lt;a href=&quot;https://www.youtube.com/playlist?list=PLzQWIQOqeUSMhUDr4ntMmtBHIdn4DaLqr&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;In this series I will try to show tips and tricks for those coming like me from the world on React-Native. I always find it easier when learning new stuff, comparing it with what you already know. This will be a place for
me to also improved, cause when you teach you learn so much.&lt;/p&gt;&lt;h2&gt;Attempting to learn Dart and Flutter: Part 1&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;This part 1 is more an introduction of the series, not lot of code will be involved in this one.&lt;/strong&gt;&lt;/p&gt;&lt;h3&gt;Dart&lt;/h3&gt;&lt;p&gt;I&amp;#x27;ve been playing with &lt;a href=&quot;https://www.typescriptlang.org/&quot;&gt;Typescript&lt;/a&gt; for the past year and really like it, this is really an upgrade of javascript for me. I really loved type.&lt;/p&gt;&lt;p&gt;So when I see &lt;a href=&quot;https://www.dartlang.org/&quot;&gt;Dart&lt;/a&gt; is type and look a lot like it I really start to get excited. First I even feel &lt;code&gt;Dart &amp;gt; Typescript&lt;/code&gt;. The type system is easier, you can have everything you like in Typescript almost but I fill is more tighten to the language.
The devtools is awesome with dart also. Really well integrated with &lt;a href=&quot;https://code.visualstudio.com/&quot;&gt;VSCode&lt;/a&gt; or the text editor I used right now &lt;a href=&quot;https://www.jetbrains.com/idea/&quot;&gt;IntelliJ&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;For learning Dart and Flutter my first step was to do this &lt;a href=&quot;https://www.udemy.com/dart-and-flutter-the-complete-developers-guide/&quot;&gt;Tutorial&lt;/a&gt; by Stephen Grider. Just loved it :) Wow, I take so many course from him in the past, and this one again is so good.
You start by going over Dart and right after Flutter.&lt;/p&gt;&lt;p&gt;You learn:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;State Management&lt;/li&gt;&lt;li&gt;RxDart&lt;/li&gt;&lt;li&gt;Animation&lt;/li&gt;&lt;li&gt;Navigation&lt;/li&gt;&lt;li&gt;Abstract Class&lt;/li&gt;&lt;li&gt;Testing http call&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;What I liked about Flutter ?&lt;/h3&gt;&lt;p&gt;So here a list of what I really like about Flutter and why I think this can maybe become really really big.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Hot Stateful Reload&lt;/li&gt;&lt;li&gt;Integration with DevTools&lt;/li&gt;&lt;li&gt;Profiler&lt;/li&gt;&lt;li&gt;Performance peek right inside the Text Editor&lt;/li&gt;&lt;li&gt;The performance of Flutter is wow even for a cross-platform tool.&lt;/li&gt;&lt;li&gt;Debugger is top notch&lt;/li&gt;&lt;li&gt;Navigation is integrated no package to install and also really easy to use.&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://youtu.be/ek8ZPdWj4Qo&quot;&gt;FutureBuilder&lt;/a&gt; are just wow, they are like Suspense in react&lt;/li&gt;&lt;li&gt;Build in testing tool&lt;/li&gt;&lt;li&gt;App size are really small for the hello world project. &lt;a href=&quot;https://flutter.dev/docs/resources/faq#how-big-is-the-flutter-engine&quot;&gt;2.7mb&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://youtu.be/MkKEWHfy99Y&quot;&gt;StreamBuilder&lt;/a&gt; pretty nice too.&lt;/li&gt;&lt;li&gt;Android app are really good, I can get easily 60fps for animation and same for ios, something who was hard to get in react-native.&lt;/li&gt;&lt;li&gt;Animation are so good, really easy to figure out how to play with, I love using also canvas etc.&lt;/li&gt;&lt;li&gt;In ios when you use &lt;a href=&quot;https://flutter.dev/docs/development/ui/widgets/cupertino&quot;&gt;Cupertino&lt;/a&gt; you can have even the navigation big title animation&lt;/li&gt;&lt;li&gt;Context kind of api with Inherited Widget&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Image of what I mean when I say really well integrated with Text Editor&lt;/p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1035px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/f2386444bb4a8f119a3ce88084908db6/8b4c6/1.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:57.22305389221557%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAABYlAAAWJQFJUiTwAAACJklEQVQoz11Su3LUMBT1d6zX1tOyLMv2xuslyTIUfBIdX0FLlS0oQgoKKhi3zPAjMO4pKCCR53KkzWQyFEePK+ncc89V1u/GN86577qqvmitZyXVzBibBeezqfRcATGO8/MM+K6bm6aZ67pGHHeU+mqM+aaMeZvV2twOzlNVVaSUot63dDn1NAw7cs6S0ohrnc4ihJS0G/d0OBzIWvsUj++lrj5npeA3pnGU55s/ZVmGvvPhMPrgvQ/O+dD3XbC2CVAGVIAMHWJ9PwQhRNhutyHP87+YiTN+myH7qbE1CPOHkjHa9T1dXb6grm2SApRMIEsKIjTUdLjTek+cc4KIiMAwayHvMgPCrm0TIbyjtrH0+uVEr44THaaRvGvIIaEx1ZMtbRctGQg+J1IOpZGQFcVdBtmneBGSEyHMpYuLC9pPE+3HMT2E+U8KlZLkWp88jmQQEhGKoqDNZnOXYTiV2GzzM2ENwuN0oOP1NQ19hwR1KjmVjbOosEETRzTmWVOCRLOKqLAx9uRsE+U/xIxSCjKVOXcN6xiLZL5DiVKlPSsZKSFJgSTtGQtxToTW1Ddn86t7YMXjFRkT4jqiru3a9cMKr9ZtUay8LFfJ+Yq/ucKyFU25fyz/Y/TwQ/LosZPRw/9hG1QgBAlYEr0aEdtDhH48q2BL/KuM8U/4NuodCH9D5Q88XhjnC38GlLOAbBFcLDquyzIBHV2gaCmLMt77KZX+pZR+/w+seirhnJM1OAAAAABJRU5ErkJggg==&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;1&quot; title=&quot;1&quot; src=&quot;/static/f2386444bb4a8f119a3ce88084908db6/17fa4/1.png&quot; srcSet=&quot;/static/f2386444bb4a8f119a3ce88084908db6/f4a45/1.png 259w,/static/f2386444bb4a8f119a3ce88084908db6/ef0f6/1.png 518w,/static/f2386444bb4a8f119a3ce88084908db6/17fa4/1.png 1035w,/static/f2386444bb4a8f119a3ce88084908db6/d6f0c/1.png 1553w,/static/f2386444bb4a8f119a3ce88084908db6/a1bed/1.png 2070w,/static/f2386444bb4a8f119a3ce88084908db6/8b4c6/1.png 5344w&quot; sizes=&quot;(max-width: 1035px) 100vw, 1035px&quot; loading=&quot;lazy&quot;/&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;h3&gt;What are the cons&lt;/h3&gt;&lt;p&gt;Here a list of what I don&amp;#x27;t really like for now about it&lt;/p&gt;&lt;ul&gt;&lt;li&gt;State management is not simple like react-native&lt;/li&gt;&lt;li&gt;Not all packages are create yet, react-native have all the js ecosystem who is a big plus.&lt;/li&gt;&lt;li&gt;Widget hell&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;A list of stuff to check if you are interested.&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://codemagic.io/&quot;&gt;CodeMagic&lt;/a&gt; A CI/CD just for Flutter&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/channel/UCtWyVkPpb8An90SNDTNF0Pg&quot;&gt;Fluttery&lt;/a&gt; An awesome Youtube Channel about Flutter animation etc&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/roughike/inKino&quot;&gt;Inkino&lt;/a&gt; An open source cinema app build for the mobile + web cause yes dart can be used for the web.&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://itsallwidgets.com/&quot;&gt;itsallwidgets&lt;/a&gt; A site for showcasing app build with Flutter&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;End word&lt;/h3&gt;&lt;p&gt;I hope you enjoy this little intro, yes I know not lot of code. But in the next part we gonna start to learn a bit more. :) Let me know in the comments if you have any questions or more :)&lt;/p&gt;&lt;p&gt;Happy Coding :)&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Build a REST API with AdonisJs and TDD Part 1]]></title><description><![CDATA[Want to learn how to use AdonisJs by building a rest api using TDD approach? This is the tutorial you want]]></description><link>https://equimper.com/blog/build-a-rest-api-with-adonisjs-and-tdd-part-1</link><guid isPermaLink="false">https://equimper.com/blog/build-a-rest-api-with-adonisjs-and-tdd-part-1</guid><category><![CDATA[tutorial]]></category><category><![CDATA[adonisjs]]></category><category><![CDATA[tdd]]></category><category><![CDATA[javascript]]></category><category><![CDATA[testing]]></category><pubDate>Wed, 02 Jan 2019 00:00:00 GMT</pubDate><content:encoded>&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://equimper.com/blog/build-a-rest-api-with-adonisjs-and-tdd-part-2&quot;&gt;Part 2&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://equimper.com/blog/build-a-rest-api-with-adonisjs-and-tdd-part-3&quot;&gt;Part 3&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://equimper.com/blog/build-a-rest-api-with-adonisjs-and-tdd-part-4&quot;&gt;Part 4&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/EQuimper/adonis-tdd-tutorial-demo&quot;&gt;Source Code&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I&amp;#x27;ve been playing lately with &lt;a href=&quot;https://adonisjs.com&quot;&gt;AdonisJs&lt;/a&gt; a NodeJS MVC framework who look a lot like &lt;a href=&quot;https://laravel.com/&quot;&gt;Laravel&lt;/a&gt; a really popular PHP framework. I really started to love the Adonis approach, more convention than configuration. I also love the fact they say in the headline.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;Writing micro-services or you are a fan of TDD, it all boils down to confidence. AdonisJs simplicity will make you feel confident about your code.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In the past few month, I wrote all my backend project with the TDD pattern, and I really feel this help me getting more productive, and more confident with my code. I know TDD is not perfect, can slow you down, when you start, but I really think this can improved your code in the long term.&lt;/p&gt;&lt;h3&gt;About this tutorial&lt;/h3&gt;&lt;p&gt;So in this tutorial we gonna build kind of a bucket list for movies to watch. A user can create a challenge, and put movies to this one. I know, this is not the most awesome project ever, but this will help you see how Lucid, the Adonis ORM work with relationship. We gonna also see how easy this framework will make our live.&lt;/p&gt;&lt;p&gt;At the end of this tutorial, we gonna create a service where a user can finally enter just the name of the movie and the year. Us we will use &lt;a href=&quot;https://www.themoviedb.org&quot;&gt;TheMovieDB Api&lt;/a&gt; and find info about this movie.&lt;/p&gt;&lt;h3&gt;Getting Started&lt;/h3&gt;&lt;p&gt;First we need to install the Adonis cli&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;npm i -g @adonisjs/cli
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To make sure everything work run the command in your terminal&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;adonis --help
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you see a list of command that mean this is working :)&lt;/p&gt;&lt;p&gt;For creating the project we will run this command in the terminal&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;adonis new movies_challenges --api-only
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here this will create a new project call &lt;code&gt;movies_challenges&lt;/code&gt; and this will be an api only boilerplate, so no ui with this.&lt;/p&gt;&lt;p&gt;Follow the instructions&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-cmshd&quot;&gt;cd movies_challenges
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For running the project the command will be&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;adonis serve --dev
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But for us we don&amp;#x27;t really need cause all the interaction will be done from the testing.&lt;/p&gt;&lt;p&gt;Open the project in your text-editor of choice. For myself I use &lt;a href=&quot;https://code.visualstudio.com/&quot;&gt;VSCode&lt;/a&gt; it&amp;#x27;s free and awesome.&lt;/p&gt;&lt;h2&gt;Setup the db&lt;/h2&gt;&lt;p&gt;Adonis have setup lot of stuff for us. But they let us choosing some stuff like which db to use etc. If you open the file &lt;code&gt;config/database.js&lt;/code&gt; you will see &lt;code&gt;sqlite&lt;/code&gt;, &lt;code&gt;mysql&lt;/code&gt; and &lt;code&gt;postgresql&lt;/code&gt; config. For this project I will be using Posgresql&lt;/p&gt;&lt;p&gt;To make it work we need to follow the instruction they provide at the bottom of this file.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;npm i --save pg
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After this go inside your &lt;code&gt;.env&lt;/code&gt; file and setup the connection for your db. For me this will look like&lt;/p&gt;&lt;pre&gt;&lt;code&gt;DB_CONNECTION=pg
DB_HOST=127.0.0.1
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=postgres
DB_DATABASE=movies_challenges_dev
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After I make sure I create the db from my terminal&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;createdb movies_challenges_dev
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Setup the testing environnment&lt;/h2&gt;&lt;p&gt;Adonis don&amp;#x27;t came with a testing framework out-of-the-box, but it&amp;#x27;s really easy to make it work.&lt;/p&gt;&lt;p&gt;Run the command&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;adonis install @adonisjs/vow
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;What is that ? Adonis have a way to install dependency by using npm internally. But the beauty of this it&amp;#x27;s they can add other stuff also. Like if you look what happen after this is done, they will open a a url in your browser with other instructions.&lt;/p&gt;&lt;p&gt;They have create 3 new files.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;.env.testing
vowfile.js
example.spec.js
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;First we will setup the &lt;code&gt;.env.testing&lt;/code&gt; file to make sure we it a test db and not the dev one.&lt;/p&gt;&lt;p&gt;Append that to the end of the file&lt;/p&gt;&lt;pre&gt;&lt;code&gt;DB_CONNECTION=pg
DB_HOST=127.0.0.1
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=postgres
DB_DATABASE=movies_challenges_test
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After I make sure I create the db from my terminal&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;createdb movies_challenges_test
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Writing your first test&lt;/h2&gt;&lt;p&gt;So the way the app will work is a User can have many Challenges. Those challenge can have many movie to it. But movie can be to many challenge.&lt;/p&gt;&lt;p&gt;So in relationship this will look like&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://i.ibb.co/G5xjb5Z/Screenshot-2019-01-02-11-32-43.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;If you have check a bit the folder structure you will see Adonis give use User model and Auth of the box.&lt;/p&gt;&lt;p&gt;We will use this in the future.&lt;/p&gt;&lt;p&gt;So for making your first test file we will need to think about what we need to do.&lt;/p&gt;&lt;p&gt;The first thing I want to test is the fact a user can create a challenge. A challenge need to have a title, and a description is optionnal. I want to make sure only a authenticate user can create a challenge. When a challenge is create I need to put the current_user id to the data. So we will know who is the owner.&lt;/p&gt;&lt;p&gt;Adonis give us lot of tool to make our live easier. One of them is generator command thank to ace. We will use a command to make our first test. But to be able to do this we need to register the vow test framework to the provider of the project. Open &lt;code&gt;start/app.js&lt;/code&gt; and add this to your aceProvider&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; metastring=&quot;{3}&quot;&gt;const aceProviders = [
  &amp;#x27;@adonisjs/lucid/providers/MigrationsProvider&amp;#x27;,
  &amp;#x27;@adonisjs/vow/providers/VowProvider&amp;#x27;,
]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we can run the command&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;adonis make:test CreateChallenge
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;When you get ask unit or functionnal test use functionnal and click enter.&lt;/p&gt;&lt;p&gt;This will create a file&lt;/p&gt;&lt;pre&gt;&lt;code&gt;test/functional/create-challenge.spec.js
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Nice first test file create :)&lt;/p&gt;&lt;p&gt;We will change the title of this test to be more useful.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;test(&amp;#x27;can create a challenge if valid data&amp;#x27;, async ({ assert }) =&amp;gt; {})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now the way I wrote test is by creating the assertion first. After I then go backward and create the step I need to make it work.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;test(&amp;#x27;can create a challenge if valid data&amp;#x27;, async ({ assert }) =&amp;gt; {

  const response = // do api call

  response.assertStatus(201)
  response.assertJSONSubset({
    title: &amp;#x27;Top 5 2018 Movies to watch&amp;#x27;,
    description: &amp;#x27;A list of 5 movies from 2018 to absolutely watched&amp;#x27;,
    user_id: // to do
  })
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here I test than I want to receive back from my api call a &lt;code&gt;201 created&lt;/code&gt; with a certain object who will have the title a provide, the description I provide, and my current user id.&lt;/p&gt;&lt;p&gt;Next we need to write the code for the response&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const { test, trait } = use(&amp;#x27;Test/Suite&amp;#x27;)(&amp;#x27;Create Challenge&amp;#x27;)

trait(&amp;#x27;Test/ApiClient&amp;#x27;)

test(&amp;#x27;can create a challenge if valid data&amp;#x27;, async ({ assert, client }) =&amp;gt; {

  const data = {
    title: &amp;#x27;Top 5 2018 Movies to watch&amp;#x27;,
    description: &amp;#x27;A list of 5 movies from 2018 to absolutely watched&amp;#x27;
  }

  const response = await client.post(&amp;#x27;/api/challenges&amp;#x27;).send(data).end()

  response.assertStatus(201)
  response.assertJSONSubset({
    title: data.title,
    description: data.description,
    user_id: // to do
  })
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To make a api call we need to import first &lt;code&gt;trait&lt;/code&gt; from the test suite. We need to told the test we want the api client. This will give us now access to &lt;code&gt;client&lt;/code&gt; in the callback. I then put my data I want to an object and send it to a route with the verb &lt;code&gt;POST&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Now I want to test with a current user jwt in the headers. How can we do this ? This is so easy with Adonis&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;&amp;#x27;use strict&amp;#x27;

const Factory = use(&amp;#x27;Factory&amp;#x27;)
const { test, trait } = use(&amp;#x27;Test/Suite&amp;#x27;)(&amp;#x27;Create Challenge&amp;#x27;)

trait(&amp;#x27;Test/ApiClient&amp;#x27;)
trait(&amp;#x27;Auth/Client&amp;#x27;)

test(&amp;#x27;can create a challenge if valid data&amp;#x27;, async ({ assert, client }) =&amp;gt; {
  const user = await Factory.model(&amp;#x27;App/Models/User&amp;#x27;).create()

  const data = {
    title: &amp;#x27;Top 5 2018 Movies to watch&amp;#x27;,
    description: &amp;#x27;A list of 5 movies from 2018 to absolutely watched&amp;#x27;,
  }

  const response = await client
    .post(&amp;#x27;/api/challenges&amp;#x27;)
    .loginVia(user, &amp;#x27;jwt&amp;#x27;)
    .send(data)
    .end()

  response.assertStatus(201)
  response.assertJSONSubset({
    title: data.title,
    description: data.description,
    user_id: user.id,
  })
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;OMG !!! Too much. DONT WORRY. We just need to break it down a bit. So first what is Factory. Factory is a way to make dummy data easier. This come with a really nice api. Here the Factory will create a user to the db. But how can the factory know the data we want ? Easy just open the &lt;code&gt;database/factory.js&lt;/code&gt; file and add this at the bottom&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const Factory = use(&amp;#x27;Factory&amp;#x27;)

Factory.blueprint(&amp;#x27;App/Models/User&amp;#x27;, faker =&amp;gt; {
  return {
    username: faker.username(),
    email: faker.email(),
    password: &amp;#x27;password123&amp;#x27;,
  }
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here we create a Factory for the Models user we have in the db. This use faker also who is a library who make dummy data so much easier. Here I put a fake username and email. But why I don&amp;#x27;t do this to password ? It&amp;#x27;s because when I will need to test login I want to be able to log, and because the password will become hash I need to know what is the original version.&lt;/p&gt;&lt;p&gt;So this line&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const user = await Factory.model(&amp;#x27;App/Models/User&amp;#x27;).create()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We create a user to the db, now we can use this same user here in the request&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const response = await client
  .post(&amp;#x27;/api/challenges&amp;#x27;)
  .loginVia(user, &amp;#x27;jwt&amp;#x27;)
  .send(data)
  .end()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As you can see we can now use loginVia and pass the user at first argument, the second argument is the type of auth here I say jwt. I can use &lt;code&gt;.loginVia&lt;/code&gt; cause of this trait at the top&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;trait(&amp;#x27;Auth/Client&amp;#x27;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now in my json response I can now check the user id is really the one of the current user&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;response.assertJSONSubset({
  title: data.title,
  description: data.description,
  user_id: user.id,
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;One think we need to do before going further and run the test is we need to see the error from the response to do a real tdd.&lt;/p&gt;&lt;p&gt;So we will add this line before the assertion&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;console.log(&amp;#x27;error&amp;#x27;, response.error)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we can run the test with the command &lt;code&gt;adonis test&lt;/code&gt;&lt;/p&gt;&lt;p&gt;You will see the error&lt;/p&gt;&lt;pre&gt;&lt;code&gt;error: relation &amp;quot;users&amp;quot; does not exist
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;What that mean ? It&amp;#x27;s because Vow by default don&amp;#x27;t run migration. But us a developer we don&amp;#x27;t want to run it manually on every test that will be painful. What can we do ? Adonis make again our live easy. Go in the file &lt;code&gt;vowfile.js&lt;/code&gt; and uncomment the code already wrote for this&lt;/p&gt;&lt;pre&gt;&lt;code&gt;On line 14: const ace = require(&amp;#x27;@adonisjs/ace&amp;#x27;)
On line 37: await ace.call(&amp;#x27;migration:run&amp;#x27;, {}, { silent: true })
On line 60: await ace.call(&amp;#x27;migration:reset&amp;#x27;, {}, { silent: true })
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now if you rerun the test you will see&lt;/p&gt;&lt;pre&gt;&lt;code&gt;error { Error: cannot POST /api/challenges (404)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Nice one step further :) This error mean we don&amp;#x27;t have a route. We need to create it. Open &lt;code&gt;start/routes.js&lt;/code&gt; and add this code&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;Route.post(&amp;#x27;/api/challenges&amp;#x27;, &amp;#x27;ChallengeController.store&amp;#x27;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here I say, when we get a post request to the route &lt;code&gt;/api/challenges&lt;/code&gt; pass the data to the controller ChallengeController and the methods store. Remember Adonis is MVC so yes we need controller :)&lt;/p&gt;&lt;p&gt;Save the code and rerun the test&lt;/p&gt;&lt;p&gt;Now in the text of the error you will see&lt;/p&gt;&lt;pre&gt;&lt;code&gt;Error: Cannot find module \&amp;#x27;/Users/equimper/coding/tutorial/movies_challenges/app/Controllers/Http/ChallengeController\&amp;#x27;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This mean the controller don&amp;#x27;t exist :) So we need to create one. Again adonis have a generator for this&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;adonis make:controller ChallengeController
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;When ask choose http not websocket&lt;/p&gt;&lt;p&gt;Rerun the test&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&amp;#x27;RuntimeException: E_UNDEFINED_METHOD: Method store missing on App/Controllers/Http/ChallengeController\n&amp;gt; More details: https://err.sh/adonisjs/errors/E_UNDEFINED_METHOD&amp;#x27;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Method store is missing. Fine this is normal the controller is empty. Add this to your file&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// app/Controllers/Http/ChallengeController.js
class ChallengeController {
  store() {}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Rerun the test&lt;/p&gt;&lt;pre&gt;&lt;code&gt;expected 204 to equal 201
204 =&amp;gt; 201
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So now this is where the fun start, we expected 201 but received 204. We can fix this error by adding&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;class ChallengeController {
  store({ response }) {
    return response.created({})
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Adonis give us the response object who can be destructuring from the arguments of the method. Here I want to return 201 who mean created so I can use the created function. I pass an empty object so I can see my test failing further&lt;/p&gt;&lt;pre&gt;&lt;code&gt; expected {} to contain subset { Object (title, description, ...) }
  {
  + title: &amp;quot;Top 5 2018 Movies to watch&amp;quot;
  + description: &amp;quot;A list of 5 movies from 2018 to absolutely watched&amp;quot;
  + user_id: 1
  }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here the error mean we send nothing but expected stuff. Now time to do the logic.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const Challenge = use(&amp;#x27;App/Models/Challenge&amp;#x27;)

class ChallengeController {
  async store({ response, request }) {
    const challenge = await Challenge.create(
      request.only([&amp;#x27;title&amp;#x27;, &amp;#x27;description&amp;#x27;])
    )

    return response.created(challenge)
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I add an import at the top, this is my challenge model I plan to created in future test. Now I can make use of async and also the request object to create a challenge. The only method info can be see &lt;a href=&quot;https://adonisjs.com/docs/4.1/request#_only&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Now if I rerun the test I see&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&amp;#x27;Error: Cannot find module \&amp;#x27;/Users/equimper/coding/tutorial/movies_challenges/app/Models/Challenge\&amp;#x27;&amp;#x27;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Fine make sense the model don&amp;#x27;t exist&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;adonis make:model Challenge -m
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The -m give you the migration file also&lt;/p&gt;&lt;p&gt;This command will created&lt;/p&gt;&lt;pre&gt;&lt;code&gt;✔ create  app/Models/Challenge.js
✔ create  database/migrations/1546449691298_challenge_schema.js
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now if we return the test&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&amp;#x27;error: insert into &amp;quot;challenges&amp;quot; (&amp;quot;created_at&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;title&amp;quot;, &amp;quot;updated_at&amp;quot;) values ($1, $2, $3, $4) returning &amp;quot;id&amp;quot; - column &amp;quot;description&amp;quot; of relation &amp;quot;challenges&amp;quot; does not exist&amp;#x27;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Make sense the table don&amp;#x27;t have a column description. So we should add one&lt;/p&gt;&lt;p&gt;So open your migration file for the challenge_schema&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; metastring=&quot;{4}&quot;&gt;class ChallengeSchema extends Schema {
  up() {
    this.create(&amp;#x27;challenges&amp;#x27;, table =&amp;gt; {
      table.text(&amp;#x27;description&amp;#x27;)
      table.increments()
      table.timestamps()
    })
  }

  down() {
    this.drop(&amp;#x27;challenges&amp;#x27;)
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here I add a colum &lt;code&gt;text&lt;/code&gt; call description&lt;/p&gt;&lt;p&gt;Rerun the test&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&amp;#x27;error: insert into &amp;quot;challenges&amp;quot; (&amp;quot;created_at&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;title&amp;quot;, &amp;quot;updated_at&amp;quot;) values ($1, $2, $3, $4) returning &amp;quot;id&amp;quot; - column &amp;quot;title&amp;quot; of relation &amp;quot;challenges&amp;quot; does not exist&amp;#x27;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now is the same error but for title&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; metastring=&quot;{4}&quot;&gt;class ChallengeSchema extends Schema {
  up() {
    this.create(&amp;#x27;challenges&amp;#x27;, table =&amp;gt; {
      table.string(&amp;#x27;title&amp;#x27;)
      table.text(&amp;#x27;description&amp;#x27;)
      table.increments()
      table.timestamps()
    })
  }

  down() {
    this.drop(&amp;#x27;challenges&amp;#x27;)
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here title will be a string. Now rerun the test&lt;/p&gt;&lt;pre&gt;&lt;code&gt;  expected { Object (title, description, ...) } to contain subset { Object (title, description, ...) }
  {
  - created_at: &amp;quot;2019-01-02 12:28:37&amp;quot;
  - id: 1
  - updated_at: &amp;quot;2019-01-02 12:28:37&amp;quot;
  + user_id: 1
  }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The error mean the title and description are save, but the user_id don&amp;#x27;t exist, so we need to add the relation in the migration and the model&lt;/p&gt;&lt;p&gt;Again in the migration file add&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; metastring=&quot;{6-10}&quot;&gt;class ChallengeSchema extends Schema {
  up() {
    this.create(&amp;#x27;challenges&amp;#x27;, table =&amp;gt; {
      table.string(&amp;#x27;title&amp;#x27;)
      table.text(&amp;#x27;description&amp;#x27;)
      table
        .integer(&amp;#x27;user_id&amp;#x27;)
        .unsigned()
        .references(&amp;#x27;id&amp;#x27;)
        .inTable(&amp;#x27;users&amp;#x27;)
      table.increments()
      table.timestamps()
    })
  }

  down() {
    this.drop(&amp;#x27;challenges&amp;#x27;)
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here the user_id is a integer, reference the id of a user in the users table&lt;/p&gt;&lt;p&gt;Now open the Challenge model in &lt;code&gt;app/Models/Challenge.js&lt;/code&gt; and add this code&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;class Challenge extends Model {
  user() {
    return this.belongsTo(&amp;#x27;App/Models/User&amp;#x27;)
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And we need to do the other way of relation so open &lt;code&gt;app/Models/User.js&lt;/code&gt; and add at the bottom after tokens&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;challenges() {
  return this.hasMany(&amp;#x27;App/Models/Challenge&amp;#x27;)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Wow I love this syntax and how easy we can see the relations. Thank to Adonis team and Lucid ORM :)&lt;/p&gt;&lt;p&gt;Run the test&lt;/p&gt;&lt;pre&gt;&lt;code&gt; expected { Object (title, description, ...) } to contain subset { Object (title, description, ...) }
  {
  - created_at: &amp;quot;2019-01-02 12:35:20&amp;quot;
  - id: 1
  - updated_at: &amp;quot;2019-01-02 12:35:20&amp;quot;
  + user_id: 1
  }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Same error ? Yes when we create we didn&amp;#x27;t put the user_id. So we need to&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; metastring=&quot;{7}&quot;&gt;class ChallengeController {
  async store({ response, request, auth }) {
    const user = await auth.getUser()

    const challenge = await Challenge.create({
      ...request.only([&amp;#x27;title&amp;#x27;, &amp;#x27;description&amp;#x27;]),
      user_id: user.id,
    })

    return response.created(challenge)
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here I make use of auth, who is a object we method touching the authentication. Here I can use the current user with the function auth.getUser. This will return the user from the jwt. Now I can then merge this to the object when create.&lt;/p&gt;&lt;p&gt;Now if you run your test all should work. BUTTTTT this is not done. We need a test to make sure the user is really authenticate, cause now this endpoint is accessible by everyone.&lt;/p&gt;&lt;p&gt;Add to our test file&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;test(&amp;#x27;cannot create a challenge if not authenticated&amp;#x27;, async ({
  assert,
  client,
}) =&amp;gt; {})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Again we gonna work with the same idea, building the assertion first and going backward&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;test(&amp;#x27;cannot create a challenge if not authenticated&amp;#x27;, async ({
  assert,
  client,
}) =&amp;gt; {
  response.assertStatus(401)
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here we want the status to be 401 unauthorized&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;test(&amp;#x27;cannot create a challenge if not authenticated&amp;#x27;, async ({
  assert,
  client,
}) =&amp;gt; {
  const data = {
    title: &amp;#x27;Top 5 2018 Movies to watch&amp;#x27;,
    description: &amp;#x27;A list of 5 movies from 2018 to absolutely watched&amp;#x27;,
  }

  const response = await client
    .post(&amp;#x27;/api/challenges&amp;#x27;)
    .send(data)
    .end()

  console.log(&amp;#x27;error&amp;#x27;, response.error)

  response.assertStatus(401)
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;First make sure to delete the console.log from the other test. Now your test should look like that here.&lt;/p&gt;&lt;p&gt;Open your routes file&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;Route.post(&amp;#x27;/api/challenges&amp;#x27;, &amp;#x27;ChallengeController.store&amp;#x27;).middleware([&amp;#x27;auth&amp;#x27;])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you run the test all will be green :)&lt;/p&gt;&lt;p&gt;But now I will like to test the fact then title is required and both description and title need to be a string how can I do this ?&lt;/p&gt;&lt;p&gt;Adonis give us access to another really nice tool can validator.&lt;/p&gt;&lt;p&gt;We need to install the validator library&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;adonis install @adonisjs/validator
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Go to &lt;code&gt;start/app.js&lt;/code&gt; and add the provider&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; metastring=&quot;{7}&quot;&gt;const providers = [
  &amp;#x27;@adonisjs/framework/providers/AppProvider&amp;#x27;,
  &amp;#x27;@adonisjs/auth/providers/AuthProvider&amp;#x27;,
  &amp;#x27;@adonisjs/bodyparser/providers/BodyParserProvider&amp;#x27;,
  &amp;#x27;@adonisjs/cors/providers/CorsProvider&amp;#x27;,
  &amp;#x27;@adonisjs/lucid/providers/LucidProvider&amp;#x27;,
  &amp;#x27;@adonisjs/validator/providers/ValidatorProvider&amp;#x27;,
]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now go back to our test file for challenge and add a new one&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;test(&amp;#x27;cannot create a challenge if no title&amp;#x27;, async ({ assert }) =&amp;gt; {})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Before going further, I don&amp;#x27;t like the fact I need to manually wrote the title and description. I would like to be able to make the factory create it for us. This is possible, first go to &lt;code&gt;database/factory.js&lt;/code&gt;&lt;/p&gt;&lt;p&gt;We need to create a Factory for the Challenge&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;Factory.blueprint(&amp;#x27;App/Models/Challenge&amp;#x27;, faker =&amp;gt; {
  return {
    title: faker.sentence(),
    description: faker.sentence()
  }
});
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we can use this with the help of make&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const { title, description } = await Factory.model(
  &amp;#x27;App/Models/Challenge&amp;#x27;
).make()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will give us a fake title and description but without being save to the db.&lt;/p&gt;&lt;p&gt;Going back to the test will would like to receive error if the title is not in the body&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;test(&amp;#x27;cannot create a challenge if no title&amp;#x27;, async ({ assert, client }) =&amp;gt; {
  response.assertStatus(400)
  response.assertJSONSubset([
    {
      message: &amp;#x27;title is required&amp;#x27;,
      field: &amp;#x27;title&amp;#x27;,
      validation: &amp;#x27;required&amp;#x27;,
    },
  ])
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we need to write the code to get to this. I will skip some process, but hey continue it, this is how we get better. I will just not wrote it cause that take lot and lot of line :)&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;test(&amp;#x27;cannot create a challenge if no title&amp;#x27;, async ({ assert, client }) =&amp;gt; {
  const user = await Factory.model(&amp;#x27;App/Models/User&amp;#x27;).create()
  const { description } = await Factory.model(&amp;#x27;App/Models/Challenge&amp;#x27;).make()

  const data = {
    description,
  }

  const response = await client
    .post(&amp;#x27;/api/challenges&amp;#x27;)
    .loginVia(user, &amp;#x27;jwt&amp;#x27;)
    .send(data)
    .end()

  response.assertStatus(400)
  response.assertJSONSubset([
    {
      message: &amp;#x27;title is required&amp;#x27;,
      field: &amp;#x27;title&amp;#x27;,
      validation: &amp;#x27;required&amp;#x27;,
    },
  ])
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;First we create a user to be able to log, cause we need to be authenticated remember :)&lt;/p&gt;&lt;p&gt;Second I get a fake description from my factory. I just send this one.&lt;/p&gt;&lt;p&gt;I assert I receive a 400 for bad request and a json array of error message.&lt;/p&gt;&lt;p&gt;If I run the test now I receive&lt;/p&gt;&lt;pre&gt;&lt;code&gt;expected 201 to equal 400
  201 =&amp;gt; 400
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That mean the Challenge get create but shouldn&amp;#x27;t&lt;/p&gt;&lt;p&gt;So we need to add a validator for this&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;adonis make:validator CreateChallenge
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Go inside your routes file and we want to use this&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;Route.post(&amp;#x27;/api/challenges&amp;#x27;, &amp;#x27;ChallengeController.store&amp;#x27;)
  .validator(&amp;#x27;CreateChallenge&amp;#x27;)
  .middleware([&amp;#x27;auth&amp;#x27;])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now if you run the test you will see&lt;/p&gt;&lt;pre&gt;&lt;code&gt;expected 201 to equal 400
  201 =&amp;gt; 400
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Make sense the validator break stuff. Time to wrote some code. Open &lt;code&gt;app/Validators/CreateChallenge.js&lt;/code&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;class CreateChallenge {
  get rules() {
    return {
      title: &amp;#x27;required|string&amp;#x27;,
      description: &amp;#x27;string&amp;#x27;,
    }
  }

  get messages() {
    return {
      required: &amp;#x27;{{ field }} is required&amp;#x27;,
      string: &amp;#x27;{{ field }} is not a valid string&amp;#x27;,
    }
  }

  get validateAll() {
    return true
  }

  async fails(errorMessages) {
    return this.ctx.response.status(400).json(errorMessages)
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here I add some rules, messages, and I also show the fails with a status 400 for bad request. I also put the validateAll to make sure I validate all stuff, not just one by one.&lt;/p&gt;&lt;p&gt;If you run the test now all should work :)&lt;/p&gt;&lt;p&gt;We can also add the notNullable field to the title column in the migrations&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;table.string(&amp;#x27;title&amp;#x27;).notNullable()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A last test can be create to test both description and title need to be a string.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;test(&amp;#x27;cannot create a challenge if title and description are not a string&amp;#x27;, async ({
  assert,
  client,
}) =&amp;gt; {
  const user = await Factory.model(&amp;#x27;App/Models/User&amp;#x27;).create()

  const data = {
    title: 123,
    description: 123,
  }

  const response = await client
    .post(&amp;#x27;/api/challenges&amp;#x27;)
    .loginVia(user, &amp;#x27;jwt&amp;#x27;)
    .send(data)
    .end()

  response.assertStatus(400)
  response.assertJSONSubset([
    {
      message: &amp;#x27;title is not a valid string&amp;#x27;,
      field: &amp;#x27;title&amp;#x27;,
      validation: &amp;#x27;string&amp;#x27;,
    },
    {
      message: &amp;#x27;description is not a valid string&amp;#x27;,
      field: &amp;#x27;description&amp;#x27;,
      validation: &amp;#x27;string&amp;#x27;,
    },
  ])
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And if we run again the test BOOM all green.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://i.ibb.co/sygHVRs/Screenshot-2019-01-02-13-11-20.png&quot;/&gt;&lt;/p&gt;&lt;hr/&gt;&lt;h3&gt;End word&lt;/h3&gt;&lt;p&gt;I hope you enjoy the part 1 of this tutorial. Don&amp;#x27;t forget to subscribe to get notifications when I will post the part 2.&lt;/p&gt;&lt;p&gt;If you find any typo, or your want to let me know something about this project, don&amp;#x27;t hesitate to let a comment below :)&lt;/p&gt;&lt;p&gt;The code can be find here on &lt;a href=&quot;https://github.com/EQuimper/adonis-tdd-tutorial-demo&quot;&gt;github&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Setup CORS in Firebase Functions]]></title><description><![CDATA[How can I setup CORS in Google Cloud Functions. How can I remove the error 'Access-Control-Allow-Origin'. You get this issue about CORS and you don't know what to do ? I finally fix it on my side and I want to show you how I deal with it.]]></description><link>https://equimper.com/blog/setup-cors-in-firebase-functions</link><guid isPermaLink="false">https://equimper.com/blog/setup-cors-in-firebase-functions</guid><category><![CDATA[article]]></category><category><![CDATA[tutorial]]></category><category><![CDATA[nodejs]]></category><category><![CDATA[firebase]]></category><category><![CDATA[firebase functions]]></category><category><![CDATA[javascript]]></category><category><![CDATA[express]]></category><category><![CDATA[typescript]]></category><pubDate>Tue, 27 Nov 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In one of my last project, I was using &lt;a href=&quot;https://firebase.google.com/docs/functions/&quot;&gt;Firebase Functions&lt;/a&gt;. I did love to use them, but it’s quite hard to find some solution on this new stuff. One think I found pretty hard to get it work was the CORS of my project. When I use &lt;a href=&quot;https://expressjs.com/&quot;&gt;Express&lt;/a&gt; I can use the packages &lt;a href=&quot;https://github.com/expressjs/cors&quot;&gt;CORS&lt;/a&gt;, but here we don&amp;#x27;t have a server. Firebase Functions are just simple function. Yes, they can be use as HTTP endpoint etc, but they go sleep after being trigger and completed the job. The thing also is when I add this CORS package, I add it as middleware. Here if, I want to use a middleware I can but I will need to add express and wrap the full server with it.&lt;/p&gt;&lt;p&gt;Yes, that will have been so much easier I know. But I want to fix that without going to this path. So after searching on StackOverFlow a lot and try/error I finally figured out :).&lt;/p&gt;&lt;p&gt;First, we need to add this CORS package. Yes I know you can set it without it, but for this tutorial, I will show with
it. Also the example I will show make use of &lt;a href=&quot;https://www.typescriptlang.org/&quot;&gt;Typescript&lt;/a&gt;. You can use javascript without any problem also :)&lt;/p&gt;&lt;pre&gt;&lt;code&gt;yarn add cors
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After inside your &lt;code&gt;index.ts&lt;/code&gt; file or whatever file where you import your function just import CORS and initialize it.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import cors from &amp;#x27;cors&amp;#x27;

const corsHandler = cors({
  origin: [
    &amp;#x27;http://localhost:3000&amp;#x27;,
    // Staging URL
    // PROD URL
  ],
}****)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We will need to add this &lt;code&gt;corsHandler&lt;/code&gt; function to your functions.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;export const hello = functions.https.onRequest(
  (req: functions.Request, res: functions.Response) =&amp;gt; {
    // @ts-ignore
    // tslint:disable-next-line:no-empty
    corsHandler(req, res, async () =&amp;gt; {
      await // my logic

      res.status(200).json({ message: &amp;#x27;Yes cors work&amp;#x27; })
    })
  }
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As you can see I pass to my corsHandler the request and response object. This way I can setup the cors pretty easily. I know in some place we see&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;export const hello = functions.https.onRequest(
  async (req: functions.Request, res: functions.Response) =&amp;gt; {
    // @ts-ignore
    // tslint:disable-next-line:no-empty
    corsHandler(req, res, () =&amp;gt; {})

    await // my logic

    res.status(200).json({ message: &amp;#x27;Cors will work, but we will received an error of headers&amp;#x27; })
  }
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Like you can see, not a lot of difference. But yes we have one if I do this in the firebase logs I received. &lt;strong&gt;Error: Can&amp;#x27;t set headers after they are sent.&lt;/strong&gt;&lt;/p&gt;&lt;h2&gt;Alternative&lt;/h2&gt;&lt;p&gt;For sure with this way, this will get painful to add CORS everywhere. That&amp;#x27;s why you can then use express to make your life easier.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import express from &amp;#x27;express&amp;#x27;;
import cors from &amp;#x27;cors&amp;#x27;;

const app = express();

app.use(cors({
  origin: [
    &amp;#x27;http://localhost:3000&amp;#x27;,
    // Staging URL
    // PROD URL
  ],
})

app.post(&amp;#x27;/hello&amp;#x27;, async (req: functions.Request, res: functions.Response) =&amp;gt; {
  // logic here
}));

export const app = functions.https.onRequest(app);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Much simpler, YES sure. But now your endpoint will look like &lt;code&gt;&amp;lt;yourdomain&amp;gt;/app/...&lt;/code&gt;. You can maybe go with like a &lt;code&gt;v1&lt;/code&gt; as export so this will look like versioning but hey here it&amp;#x27;s your choice :)&lt;/p&gt;&lt;h2&gt;End word&lt;/h2&gt;&lt;p&gt;Hope this helps you fix this issue. For me, that takes a bit more time then on a regular server. But now it work :).&lt;/p&gt;</content:encoded></item><item><title><![CDATA[How to setup TailwindCSS in Phoenix 1.4]]></title><description><![CDATA[How to use TailwindCSS with Phoenix 1.4]]></description><link>https://equimper.com/blog/how-to-setup-tailwindcss-in-phoenix-1.4</link><guid isPermaLink="false">https://equimper.com/blog/how-to-setup-tailwindcss-in-phoenix-1.4</guid><category><![CDATA[elixir]]></category><category><![CDATA[css]]></category><category><![CDATA[article]]></category><category><![CDATA[phoenix]]></category><category><![CDATA[tailwindcss]]></category><category><![CDATA[tutorial]]></category><category><![CDATA[postcss]]></category><pubDate>Wed, 14 Nov 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I&amp;#x27;ve been using &lt;a href=&quot;https://tailwindcss.com&quot;&gt;Tailwind&lt;/a&gt; lately and really loved it. But one thing about this one is how to install it in a new project. My last personal project was with the brand new Phoenix 1.4 framework and I did want to use Tailwind for this one. So here just a &amp;quot;How to&amp;quot; guide about installing this one.&lt;/p&gt;&lt;p&gt;I did this article, cause I did search for this kind of one in the net and didn&amp;#x27;t found anything. So I hope that can help someone who tries it :)&lt;/p&gt;&lt;h2&gt;Step 1 - Setup the Project&lt;/h2&gt;&lt;p&gt;First, make sure you have the new version of Phoenix install on your machine. Just follow all the step on the docs &lt;a href=&quot;https://phoenixframework.org&quot;&gt;here&lt;/a&gt;. After we need to start a brand new project. We can do this by running the command&lt;/p&gt;&lt;pre&gt;&lt;code&gt;mix phx.new myproject
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Don&amp;#x27;t forget to say yes when they ask about installing the dependencies.&lt;/p&gt;&lt;h2&gt;Step 2 - Install Tailwind&lt;/h2&gt;&lt;pre&gt;&lt;code&gt;cd assets
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So now we are in the front-end side, we can then install tailwind as a npm dev packages&lt;/p&gt;&lt;pre&gt;&lt;code&gt;yarn add -D tailwindcss
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now Tailwind is installed and ready. But we need to initialize it to get the basic theme etc.&lt;/p&gt;&lt;p&gt;From the terminal run the command&lt;/p&gt;&lt;pre&gt;&lt;code&gt;./node_modules/.bin/tailwind init
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This command will create a &lt;code&gt;tailwind.js&lt;/code&gt; file who contains all the CSS of your project. Here I don&amp;#x27;t go in details about Tailwind you should read about it &lt;a href=&quot;https://tailwindcss.com/docs/what-is-tailwind&quot;&gt;here&lt;/a&gt;&lt;/p&gt;&lt;h2&gt;Step 3 - Setup Webpack etc...&lt;/h2&gt;&lt;p&gt;Now we need to setup webpack to make it work with Tailwind + Postcss&lt;/p&gt;&lt;pre&gt;&lt;code&gt;yarn add -D postcss-loader
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will add Postcss as dev dependencies and will be available for webpack.&lt;/p&gt;&lt;p&gt;Create a file in the assets folder call &lt;code&gt;postcss.config.js&lt;/code&gt; and add this code&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// assets/postcss.config.js

module.exports = {
  plugins: [require(&amp;#x27;tailwindcss&amp;#x27;)(&amp;#x27;./tailwind.js&amp;#x27;), require(&amp;#x27;autoprefixer&amp;#x27;)],
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will setup Tailwind with the file we have created when we run &lt;code&gt;./node_modules/.bin/tailwind init&lt;/code&gt;. Also here I just add the autoprefixer but not required.&lt;/p&gt;&lt;p&gt;After this open you &lt;code&gt;webpack.config.js&lt;/code&gt; file and add postcss-loader after the css-loader in the module object.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; metastring=&quot;{35}&quot;&gt;// assets/webpack.config.js

const path = require(&amp;#x27;path&amp;#x27;);
const glob = require(&amp;#x27;glob&amp;#x27;);
const MiniCssExtractPlugin = require(&amp;#x27;mini-css-extract-plugin&amp;#x27;);
const UglifyJsPlugin = require(&amp;#x27;uglifyjs-webpack-plugin&amp;#x27;);
const OptimizeCSSAssetsPlugin = require(&amp;#x27;optimize-css-assets-webpack-plugin&amp;#x27;);
const CopyWebpackPlugin = require(&amp;#x27;copy-webpack-plugin&amp;#x27;);

module.exports = (env, options) =&amp;gt; ({
  optimization: {
    minimizer: [
      new UglifyJsPlugin({ cache: true, parallel: true, sourceMap: false }),
      new OptimizeCSSAssetsPlugin({}),
    ],
  },
  entry: {
    &amp;#x27;./js/app.js&amp;#x27;: [&amp;#x27;./js/app.js&amp;#x27;].concat(glob.sync(&amp;#x27;./vendor/**/*.js&amp;#x27;)),
  },
  output: {
    filename: &amp;#x27;app.js&amp;#x27;,
    path: path.resolve(__dirname, &amp;#x27;../priv/static/js&amp;#x27;),
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: &amp;#x27;babel-loader&amp;#x27;,
        },
      },
      {
        test: /\.css$/,
          use: [MiniCssExtractPlugin.loader, &amp;#x27;css-loader&amp;#x27;, &amp;#x27;postcss-loader&amp;#x27;]
      },
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({ filename: &amp;#x27;../css/app.css&amp;#x27; }),
    new CopyWebpackPlugin([{ from: &amp;#x27;static/&amp;#x27;, to: &amp;#x27;../&amp;#x27; }]),
  ],
});

&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Open your &lt;code&gt;assets/css/app.css&lt;/code&gt; and override the code for this&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;/** assets/css/app.css */

/**
 * This injects Tailwind&amp;#x27;s base styles, which is a combination of
 * Normalize.css and some additional base styles.
 *
 * You can see the styles here:
 * https://github.com/tailwindcss/tailwindcss/blob/master/css/preflight.css
 *
 * If using `postcss-import`, use this import instead:
 *
 * @import &amp;quot;tailwindcss/preflight&amp;quot;;
 */
 @tailwind preflight;

 /**
  * This injects any component classes registered by plugins.
  *
  * If using `postcss-import`, use this import instead:
  *
  * @import &amp;quot;tailwindcss/components&amp;quot;;
  */
 @tailwind components;

 /**
  * Here you would add any of your custom component classes; stuff that you&amp;#x27;d
  * want loaded *before* the utilities so that the utilities could still
  * override them.
  *
  * Example:
  *
  * .btn { ... }
  * .form-input { ... }
  *
  * Or if using a preprocessor or `postcss-import`:
  *
  * @import &amp;quot;components/buttons&amp;quot;;
  * @import &amp;quot;components/forms&amp;quot;;
  */

 /**
  * This injects all of Tailwind&amp;#x27;s utility classes, generated based on your
  * config file.
  *
  * If using `postcss-import`, use this import instead:
  *
  * @import &amp;quot;tailwindcss/utilities&amp;quot;;
  */
 @tailwind utilities;

 /**
  * Here you would add any custom utilities you need that don&amp;#x27;t come out of the
  * box with Tailwind.
  *
  * Example :
  *
  * .bg-pattern-graph-paper { ... }
  * .skew-45 { ... }
  *
  * Or if using a preprocessor or `postcss-import`:
  *
  * @import &amp;quot;utilities/background-patterns&amp;quot;;
  * @import &amp;quot;utilities/skew-transforms&amp;quot;;
  */
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Step 4 - Time to code&lt;/h2&gt;&lt;p&gt;Now after you run &lt;code&gt;mix phx.server&lt;/code&gt; from the &lt;em&gt;ROOT&lt;/em&gt; directory of your project, you can then see the result inside your &lt;code&gt;priv/static/css/app.css&lt;/code&gt;. All the TailwindCSS will be there.&lt;/p&gt;&lt;h2&gt;End word&lt;/h2&gt;&lt;p&gt;I hope this article make your life a bit easier and now you are able to go and build your awesome project with Tailwind and Phoenix :)&lt;/p&gt;</content:encoded></item><item><title><![CDATA[How do I manage state with React?]]></title><description><![CDATA[How do I manage state in my react application? When to use Redux, MobX, Context API vs Component level state? What to do to handle forms state? How can I make my app state easier to maintain?]]></description><link>https://equimper.com/blog/how-do-i-manage-my-state-with-react</link><guid isPermaLink="false">https://equimper.com/blog/how-do-i-manage-my-state-with-react</guid><category><![CDATA[react]]></category><category><![CDATA[redux]]></category><category><![CDATA[formik]]></category><category><![CDATA[mobx-state-tree]]></category><category><![CDATA[mobx]]></category><category><![CDATA[context api]]></category><category><![CDATA[opinion]]></category><category><![CDATA[article]]></category><category><![CDATA[javascript]]></category><pubDate>Sun, 13 May 2018 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Intro&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;SML&lt;/strong&gt; -&amp;gt; State management library (e.g. Redux &amp;amp; MobX)&lt;/p&gt;&lt;p&gt;&lt;strong&gt;P.S.&lt;/strong&gt; This is just my opinion, this is not a best practice guide etc. It is just what I&amp;#x27;ve found to be the best for the apps I built recently.&lt;/p&gt;&lt;p&gt;When building an app with React or React Native I had lots of options. One of the most important option was how to manage state, where to store it, how to use it, and lastly, how to make it easy to maintain.&lt;/p&gt;&lt;p&gt;I believe these are common questions before starting most projects. React gives us freedom and liberty that other libraries and frameworks don&amp;#x27;t give you, but it comes with it&amp;#x27;s own costs. You need to make more decisions, code with fewer conventions, etc.&lt;/p&gt;&lt;p&gt;One question I always ask myself before creating/managing state is which components are involved with this state. If you believe many components will be involved, then the answer is more obvious than when only a few components are involved. A SML can help you in these cases. When the answer is a single component and it&amp;#x27;s children, it is probably better to keep it at the component level state.&lt;/p&gt;&lt;h3&gt;Form state&lt;/h3&gt;&lt;p&gt;So why not start with something I think the majority would agree. Don&amp;#x27;t put form state in Redux or any other lib, use component level state or tools like &lt;a href=&quot;https://github.com/jaredpalmer/formik&quot;&gt;formik&lt;/a&gt; or &lt;a href=&quot;https://github.com/final-form/react-final-form&quot;&gt;react-final-form&lt;/a&gt;. I believe many developers have used libraries like redux-form or something similar, but make sure to try these libs. Formik and React-Final-Form are going to change the way you think about forms state. They&amp;#x27;re gonna help you with the management of you forms state easier than before.&lt;/p&gt;&lt;p&gt;Personally I prefer Formik, I like to use it with &lt;a href=&quot;https://github.com/jquense/yup&quot;&gt;Yup&lt;/a&gt; for creating validation schema.&lt;/p&gt;&lt;p&gt;I want to get the result of the login form inside my SML. You may wonder how may I do this? I have seen this question quite often and the answer is inside the question. &lt;strong&gt;The Result&lt;/strong&gt;. Let Formik manage your form, handle the error(s) and submit. Then when you know all is good, store the result in your SML. Trust me, after building like 2-3 forms, you will not be able to live without Formik and Yup again.&lt;/p&gt;&lt;h3&gt;Animation state&lt;/h3&gt;&lt;p&gt;The state should be managed at the component level state. By doing it this way, you can reuse this component with animation in another project. Remember if you build a project today with Redux and you handle this state with it and you want to reuse it, you will also need to use Redux in this new project and all the related boilerplate code. By creating it at the component level state, it&amp;#x27;s almost as simple as copying &amp;amp; pasting one file to transfer a usable component to your new project - Or you can publish it as an NPM package! :)&lt;/p&gt;&lt;h3&gt;App State&lt;/h3&gt;&lt;p&gt;When you build a modern app you need to know a great deal about the current state of the app. Is the user online or offline? Is their location important? What is the part of the app that runs foreground or background in react-native, etc...&lt;/p&gt;&lt;p&gt;This is the kind of state I really like to manage with a SML. Why? Remember my question earlier about which components are involved? First, this is not even just component, some functions will need to know about this. For example, if offline you might store what the user tries to send and push it later to the server when he&amp;#x27;s back online. Then maybe you want to show a little toastr (or any other visual component) that says the app is in an offline mode.&lt;/p&gt;&lt;p&gt;In the the geolocation example, if you keep it as a &lt;em&gt;global&lt;/em&gt;, you are making sure that each component(s) who need this value will have the same exact value. So, if you build an app with a map + something else, both are gonna have the same source of truth.&lt;/p&gt;&lt;h3&gt;Modal, toastr, theme manager&lt;/h3&gt;&lt;p&gt;For this I once again go with a SML or now that it is released, the &lt;a href=&quot;https://medium.com/dailyjs/reacts-%EF%B8%8F-new-context-api-70c9fe01596b&quot;&gt;Context API&lt;/a&gt;. First, for a toastr and/or a modal, I think it is much simpler to keep just one instance of them. What do I mean by that? For instance, you declare one component who acts as the modal parent. This component handles if the modal is visible and if it is, which &lt;em&gt;type&lt;/em&gt; it represents (for example, if it&amp;#x27;s a welcome modal or a modal for a certain situation).&lt;/p&gt;&lt;p&gt;This one should connect with your SML. Why? Because the action to open the modal is surely gonna be used deeply in your app and you don&amp;#x27;t want to pass down this action 20 levels deep.&lt;/p&gt;&lt;p&gt;When dealing with a theme, I think you don&amp;#x27;t have many options. You can use the new Context API (which I think is awesome for this kind of stuff) or you can use your SML of choice.&lt;/p&gt;&lt;h3&gt;User state&lt;/h3&gt;&lt;p&gt;This one is surely one of the most common one. Keeping the current viewer state. Is the user logged in or not, his avatar URL etc. I think this one should be handled in your SML. More often than not, the navbar is going to need the avatar URL and also if the user is logged in to conditionally show some links. Also, when the user sees his profile, he can probably update it but if he&amp;#x27;s looking at someone else&amp;#x27;s profile, it may be just a plain view.&lt;/p&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;I hope this little article has helped you at some point. If your question is which SML I like the most, I think right now it is &lt;a href=&quot;https://github.com/mobxjs/mobx-state-tree&quot;&gt;mobx-state-tree&lt;/a&gt; which is like Redux meets MobX.&lt;/p&gt;&lt;p&gt;Hope you see why React state can be really useful and don&amp;#x27;t make the same mistake I made when starting by only using the SML state and never using component level state.&lt;/p&gt;&lt;p&gt;Let me know in the comments if you have any questions or if you find some typos :)&lt;/p&gt;</content:encoded></item><item><title><![CDATA[My Goals for 2018]]></title><description><![CDATA[What is my goals for 2018? Where my youtube channel go?]]></description><link>https://equimper.com/blog/my-goals-for-2018</link><guid isPermaLink="false">https://equimper.com/blog/my-goals-for-2018</guid><category><![CDATA[random]]></category><category><![CDATA[my life]]></category><category><![CDATA[youtube channel]]></category><pubDate>Fri, 12 Jan 2018 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Intro&lt;/h2&gt;&lt;p&gt;2018 !!! Finally new year, time to make a new plan and check what we did last year. Also, it&amp;#x27;s the time of the year where we can setup the plan for the incoming 12 months.&lt;/p&gt;&lt;h2&gt;2017&lt;/h2&gt;&lt;p&gt;So what was my plan last year?&lt;/p&gt;&lt;h4&gt;Get 500+ Subscribers on my youtube channel. [CHECK]&lt;/h4&gt;&lt;p&gt;Right now I have 2935 subscribers on my channel. This is awesome thank you, everyone, who follow me there. This is really awesome to see some people like the things I do. I hope what I shared as tips on my channel can really help you :)&lt;/p&gt;&lt;h4&gt;Post 25 videos at least on youtube. [CHECK]&lt;/h4&gt;&lt;p&gt;I posted 113 videos in 2017. Yes this challenge is done, but I&amp;#x27;m a bit disappointed with the fact then I didn&amp;#x27;t do all the tutorials I plan to. 2018 please be good with me here and help me to stay motivated.&lt;/p&gt;&lt;h4&gt;Create 2 apps for my startup idea. [NOPE]&lt;/h4&gt;&lt;p&gt;I did 0 apps idea for myself. All the apps I did was for the client.&lt;/p&gt;&lt;h4&gt;Get better as a Mentor and see student smile after graduating [CHECK]&lt;/h4&gt;&lt;p&gt;I get more patient, cause yes I need haha. Like me everyone who start in programming struggle on some point. Here has a mentor the thing is sometimes this stuff make so much sense for you then you don&amp;#x27;t understand why this person don&amp;#x27;t understand yet. Was really hard for me to go over this but this thing it&amp;#x27;s what I think to make a great mentor. But I need to get better in teaching and plan to do some little video like tips I found who can help a student. Get almost always the same question so why not recorded the answer? :)&lt;/p&gt;&lt;h4&gt;Get better and better on JavaScript [CHECK]&lt;/h4&gt;&lt;p&gt;I think I did here. Learn a lot about data structure and references this year.&lt;/p&gt;&lt;h4&gt;Learn Golang or Elixir a bit more. [CHECK]&lt;/h4&gt;&lt;p&gt;I did for both some little project and I&amp;#x27;m also working right now on a tutorial where I teach Elixir with Grahpql + Phoenix + React-Native where the plan is to build an Instagram Clone&lt;/p&gt;&lt;h4&gt;Wrote 30 posts on this blogs. [NOPE]&lt;/h4&gt;&lt;p&gt;NOPE, I didn&amp;#x27;t ...&lt;/p&gt;&lt;h4&gt;Create 3 tutorials and post it on Youtube and Udemy for free. [CHECK]&lt;/h4&gt;&lt;p&gt;I did on youtube, but Udemy I&amp;#x27;ve done zero&lt;/p&gt;&lt;h4&gt;Create 1 awesome library for the community. [NOPE]&lt;/h4&gt;&lt;p&gt;I made nothing really awesome :S&lt;/p&gt;&lt;h4&gt;Contribute on at least 3 open source project. [NOPE]&lt;/h4&gt;&lt;p&gt;Didn&amp;#x27;t have the motivation to continue to work after my 10hours code straight almost every day.&lt;/p&gt;&lt;h4&gt;Get better in English [CHECK]&lt;/h4&gt;&lt;p&gt;I think I get better here, but still, need to improve it.&lt;/p&gt;&lt;h4&gt;Start to learn Spanish [NOPE]&lt;/h4&gt;&lt;p&gt;Didn&amp;#x27;t event started haha&lt;/p&gt;&lt;h4&gt;Read 10 books about business [NOPE]&lt;/h4&gt;&lt;p&gt;Just read one here.&lt;/p&gt;&lt;h4&gt;Read 20 books about programming [NOPE]&lt;/h4&gt;&lt;p&gt;Read 6 here, and I don&amp;#x27;t think 20 books is ok in a year haha&lt;/p&gt;&lt;h4&gt;Get 1500 points on StackOverflow (652 currently) [NOPE]&lt;/h4&gt;&lt;p&gt;Right now I&amp;#x27;m with 1058 points :( almost.&lt;/p&gt;&lt;h2&gt;2018&lt;/h2&gt;&lt;p&gt;So this year, which kind of year I want 2018 to be? Good question! I think this year gonna be a way for me to start moving a bit faster on some topic and starting to get better at what I have already started. What do I mean? First thing, my project I build right now started to be a bit faster, no need anymore to do all the research I did last year to get this feature done example. So I can focus more on coding and build awesome product faster. And faster what I mean by that is making more product. What took me before 40hours to make now I can do this in 30hours or less. So that gonna let me finish product earlier and go on the next one faster etc. By doing this I&amp;#x27;m gonna see more scenario and business logic. At the end of this, I&amp;#x27;m gonna just have more experience.&lt;/p&gt;&lt;p&gt;Also, I need to focus on getting better at what I already do and not spread myself too much. I think this year Javascript, Golang, and some Elixir gonna be the only language I&amp;#x27;m gonna touch.&lt;/p&gt;&lt;p&gt;2018 also gonna be the year of learning Blockchain&amp;#x27;s technologies. Learning how to work with them and building dapps. I know this gonna be big in the future and I want to have an edge here :)&lt;/p&gt;&lt;p&gt;For my youtube channel, I want to start to be a bit more professional. Not doing cut in a video it&amp;#x27;s a bad idea, I need to start cutting part who make my viewer losing time. Where I say &amp;quot;eeeeeeee&amp;quot; for like 5 sec haha. Also, I need to take time to talk good in English. Showing more picture of what we gonna do. Explain more before we start a feature. Going deeper into some stuff another tutorial doesn&amp;#x27;t show.&lt;/p&gt;&lt;h2&gt;My goals for 2018&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;Get good with Golang&lt;/li&gt;&lt;li&gt;Get 5000 subscribers on youtube&lt;/li&gt;&lt;li&gt;Post 5 tutorials on youtube&lt;/li&gt;&lt;li&gt;Get 3000 points on StackOverflow&lt;/li&gt;&lt;li&gt;Read 10 books in programming&lt;/li&gt;&lt;li&gt;Improve my English&lt;/li&gt;&lt;li&gt;Improve my health by doing exercise a bit more&lt;/li&gt;&lt;li&gt;Improve my teaching&amp;#x27;s skill&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Good year everyone :)&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Make iterm more powerful]]></title><description><![CDATA[Iterm his already awesome but with this quick tips can be more. How can you make iterm listen to native mac command ?]]></description><link>https://equimper.com/blog/make-iterm-more-powerful</link><guid isPermaLink="false">https://equimper.com/blog/make-iterm-more-powerful</guid><category><![CDATA[random]]></category><category><![CDATA[tips]]></category><category><![CDATA[command line]]></category><pubDate>Thu, 22 Jun 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I love &lt;a href=&quot;https://iterm2.com/&quot;&gt;Iterm&lt;/a&gt; and I would like to share with you some of the tips I found with this awesome tools.&lt;/p&gt;&lt;h2&gt;Make him look pretty&lt;/h2&gt;&lt;p&gt;Everyone loved to work with the awesome, fast and powerful tool. But we also want them to look pretty and by customizable. Iterm can be all of them. First thing at the first installation the theme is already pretty good. But if you want to change this theme just take a look at this &lt;a href=&quot;http://iterm2colorschemes.com/&quot;&gt;website&lt;/a&gt;. He has a lot of scheme and some of them are really beautiful. Also in your profile settings &lt;code&gt;⌘ + ,&lt;/code&gt; you can change the fonts of him. If you don&amp;#x27;t like the standard font you can just change it here. &lt;img src=&quot;https://image.ibb.co/nFyA05/uhjhcr38qq5efbw_preserve_transparency_False_size_1024x1024_size_mode_2.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;Just click on change font. For me has you can see I use &lt;a href=&quot;https://github.com/i-tu/Hasklig&quot;&gt;Hasklig&lt;/a&gt;.&lt;/p&gt;&lt;h2&gt;Make it feel more native&lt;/h2&gt;&lt;p&gt;Has a Mac user, we love the shortcut of Mac when it comes to delete a single word, delete a full line, go to the beginning of a line etc. But if you have played with iterm you know them they don&amp;#x27;t work. &lt;strong&gt;BUT&lt;/strong&gt; They can ;)&lt;/p&gt;&lt;p&gt;Go in your profile &lt;code&gt;⌘ + ,&lt;/code&gt; and click on keys&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://image.ibb.co/m95OL5/v0meg9nqfruwhj5_preserve_transparency_False_size_1024x1024_size_mode_2.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;After that in the right where we see Key mappings, we can add these command.&lt;/p&gt;&lt;hr/&gt;&lt;h3&gt;For delete a single word with &lt;code&gt;⌥ + ⌫&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Action: Send Hex Code 0x17&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;For delete a full line with &lt;code&gt;⌘ + ⌫&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Action: Send Hex Code 0x15&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;For go to the beginning of a line with &lt;code&gt;⌘ + ←&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Action: Send Hex Code 0x01&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;For go to the end of a line with &lt;code&gt;⌘ + →&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Action: Send Hex Code 0x05&lt;/li&gt;&lt;/ul&gt;&lt;hr/&gt;&lt;h2&gt;Some tips&lt;/h2&gt;&lt;p&gt;For opening a new tab like always in Mac you can just &lt;code&gt;⌘ + t&lt;/code&gt;. After that, if you want to travel between them you can &lt;code&gt;⌘ + number of the panel&lt;/code&gt;. Example &lt;code&gt;⌘ + 2&lt;/code&gt; send me to the second panel.&lt;/p&gt;&lt;p&gt;Also if you want to split screen just hit &lt;code&gt;⌘ + d&lt;/code&gt; that gonna split to the right. If you want to change between split you can here&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://image.ibb.co/m95OL5/v0meg9nqfruwhj5_preserve_transparency_False_size_1024x1024_size_mode_2.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;Add the same command as me. So now I just need to &lt;code&gt;⌥ + number of the split&lt;/code&gt;.&lt;/p&gt;&lt;h2&gt;Open him with a good size&lt;/h2&gt;&lt;p&gt;For me, I like Iterm to be with a standard size when I open it. For the change, it just goes in profile again but on the window now. If you want the same size as me.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Column: 120&lt;/li&gt;&lt;li&gt;Rows: 41&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://image.ibb.co/kOCjA5/wchcxskommveugq_preserve_transparency_False_size_1024x1024_size_mode_2.png&quot;/&gt;&lt;/p&gt;&lt;h2&gt;If you want to open with the split or new tab same directory&lt;/h2&gt;&lt;p&gt;When I code I always finish by open lot of tabs with him. I hate when I need to cd in my directory again. So for that Iterm make it easy for us. You can check on Iterm to make him open in the same directory really easy.&lt;/p&gt;&lt;p&gt;In profile again with the tab general open just check in the working directory section like that&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://image.ibb.co/nRanV5/3676wras0icr8mq_preserve_transparency_False_size_1024x1024_size_mode_2.png&quot;/&gt;&lt;/p&gt;&lt;h2&gt;Finish&lt;/h2&gt;&lt;p&gt;Hope you have like this little post and find it helpful :)&lt;/p&gt;</content:encoded></item><item><title><![CDATA[What I found by building my own NodeJS boilerplate.]]></title><description><![CDATA[By building your own boilerplate or at least play with code for fun you can found some new stuff and use it for your next project.]]></description><link>https://equimper.com/blog/what-i-found-by-building-my-own-nodejs-boilerplate</link><guid isPermaLink="false">https://equimper.com/blog/what-i-found-by-building-my-own-nodejs-boilerplate</guid><category><![CDATA[nodejs]]></category><category><![CDATA[javascript]]></category><category><![CDATA[mongodb]]></category><category><![CDATA[express]]></category><category><![CDATA[tips]]></category><category><![CDATA[npm packages]]></category><pubDate>Wed, 03 May 2017 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Mongoose Tips&lt;/h1&gt;&lt;p&gt;I’ve played with Mongoose a lot in the past week. I’ve built a &lt;a href=&quot;https://github.com/EQuimper/nodejs-api-boilerplate&quot;&gt;NodeJS API boilerplate&lt;/a&gt; for help me kickstart some REST API project. I setup the regular auth using PassportJS with the local and JWT strategies. By doing this I found some useful tricks with Mongoose. Some tips I never really see somewhere ‘maybe I didn’t search lot 😃’ and I want to share you what I found.&lt;/p&gt;&lt;h2&gt;toJSON()&lt;/h2&gt;&lt;p&gt;Example, you want to make authentication with your app and you don’t want to send the password to the front-end. It’s normal cause this is a big security issue if you did. So want you can do it’s create a function who take your user and return a new object.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;function getUser(user) {
  return {
    _id: user._id,
    username: user.username,
  };
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This strategy work but I think the one I’m gonna show gonna be better.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;UserSchema.methods = {
  /**
   * Authenticate the user
   *
   * @public
   * @param {String} password - provided by the user
   * @returns {Boolean} isMatch - password match
   */
  authenticateUser(password) {
    return compareSync(password, this.password);
  },
  /**
   * Hash the user password
   *
   * @private
   * @param {String} password - user password choose
   * @returns {String} password - hash password
   */
  _hashPassword(password) {
    return hashSync(password);
  },

  /**
   * Generate a jwt token for authentication
   *
   * @public
   * @returns {String} token - JWT token
   */
  createToken() {
    return jwt.sign(
      {
        _id: this._id,
      },
      constants.JWT_SECRET,
    );
  },

  /**
   * Parse the user object in data we wanted to send when is auth
   *
   * @public
   * @returns {Object} User - ready for auth
   */
  toAuthJSON() {
    return {
      _id: this._id,
      token: `JWT ${this.createToken()}`,
    };
  },

  /**
   * Parse the user object in data we wanted to send
   *
   * @public
   * @returns {Object} User - ready for populate
   */
  toJSON() {
    return {
      _id: this._id,
      username: this.username,
    };
  },
};
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So here we have a lot of stuff to check 😃. Methods in mongoose are finally what they said. They are methods available on your user object. An example here we have &lt;code&gt;js±authenticateUser(password)&lt;/code&gt; who is use for authenticate the user find with email if the password is the right one. Same go for the &lt;code&gt;js±_hashPassword(password)&lt;/code&gt; who just simply hash the password before saving the user in the DB. &lt;code&gt;js±createToken()&lt;/code&gt; like the name say create the JWT token and can be user right inside the response&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;res.status(200).json({ user, token: user.createToken() })
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But the one I want you to see it&amp;#x27;s the &lt;code&gt;js±toJSON()&lt;/code&gt;. This on is use when finally you on your user. So if you check back&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;res.status(200).json({ user, token: user.createToken() })
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;you can see I send the user. Because we have the &lt;code&gt;js±toJSON()&lt;/code&gt; on make it working just like this. We don&amp;#x27;t send timestamps, email, password etc. We just send &lt;code&gt;js±_id&lt;/code&gt; and &lt;code&gt;js±username&lt;/code&gt; nothing more. But ok why do the &lt;code&gt;js±toAuthJSON()&lt;/code&gt;? Because now I can reformat the response to be&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;res.status(200).send(user.toAuthJSON())
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;so I just send an Object with &lt;code&gt;_id&lt;/code&gt; and &lt;code&gt;token&lt;/code&gt;. Hope this part make sense 😃.&lt;/p&gt;&lt;p&gt;The reason why have to methods for JSON below 😃.&lt;/p&gt;&lt;h2&gt;Statics&lt;/h2&gt;&lt;p&gt;After that in Mongoose, you have access to something call Statics in your schema. This is the same thing like in class. Statics are method who can be used without initiate this one. So you can use it right with the model himself.&lt;/p&gt;&lt;p&gt;Example&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;PostSchema.statics = {
  /**
   * Create a post
   *
   * @public
   * @param {Object} args - Object contains title and text
   * @param {String} authorId - the author id
   * @returns {Post} Post Object - new post create
   */
  createPost(args, authorId) {
    return this.create({
      ...args,
      author: authorId,
    });
  },

  list({ skip = 0, limit = 10 }) {
    return this.find()
      .sort({ createdAt: -1 })
      .skip(skip)
      .limit(limit)
      .populate(&amp;#x27;author&amp;#x27;);
  },
};
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here I have 2 statics methods to my post. This method finally is just for abstract some of your code. For me, that make my life a bit easier and make the controller cleaner. The &lt;code&gt;js±createPost(args, authorId)&lt;/code&gt; it&amp;#x27;s for just clean up a bit the code. I can use it by doing&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;Post.createPost({ title: &amp;#x27;Hello&amp;#x27; }, &amp;#x27;123&amp;#x27;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I just remove some code and make it a bit easier when it came to maybe change DB. I can keep the same controller but just change my &lt;code&gt;js±Post&lt;/code&gt; services.&lt;/p&gt;&lt;p&gt;After this one we have&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;list({ skip = 0, limit = 10 })
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This one it&amp;#x27;s just for make kind of pagination easier. You can see I use the ES6 feature &lt;a href=&quot;https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Default_parameters&quot;&gt;Default Parameters&lt;/a&gt; who let me add default parameters if these values are &lt;code&gt;js±undefined&lt;/code&gt;. Again I can use it like that&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;Post.list({ skip: 5, limit: 20 });
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is again for me just sugars and makes my code easier to follow.&lt;/p&gt;&lt;h2&gt;Again toJSON() 😃&lt;/h2&gt;&lt;p&gt;In the last example in the list we have &lt;code&gt;js±.populate(&amp;#x27;author&amp;#x27;);&lt;/code&gt;. Because of the &lt;code&gt;js±toJSON()&lt;/code&gt; by default the user gonna have only &lt;code&gt;js±_id&lt;/code&gt; and &lt;code&gt;js±username&lt;/code&gt; no need to add select value etc :). That&amp;#x27;s why I have &lt;code&gt;js±toAuthJSON()&lt;/code&gt; who is called on login and &lt;code&gt;js±toJSON()&lt;/code&gt; for this kind of thing.&lt;/p&gt;&lt;h2&gt;Packages&lt;/h2&gt;&lt;p&gt;Some packages I didn&amp;#x27;t know in the NodeJS ecosystem and need to be used 😄.&lt;/p&gt;&lt;h3&gt;&lt;a href=&quot;https://github.com/hapijs/joi&quot;&gt;Joi&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;I really like this one for help me make validation in my controller. So easy to use too.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;export const validation = {
  create: {
    body: {
      title: Joi.string().min(3).required(),
      text: Joi.string().required(),
    },
  },
  update: {
    body: {
      title: Joi.string().min(3),
      text: Joi.string(),
    },
  },
};
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After this, in your routes file, you do with the help of &lt;a href=&quot;https://github.com/AndrewKeig/express-validation&quot;&gt;express-validation&lt;/a&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;routes.post(
  &amp;#x27;/&amp;#x27;,
  authJwt,
  validate(PostController.validation.create),
  PostController.create,
);
routes.patch(
  &amp;#x27;/:id&amp;#x27;,
  authJwt,
  validate(PostController.validation.update),
  PostController.updatePost,
);
&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;&lt;a href=&quot;https://github.com/helmetjs/helmet&quot;&gt;Helmet&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Helmet&amp;#x27;s a library who help you secure your Express app. Easy to install just need to add it as a middleware &lt;code&gt;js±app.use(helmet())&lt;/code&gt;. This is for getting the standard. You can check on their GitHub to see another way.&lt;/p&gt;&lt;h3&gt;&lt;a href=&quot;https://github.com/expressjs/cors&quot;&gt;Cors&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Cors&amp;#x27;s a middleware who enable for you the Cross-Origin request. Can be added for getting everything working just by doing &lt;code&gt;js±app.use(cors())&lt;/code&gt; but it&amp;#x27;s a good thing to whitelist your front-end only etc. Take again a look at the docs before use it.&lt;/p&gt;&lt;h3&gt;&lt;a href=&quot;https://github.com/adaltas/node-http-status&quot;&gt;Http-Status&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Http-Status just make your life easier to add status to your endpoint.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;export async function getList(req, res, next) {
  try {
    return res
      .status(HTTPStatus.OK)
      .json(await Post.list({ skip: req.query.skip, limit: req.query.limit }));
  } catch (err) {
    err.status = HTTPStatus.BAD_REQUEST;
    return next(err);
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Other useful packages&lt;/h2&gt;&lt;h3&gt;&lt;a href=&quot;https://github.com/prettier/prettier&quot;&gt;Prettier&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Prettier help you to reformat your code and make it look better in no time. I start to use it about 1 month ago and now use it on every project I do. Easy to install this packages gonna save you time and gonna make your code look much better. PS if you use it with eslint and have a lot of red error maybe add &lt;code&gt;eslint-config-prettier&lt;/code&gt; to your project and add it to your extends in &lt;code&gt;.eslintrc&lt;/code&gt;. This gonna remove eslint issue with syntax looking and prettier gonna manage it.&lt;/p&gt;&lt;p&gt;Example&lt;/p&gt;&lt;pre&gt;&lt;code&gt;{
  &amp;quot;extends&amp;quot;: [
    &amp;quot;equimper&amp;quot;,
    &amp;quot;prettier&amp;quot;
  ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;&lt;a href=&quot;https://github.com/okonet/lint-staged&quot;&gt;Lint-Staged&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Lint-Staged gonna run your linter on your commit. Why have it ? Because maybe you use eslint and prettier and forgot all time to run the scripts. So your code looks bad etc. By adding this tools your commit gonna be linting before that let your commit. Can be really useful for a project with a lot of people.&lt;/p&gt;&lt;p&gt;For adding it I just add this in my &lt;code&gt;packages.json&lt;/code&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;pre-commit&amp;quot;: &amp;quot;lint-staged&amp;quot;,
  &amp;quot;lint-staged&amp;quot;: {
    &amp;quot;*.js&amp;quot;: [
      &amp;quot;eslint&amp;quot;,
      &amp;quot;yarn prettier&amp;quot;,
      &amp;quot;git add&amp;quot;
    ]
  },
  &amp;quot;scripts&amp;quot;: {
    &amp;quot;lint&amp;quot;: &amp;quot;eslint src --color&amp;quot;,
    &amp;quot;prettier&amp;quot;: &amp;quot;node ./scripts/prettier.js write&amp;quot;,
    &amp;quot;lint-staged&amp;quot;: &amp;quot;lint-staged&amp;quot;,
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;End word&lt;/h2&gt;&lt;p&gt;Hope this little article was a little gold mine of packages and tips for you. That was a really good experience working on this simple boilerplate. Plz take a look at it and let me know what you think of it.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/EQuimper/nodejs-api-boilerplate&quot;&gt;NodeJS-API-Boilerplate&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Why I moved away from Atom to Visual Studio Code and my Setup]]></title><description><![CDATA[Why did I quit Atom? What Visual Studio Code have more than Atom?.]]></description><link>https://equimper.com/blog/why-i-moved-away-from-atom-to-visual-studio-code-and-my-setup</link><guid isPermaLink="false">https://equimper.com/blog/why-i-moved-away-from-atom-to-visual-studio-code-and-my-setup</guid><category><![CDATA[text editor]]></category><category><![CDATA[javascript]]></category><category><![CDATA[web]]></category><pubDate>Sat, 25 Feb 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;code&gt;youtube:baJyGTJr9so&lt;/code&gt;&lt;/p&gt;&lt;p&gt;VSC: Visual Studio Code&lt;/p&gt;&lt;h2&gt;Why I moved away from Atom&lt;/h2&gt;&lt;p&gt;I was an Atom user for nearly a year. Everything about this text editor was perfect for me. For starters, the packages manager was much more beginner friendly than Sublime. Also, there were always new updates which seemed to make my text editor more and more powerful with each update. But 4 months ago I started to feel the pain of the slow speed of Atom. This nearly broke my heart as I had put so much time and effort customizing the perfect setup for my needs. I built custom packages, created color syntax for different languages and even made my own code snippets.&lt;/p&gt;&lt;h2&gt;So VS Code?&lt;/h2&gt;&lt;p&gt;Yes, I choose &lt;a href=&quot;http://code.visualstudio.com&quot;&gt;VS Code&lt;/a&gt; and yes I wasn&amp;#x27;t sold the first time I saw it. I don&amp;#x27;t like Microsoft products, but this one had something I really liked.&lt;/p&gt;&lt;h3&gt;Fast&lt;/h3&gt;&lt;p&gt;Open VSC took me less than 10 seconds.&lt;/p&gt;&lt;h3&gt;CPU&lt;/h3&gt;&lt;p&gt;VSC took almost no CPU! I got some weird stuff with code helper in the activity monitor of my MAC but I quickly resolved the issue by tweakng the settings(I’ll show these magic settings at the end of this post).&lt;/p&gt;&lt;h3&gt;Intelisense&lt;/h3&gt;&lt;p&gt;The Atom JavaScript autocomplete was really great but when I switched to VSC I never missed it. The fact than you can mouse over a function and see what it does or &lt;code&gt;cmd + click&lt;/code&gt; on a file path and go right to the file is awesome! You can do the same thing in Atom. I know. But it’s just not as smooth as VSC.&lt;/p&gt;&lt;h3&gt;Packages&lt;/h3&gt;&lt;p&gt;Like Atom, VSC has a lot of packages. The VSC community put a lot of effort into making your experience with this text editor better everyday. I miss some of Atom packages but at the same time, I have some new favorites for VSC.&lt;/p&gt;&lt;h2&gt;My Top Packages&lt;/h2&gt;&lt;p&gt;&lt;em&gt;Here you can click on the packages name. This is a link :)&lt;/em&gt;&lt;/p&gt;&lt;h3&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=christian-kohler.path-intellisense&quot;&gt;Path Intelisense&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;This helps you get the relative path of your file and help you to autocomplete path names when you do something like…&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import MyComponent from &amp;#x27;./src/components/MyComponent&amp;#x27;;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Plus, this works with dependencies from your &lt;code&gt;packages.json&lt;/code&gt;.&lt;/p&gt;&lt;h3&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=alefragnani.project-manager&quot;&gt;Project Manager&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;This extension helps my life so much. When you have a lot of projects and don&amp;#x27;t want to waste time finding each one on your computer, you can just save them right inside the window. Just press &lt;code&gt;shift + cmd + p&lt;/code&gt; and&lt;/p&gt;&lt;pre&gt;&lt;code&gt;Project Manager: Save Project
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Afterwards, you can just come back to your text editor and search right in the project manager by typing &lt;code&gt;shift + cmd + p&lt;/code&gt; and&lt;/p&gt;&lt;pre&gt;&lt;code&gt;Project Manager: List Projects to Open
&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-rename-tag&quot;&gt;Auto Rename Tag&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;This one doesn&amp;#x27;t do much. But what it does do is a huge help! For example, you’re working on a React project and you want to change your component &lt;code&gt;MyApp&lt;/code&gt; to be &lt;code&gt;YourApp&lt;/code&gt;. This extension will rename rename every ‘MyApp’ to ‘YourApp’ at the same time.&lt;/p&gt;&lt;h3&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=xabikos.JavaScriptSnippets&quot;&gt;JavaScript (ES6) code snippets&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Some es6 snippets you help you write code faster.&lt;/p&gt;&lt;h3&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=IBM.output-colorizer&quot;&gt;Output Colorizer&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Add color to the internal terminal. Did I mention there is a built in terminal in VSC?!?&lt;/p&gt;&lt;h3&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=dzannotti.vscode-babel-coloring&quot;&gt;Babel ES6/ES7&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;You need this if you work with React.&lt;/p&gt;&lt;h3&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=naumovs.color-highlight&quot;&gt;Color Highlight&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;This will highlight your color variables inside CSS and JS. So, when you type something like &lt;code&gt;#fff&lt;/code&gt; you’ll see a white colored highlight on it.&lt;/p&gt;&lt;h3&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig&quot;&gt;EditorConfig&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;If you follow me on &lt;a href=&quot;https://www.youtube.com/channel/UC7R7bcH9-KEBDiGNP1mZnmw&quot;&gt;Youtube&lt;/a&gt; you have surely seen how much I like this little tool. It makes your code more consistent for multiple users. What do I mean by this? It allows you to not worry so much about your Text Editor settings and will add some handy settings like &lt;code&gt;indentation&lt;/code&gt; or &lt;code&gt;trim whitespace&lt;/code&gt;. This is useful for teams because it can be painful to see some 4 space indents on one page and 2 space indents on another. This works on almost every code editor too, so if your friends don&amp;#x27;t use want to use your new favorite text editor, it will work for them too.&lt;/p&gt;&lt;h3&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=nepaul.editorconfiggenerator&quot;&gt;EditorConfig Generator&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;This will generate a &lt;code&gt;.editorConfig&lt;/code&gt; file for you with some nice editor settings.&lt;/p&gt;&lt;h3&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint&quot;&gt;Eslint&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Again, this is a tool I use on every project. This tool will help you to make your code better and let you know about errors before your code runs. For example, eslint will show you when you miss a semicolon or when you declare a variable but you never use it. But these errors depend on your eslint config.&lt;/p&gt;&lt;p&gt;PS I have created my own. You can install it from npm &lt;code&gt;npm i -D eslint-config-equimper&lt;/code&gt;. This one is an extension of the Airbnb linter.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.npmjs.com/package/eslint-config-equimper&quot;&gt;Link to mine&lt;/a&gt;&lt;/p&gt;&lt;h3&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=gcazaciuc.vscode-flow-ide&quot;&gt;Flow Ide&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;If you are like me and you like Flow you need this tool. Less laggy than the nuclide one in Atom plus it&amp;#x27;s the better solution for VSC I’ve found.&lt;/p&gt;&lt;h3&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=spywhere.guides&quot;&gt;Guides&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Add some indent guide lines to your code. Much easier on the eyes.&lt;/p&gt;&lt;h3&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=oderwat.indent-rainbow&quot;&gt;Indent-Rainbow&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Again, an extension to make your eyes happy when looking through lots of indented code.&lt;/p&gt;&lt;h3&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=wmaurer.vscode-jumpy&quot;&gt;Jumpy&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;This is an awesome extension, but I don&amp;#x27;t really use it. But for the those who don’t like using their mouse, this is something you need. It will help you navigate your file really quickly without using your mouse.&lt;/p&gt;&lt;h3&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=2gua.rainbow-brackets&quot;&gt;Rainbow Bracket&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Another one that’s easy on the eyes.&lt;/p&gt;&lt;h3&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=vsmobile.vscode-react-native&quot;&gt;React Native Tools&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;React-Native user? This tool it&amp;#x27;s for you.&lt;/p&gt;&lt;h3&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=WakaTime.vscode-wakatime&quot;&gt;Wakatime&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;This plugin will track your time spent in your text editor each week. It&amp;#x27;s like a Fitbit for a programmer. It will tell you which project you spend the most time on, which language you use the most and can even keep track of goals you set during the week.&lt;/p&gt;&lt;h2&gt;My Editor&lt;/h2&gt;&lt;p&gt;&lt;img src=&quot;https://image.ibb.co/fu8uQk/RmEXgyy.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;My color schema is &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=azemoh.one-monokai&quot;&gt;One Monokai&lt;/a&gt;. For icons I use &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=PKief.material-icon-theme&quot;&gt;Material Icon Theme&lt;/a&gt;&lt;/p&gt;&lt;h2&gt;My settings&lt;/h2&gt;&lt;p&gt;&lt;a href=&quot;https://gist.github.com/EQuimper/e619cdcd555798ea2f06aa009ec7fa8d&quot;&gt;You can add some of my settings to your.&lt;/a&gt;&lt;/p&gt;&lt;hr/&gt;&lt;h2&gt;My Snippets Packages&lt;/h2&gt;&lt;p&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=EQuimper.react-native-react-redux#review-details&quot;&gt;Link&lt;/a&gt;&lt;/p&gt;&lt;hr/&gt;&lt;h2&gt;Hidden Gem&lt;/h2&gt;&lt;p&gt;One of my friends have started his own youtube channel where he talk about programming in general. Take a look at &lt;a href=&quot;https://www.youtube.com/channel/UCxdr1zRpfUfZw_5GqrpvXGg&quot;&gt;his channel&lt;/a&gt;&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;If you want to learn React-Native with NodeJS for your server side, I&amp;#x27;m building a tutorial on youtube.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/playlist?list=PLzQWIQOqeUSNX_ZDqt9L3TMSwFa9GbIwp&quot;&gt;Build a Meetups App With React-Native and Node.JS&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Testing your API with Postman]]></title><description><![CDATA[This tutorial will show you how to used Postman and his testing tools.]]></description><link>https://equimper.com/blog/testing-your-api-with-postman</link><guid isPermaLink="false">https://equimper.com/blog/testing-your-api-with-postman</guid><category><![CDATA[tutorial]]></category><category><![CDATA[article]]></category><category><![CDATA[javascript]]></category><pubDate>Sat, 28 Jan 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I&amp;#x27;m sure you already know the famous tool call &lt;a href=&quot;https://www.getpostman.com&quot;&gt;Postman&lt;/a&gt;. This is a super useful tool for test your API and looks at the response you get from your server. But I see a lot of people just using it as a manual tester. This is not wrong but you can get much better productivity with if you use some of Postman features.&lt;/p&gt;&lt;h2&gt;Create your first Simple Test&lt;/h2&gt;&lt;p&gt;First thing this is a simple controller in your app where you can fetch a unique post with is ID as params.&lt;/p&gt;&lt;p&gt;&lt;code&gt;/posts/controller.js&lt;/code&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import Post from &amp;#x27;./model&amp;#x27;;
/**
* GET BY ID
*/
export const fetchPostById = async (req, res) =&amp;gt; {
  try {
    res.status(200).json({ post: await Post.findById(req.params.id) });
  } catch (e) {
    res.status(e.status).json({ error: true, message: e.message });
  }
};
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;/posts/routes.js&lt;/code&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import { Router } from &amp;#x27;express&amp;#x27;;
import * as PostController from &amp;#x27;./controller&amp;#x27;;

const routes = new Router();

routes.route(&amp;#x27;/posts/:id&amp;#x27;).get(PostController.fetchPostById);

export default routes;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now time to open Postman. In your left, you gonna see &lt;img src=&quot;https://image.ibb.co/fV0DJ5/sB0MxDA.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;a little folder with a plus sign. If you click there you can now create a collection. &lt;img src=&quot;https://image.ibb.co/e6yYJ5/fH7iOrk.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;Give a little name for your collection. For me, I&amp;#x27;m using &lt;code&gt;Postman-Tuto&lt;/code&gt;. With that collection, we make our life much easier to test route already create.&lt;/p&gt;&lt;p&gt;Add the route and the &lt;code&gt;GET&lt;/code&gt; method in the main area. For me, I add&lt;/p&gt;&lt;pre&gt;&lt;code&gt;http://localhost:3000/api/v1/posts/588ce463f4741431c918a04b
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt; cause I have already created a fake post.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://image.ibb.co/cGdB5k/8IjnuIJ.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;Now when I click send I receive this.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://image.ibb.co/cjOB5k/bTBgJYa.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;Perfect the route is working and the controller + model do their job.&lt;/p&gt;&lt;h2&gt;Write your first Postman test&lt;/h2&gt;&lt;p&gt;If you click on Test right below the URL container you gonna see this&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://image.ibb.co/d7dNBQ/yl3ocAW.png&quot;/&gt;.&lt;/p&gt;&lt;p&gt;Now time to write some test. First thing in the right you can see a select menu with test already create by Postman. We can select one already&lt;/p&gt;&lt;pre&gt;&lt;code&gt;Status code: Code is 200
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://image.ibb.co/gVMaWQ/ykMf8Mb.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;If you click send now we can see the test pass &lt;code&gt;1/1&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://image.ibb.co/ngbLy5/Yft8e5Y.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;Now add the&lt;/p&gt;&lt;pre&gt;&lt;code&gt;Response body: JSON value check
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;again in your right snippets.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;var jsonData = JSON.parse(responseBody);
tests[&amp;quot;Post should have title of Title 1&amp;quot;] = jsonData.post.title === &amp;quot;Title 1&amp;quot;;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Add this line and now click send.&lt;/p&gt;&lt;p&gt;This is the result.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://image.ibb.co/m7eJkk/q90y932.png&quot;/&gt;&lt;/p&gt;&lt;h2&gt;Add more test&lt;/h2&gt;&lt;p&gt;Now an example of a complete test for this routes.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;tests[&amp;quot;GET By Id Posts - Status code is 200&amp;quot;] = responseCode.code === 200;

var jsonData = JSON.parse(responseBody);

tests[&amp;quot;Post should have title of Title 1&amp;quot;] = jsonData.post.title === &amp;quot;Title 1&amp;quot;;

tests[&amp;quot;Post should have id of 588ce463f4741431c918a04b&amp;quot;] = jsonData.post._id === &amp;quot;588ce463f4741431c918a04b&amp;quot;;

tests[&amp;quot;Should have no error&amp;quot;] = jsonData.error === false;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://image.ibb.co/iKJ5WQ/aNgcIXm.png&quot;/&gt;&lt;/p&gt;&lt;h2&gt;Time to save and add new one&lt;/h2&gt;&lt;p&gt;Now in the top left, you can see a big Save button. Click on the arrow and &lt;code&gt;save as&lt;/code&gt;. Give a name to this route.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://image.ibb.co/eUNokk/rZfw6fP.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;you need to add it to your collection.&lt;/p&gt;&lt;h2&gt;The runner&lt;/h2&gt;&lt;p&gt;In the top left you can see the button Runner if you click it Postman open a new window. Select your collection in the dropdown.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://image.ibb.co/h5EerQ/wZRSxWz.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;If you click Start Run you can get this.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://image.ibb.co/dY2Ay5/p2luDGi.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;As you can see I add some new test for show how awesome this tool can be. You can also import your test run and give that to another dev in your team.&lt;/p&gt;&lt;p&gt;Last thing you can also export all your route if you click it in your collection. After the other dev just need to import it and he gets all your route. Now I start to export it in my postman folder inside my server so I can import it if I delete mine on my GUI.&lt;/p&gt;&lt;p&gt;Hope you like this little tutorial and you learn something new today :).&lt;/p&gt;&lt;p&gt;P.S You still need to run some test in your controller etc but with the Runner of Postman + the test etc that give you just much more confirmation.&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;Ressources&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://www.getpostman.com/docs&quot;&gt;Docs of Postman&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[My goals for 2017]]></title><description><![CDATA[What is my goals for 2017? What I want to do in my career?]]></description><link>https://equimper.com/blog/my-goals-for-2017</link><guid isPermaLink="false">https://equimper.com/blog/my-goals-for-2017</guid><category><![CDATA[random]]></category><category><![CDATA[my life]]></category><category><![CDATA[youtube channel]]></category><pubDate>Fri, 06 Jan 2017 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Intro&lt;/h2&gt;&lt;p&gt;2016 was a big year for me. First thing, I start coding the 6 January 2016 so today is my first full year finish. Coming from an Army background this was one of the biggest moves of my life. I&amp;#x27;ve always done a physical job and this one we all know is really more technical. I found by coding every day in the year &amp;quot;Yes 365days last year I have touched my PC and coded&amp;quot; that I love that more and more.&lt;/p&gt;&lt;p&gt;When I started that was really hard to be sure this is more than a passion. I was really not that good and everything was too much for me. I things the facts I&amp;#x27;m french and everything is English didn&amp;#x27;t help me either. So after 1 big month of using Html and CSS I jump on the Ruby On Rails part. I follow a lot of tutorial on the internet where I make a clone of some app like Pinterest, Twitter, Airbnb etc.&lt;/p&gt;&lt;p&gt;In April 2016 I know at this time I want to do a career. So I join a BootCamp call &lt;a href=&quot;https://www.thinkful.com&quot;&gt;Thinkful&lt;/a&gt;. That&amp;#x27;s was one my best moved so far. I meet one of the best programmer and more than that he was my mentor. His name is &lt;a href=&quot;https://github.com/shiftyp&quot;&gt;Ryan Lynch&lt;/a&gt;. This guy makes me understand the hard concept and make everything look easier. He pushes me on the Redux world and now I use that everywhere. Thank you, Ryan!&lt;/p&gt;&lt;p&gt;When I finish the boot camp I was struggling finding job. But I continue to work on my experience and continue to build stuff. At this time the only project has built was this little &lt;a href=&quot;http://equimper.github.io/streamingAppRedux/&quot;&gt;app&lt;/a&gt;. That&amp;#x27;s wasn&amp;#x27;t enough so I continue to build and put the commitment into my learning. With the help of the Thinkful team, I found my first as a freelance developer where I have built a full-stack application using React, Redux, React-Native, Meteor, Node etc.&lt;/p&gt;&lt;p&gt;In end November, I get a job at Thinkful where I help people with the React-Redux part of the course. I really like that, I learn much more by teaching. I liked helping people and this is a place where I&amp;#x27;m happy to help the student understand react and redux much more. I know where we struggle and that&amp;#x27;s why I think that give me a good idea how I can help them.&lt;/p&gt;&lt;p&gt;In December, I start to challenge myself a bit more. The first thing I created a &lt;a href=&quot;https://www.youtube.com/channel/UC7R7bcH9-KEBDiGNP1mZnmw&quot;&gt;youtube channel&lt;/a&gt;. This thing was something I have to think for a long time but with my bad English + my experience I wasn&amp;#x27;t sure that was a good idea. But finally I really liked it and this is something I want to put energy this year. The second thing I start to restream myself on &lt;a href=&quot;https://www.livecoding.tv/equimper/&quot;&gt;livecoding.tv&lt;/a&gt;. I start to stream almost the first day of my journey of learning code. Now I grow up a good audience and I think that push myself a bit more than doing nothing.&lt;/p&gt;&lt;p&gt;One thing too I&amp;#x27;m proud for this year was my commitment on &lt;a href=&quot;https://github.com/EQuimper&quot;&gt;github&lt;/a&gt;. I contribute on some of the open source project.&lt;/p&gt;&lt;p&gt;One of my best choice this year was to challenge myself doing 12 apps in 12 weeks. Right now I have finished the first 3 apps.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;http://www.shneed.com/&quot;&gt;ShortNeed&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://givemethatidea.com/&quot;&gt;GiveMeThatIdea&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Hy5r_gXRPaw&amp;amp;t=3s&quot;&gt;React-Native Twitch&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;That challenge myself so much, I learn stuff with this challenge so quickly and now that pushed me some time on a place I never been.&lt;/p&gt;&lt;h2&gt;My goals for 2017&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;Get 500+ Subscribers on my youtube channel.&lt;/li&gt;&lt;li&gt;Post 25 videos at least on youtube.&lt;/li&gt;&lt;li&gt;Create 2 apps for my startup idea.&lt;/li&gt;&lt;li&gt;Get better as a Mentor and see student smile after graduating.&lt;/li&gt;&lt;li&gt;Get better and better on JavaScript.&lt;/li&gt;&lt;li&gt;Learn Golang or Elixir a bit more.&lt;/li&gt;&lt;li&gt;Wrote 30 posts on this blogs.&lt;/li&gt;&lt;li&gt;Create 3 tutorials and post it on Youtube and Udemy for free.&lt;/li&gt;&lt;li&gt;Create 1 awesome library for the community.&lt;/li&gt;&lt;li&gt;Contribute on at leat 3 open source project.&lt;/li&gt;&lt;li&gt;Get better in English&lt;/li&gt;&lt;li&gt;Start to learn Spanish&lt;/li&gt;&lt;li&gt;Read 10 books about business&lt;/li&gt;&lt;li&gt;Read 20 books about programming&lt;/li&gt;&lt;li&gt;Get 1500 points on StackOverflow (652 currently)&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;End word&lt;/h2&gt;&lt;p&gt;So I hope you have big goals this year too. Don&amp;#x27;t hesitate to write a little hello in the chat and let me know what is your goal this year too.&lt;/p&gt;</content:encoded></item></channel></rss>