David Berri's Blog https://dberri.com/feed Software development tips đŸ‘šđŸ»â€đŸ’» Sat, 24 Sep 2022 13:12:37 GMT https://validator.w3.org/feed/docs/rss2.html https://github.com/nuxt-community/feed-module en <![CDATA[How to look for a branch in git]]> https://dberri.com/how-to-look-for-a-branch-in-git https://dberri.com/how-to-look-for-a-branch-in-git Fri, 31 Jan 2020 22:09:00 GMT Your coworker created a new feature and asked you to review it. How to look for a branch that someone else created and pushed to the remote repository using Git? It's as simple as running the command:

git fetch origin

(Assuming that the remote repository is called "origin")
Then, you can checkout the branch the the other person was working on with:

git checkout new-feature

(Assuming the name of the new branch Ă© “new-feature” - it's going to show up once you run the first command).

If you need to list all the branches that were pulled from the remote repository, you can use git branch.

]]>
<![CDATA[How to use git cherry-pick]]> https://dberri.com/how-to-use https://dberri.com/how-to-use Fri, 14 Feb 2020 22:26:00 GMT This command is extremely useful when you need only one or few commits from one branch in another branch, but don't want or cannot merge.

Let'' say that in your application you use the branch master to deploy to production and develop new code in another branch, say dev. You implement a few features, but realize you need one of them needs to be merged to master soon and cannot wait for you to finish whatever you were developing in the dev branch.

You can use the following git commands:

# Find and copy the commit hash that you want to send to another branch
git log

# change to the branch where this commit is needed
git checkout master

# execute the cherry pick using the hash you copied earlier
git cherry-pick bbb70c579ce1382af60eebacde95c2aef6676abf

If there are any conflicts, resolve them and commit the new code. Done.

]]>
<![CDATA[Smarter Vue Watchers]]> https://dberri.com/smarter-vue-watchers https://dberri.com/smarter-vue-watchers Sat, 08 Feb 2020 22:41:00 GMT In some Vue projects, you might need to load data from an API as soon as the component is instantiated and load new data once a value or property of the component is changed. For example, when you use a search input field. I've done that several times, and always used the following pattern:

// Inside a Vue component
created() {
  this.search()
},
watch: {
  searchInput() {
    this.search()
  }
}

And that's ok, it works well. But then I found a simpler, more elegant way to do the same thing:

// Inside a Vue component
watch: {
  searchInput: {
    handler: 'search',
    immediate: true
  }
}

This code can replace the previous one entirely. That works because a watcher can receive an object, instead of a function, and this object contains a handler, which is the method to be executed when the watcher is notified, and the property immediate, which ensures that this method is also executed as soon as the component is in the lifecycle hook created.

This tip was extracted from a video of a talk by Chris Fritz, one of the members of Vue.js' core team. Here's the video:

7 Secret Patterns Vue Consultants Don’t Want You to Know - Chris Fritz
There’s an astounding amount of power packed away in Vue, despite its small size. The official guide provides a gentle learning path and the API is thorough,...
]]>
<![CDATA[How to sort an array by date in JavaScript]]> https://dberri.com/how-to-order-an-array-by-date https://dberri.com/how-to-order-an-array-by-date Sun, 09 Feb 2020 22:42:00 GMT We can find this problem in our daily lives working with JavaScript, and of course we can use libraries that abstract this away for us. Nevertheless, it can be interesting to understand how to implement this feature and not rely on third party packages that might bring more complexity to your project.

Let's say you have an array of dates in a string format (e.g. 'yyyy-mm-dd') and you would like to sort it. With JavaScript, a good approach is to transform these dates in Date objects, and then use the Array method sort:

function fromStringToDate(date) {
 	// transforms string in array, splitting at the “-“
	const arrDate = date.split(“-“)
	const day = arrDate[2] ;
	// JavaScript represents the months starting at “0”
 	// but that's content for another post :)
 	const month = arrDate[1] - 1;
 	const year = arrDate[0];
    
    return new Date(year, month, day);
}

function compareDates(date1, date2) {
	if (date1 > date2) {
        return -1;
    } else if (date1 < date2) {
        return 1;
    } else {
        return 0;
    }
    // This code could be simplified to a one-liner:
    // return (date1 > date2) ? -1 : ((date1 < date2) ? 1 : 0)
}

const dates = [
	“2020-02-01”,
	“2020-01-05”,
	“2020-03-20”
];

dates
	.map(fromStringToDate)
	.sort(compareDates)

// [
//   Fri Mar 20 2020 00:00:00 GMT-0300 (-03),
//   Sat Feb 01 2020 00:00:00 GMT-0300 (-03),
//   Sun Jan 05 2020 00:00:00 GMT-0300 (-03)
// ]

If you want to invert the order, you just need to change the operator < to > and vice-versa.

]]>
<![CDATA[How to watch nested object properties in Vue]]> https://dberri.com/como-observar-propriedades-de-objetos-no-vue https://dberri.com/como-observar-propriedades-de-objetos-no-vue Fri, 21 Feb 2020 13:02:00 GMT When it's necessary to react to a change of state in a more generic way, we can use Vue's watchers. They work quite well for most data structures, but it can cause some confusion when you're watching arrays or objects with nested properties. For example:

export default {
	data() {
    	return {
        	price: 100.0
        }
    },
    watch: {
    	price: function (newPreco, oldPrice) {
        	// whenever the car price changes, this function will be executed
        }
    }
}

In this case, since price is a simple number, everytime it changes somewhere in the component, the function price inside the watch block will be executed. Now, let's say the price we want to keep watching is inside an object, like in the following example:

export default {
	data() {
    	return {
        	car: {
                color: 'black',
        		price: 100.0
            }
        }
    },
    watch: {
    	car: function (newCar, oldCar) {
	        // whenever the price changes, this function will be executed
            // or will it?
        }
    }
}

Now, even change the name of the watcher to car, if the car price changes, the function won't be executed. Well, in this case Vue has a "trick up its sleeve". You can define the watcher as an object that receives a handler function and a property called deep which will watch for changes in the nested properties of the object, like this:

export default {
	data() {
    	return {
        	car: {
                color: 'black',
        		price: 100.0
            }
        }
    },
    watch: {
    	car: {
        	handler: function (newCar, oldCar) {
                // whenever the car price changes, this function will be executed
            },
            deep: true
        }
    }
}

Now, every time the car price changes, the watcher function will run.

We solved a problem, but introduced another: if any other property in the car object changes, for instance the color, the watcher will execute that function.

For a long time I thought there wasn'' much to do regarding this. I would usually check if the newCar price was  different than oldCar price and execute whatever I needed. But thanks to a tweet, I found out there was a much much simpler way to do this:

Michael Thiessen on Twitter
â€œđŸ”„ You can watch nested values directly in @vuejs by using dot notation as a string. This avoids watching an object deeply and ignoring everything but one specific value. It also communicates your intent better because you don’t *actually* care about the whole object.”

Yes, we can simplify the previous code like this:

export default {
	data() {
    	return {
        	car: {
                color: 'black',
        		price: 100.0
            }
        }
    },
    watch: {
    	'car.price': function (newPrice, oldPrice) {
        	// now, only when the car price changes, it will execute the function
        }
    }
}

And besides, it's clear which property you want to watch in the car object.

]]>
<![CDATA[For Loops in JavaScript]]> https://dberri.com/for-loops-in-javascript https://dberri.com/for-loops-in-javascript Fri, 20 Mar 2020 16:37:00 GMT JavaScript has at least three distinct ways of defining "for" loops:

for: Runs a block of code a number of times;
for/in: Iterates over properties of a given object;
for/of: Iterates over the values of iterable objects;

For

This loop repeats the execution of your block of code until a specified condition becomes false.

Let's check the syntax of this simpler loop:

for (statement 1; statement 2; statement 3) {
  // block of code to be executed
}

Statement 1 is executed only once before your block of code runs. Usually we define the loop's initial condition, but this is an optional parameter and can be defined before the loop statement if needed.

Statement 2 defines the condition for the execution of the code block. Here you end up defining how many times the code block will run. This parameter is also optional, though if omitted, it's necessary to add a break inside your code block, otherwise the loop will never finish and the browser will crash.

Statement 3 is executed once for each execution after your code block runs. As you might have guessed by now, this parameter is also optional.

const languages = [‘javascript’, ‘python’, ‘php’];

for (let i = 0; i < languages.length; i++) { 
  console.log(`${i}: ${languages[i]}`)
}

// expected output:
// “0: javascript”
// “1: python”
// “2: php”

For/in

This loop iterates over an object's properties (keys).

const js = { name: ”JavaScript”, author: ”Brendan Eich”, year: 1995 };

for (const prop in js) {
  console.log(`${prop}: ${js[prop]}`);
}

// expected output:
// “name: JavaScript”
// “author: BrendanEich”
// “year: 1995”

The same could be done using a simple "for" loop using Object.keys, which extracts the properties of an object to an array:

const js = { name: ”JavaScript”, author: ”Brendan Eich”, year: 1995 };
const properties = Object.keys(js);

for (i = 0; i < properties.length; i++) { 
  const prop = properties[i]
  console.log(`${i} ${prop}: ${js[prop]}`);
}

// expected output:
// “0 name: JavaScript”
// “1 author: Brendan Eich”
// “2 year: 1995”

For/of

This runs the loop over the values of iterable objects. A few examples of iterable objects in JS are Arrays, Strings, Maps, Sets and NodeLists. The syntax is as follows:

for (*variable* of *iterable object*) {
  // code block to be executed
}

Here's an example like the previous:

const languages = [{ name: ”JavaScript” }, { name: ”Python” }, { name: ”PHP” }];

for (const lang of languages) {
  console.log(lang);
}

// expected output:
// { name: ”JavaScript” }
// { name: ”Python” }
// { name: ”PHP” }

Both for/in and for/of are very useful, each being used in their own way can make your code more legible, in my opinion. Hopefully this tip has been useful for you :)

]]>
<![CDATA[Const, Let and Var]]> https://dberri.com/const-let-and-var https://dberri.com/const-let-and-var Fri, 28 Feb 2020 16:48:00 GMT I like to imagine variables like they were drawers with labels. They are used to store data. There are three ways of declaring a variable in JavaScript: var, let or const.

Scope

The scope is the portion of code where the variable is visible. In JavaScript, every function has a scope.

var

Until ES2015 spec, this was the only way of declaring a variable in JavaScript.

var cat = ‘meaw’

var allows one to “redeclare” the same variable infinite time, always overwriting the previews declaration:

var cat = ‘meaw’
console.log(cat) // meaw

var cat = ‘oof oof’
console.log(gato) // oof oof

let

let works almost the same way as var, but it uses the local scope, not global. That means that if the variable is declared using let inside a function, for example, it will not be available outside that function. The same goes for blocks like if, for, while, etc...

function bark() {
   let dog = ‘oof oof’
   console.log(dog)
}

latir() // oof oof

console.log(dog) // ReferenceError: Can't find variable: dog

const

const uses the same scope rules as let, though it does not allow for redeclaration.

const x = 10
x = 11 // TypeError: Attempted to assign to readonly property.

It is possible to declare an array or object with const and later assign or reassign values that they store:

const obj = { a: 1 }
obj.a = 2
console.log(obj) // { a: 2 }

const arr = [1]
arr.push(2)
console.log(arr) // [1, 2]

Using let and const and avoiding var can help you code less bugs related to scope. If you use any linter like eslint, it's posible that it already points things like this to you.

]]>
<![CDATA[Local Storage]]> https://dberri.com/local-storage-2 https://dberri.com/local-storage-2 Sat, 11 Apr 2020 23:32:51 GMT With more logic and data manipulation brought to the frontend, some data storage problems start to arise. Among them, storing data betwen page reloads or sessions. This is a very common problem in SPAs (Single Page Applications), where you may have several data manipulations happening in between page reloads or would have to keep downloading the same data over and over from the server. There are cases where it's possible to minimize the user's wait time displaying info that is stored right in the browser using LocalStorage.

LocalStorage is a type of web storage that allows JavaScript applications to access data stored in the browser with no expiration date.

This functionality is available in the window object and you can access it like this:

const myStorage = window.localStorage
// or
const myStorage = localStorage

This will return a Storage object. This object has the property length that returns an integer representing the quantity of items stored in the object and it also has the following methods:

  • setItem
  • getItem
  • key
  • removeItem
  • clear

setItem

It accepts the parameters key and value that will be stored (or updated if that particular key already has some data associated):

myStorage.setItem(“name”, “David”)

In this case, "name" is the key and "David" is the value.

Important: If you want to store arrays or objects - something that will probably be more common in an application - first you will have to transform them into strings, using, for instance, JSON's stringify method:
const myBrowser = {
  name: “Chrome”,
  openTabs: 3,
  consumedMemory: 512e9
}

myStorage.setItem(“browser”, JSON.stringify(myBrowser))

getItem

You pass the key to this method and it returns what you stored with that key, or null if it does not find anything associated.

myStorage.getItem(“name”)

// expected output
// “David”

If you stored an object or array like in the previous example, you will notice that getItem returns a string representation of the object, so you should use JSON's parse method to turn it into a "real" object again:

const myBrowser = myStorage.setItem(“browser”)
console.log(myBrowser)

// expected ouput
//  “{\”name\":\"Chrome\",\"openTabs\":3,\"consumedMemory\":512000000000}"

console.log(JSON.parse(myBrowser))

// expected output
// {
//    name: "Chrome",
//    openTabs: 3,
//    consumedMemory: 512000000000
// }

key

This method accepts an integer as a parameter and with that, it returns a key if it is stored in that position or null if there's nothing there. It works more or less like accessing positions in an array. In our examples, we had stored two items in LocalStorage: name and browser:

const position0 = myStorage.key(0)
const position1 = myStorage.key(1)
const position2 = myStorage.key(2)

console.log(`${position0}, ${position1}, ${position2}`)

// expected output
// name, browser, null

This method is useful if you need to iterate over the keys inside a loop, for instance.

removeItem

You pass a key to this method and it removes the associated value:

myStorage.removeItem(“name”)

Now,  getItem(“name”), will return null and key(0) becomes: “browser”.

clear

Last but not least, we have the method clear which completely clears the application's LocalStorage, removing all of its keys.

myStorage.clear()
console.log(myStorage.length)

// expected output
// 0

Limitations

It's important to note that:

  • You should not store sensitive information or user data in LocalStorage
  • It is not a replacement for traditional databases, since data is only available in the browser
  • It has a 5mb limit in most browsers

With this introduction to LocalStorage, you will surely be able to create more powerful applications. I hope this has inspired you to use it in your apps and if you want an example to start, take a look here in my GitHub. It's a very simple task manager written in Vue.js and uses LocalStorage to persist data.

]]>
<![CDATA[Cleaning up merged git branches]]> https://dberri.com/cleaning-up-git-branches https://dberri.com/cleaning-up-git-branches Mon, 04 May 2020 19:10:47 GMT If you use any git workflow such as git flow, you end up with several branches like feature, release and hotfix that become stale as they are merged with other branches.

So, when you need to look for a specific branch using the git branch command, you could waste time skimming through a big list of branch names.

One way to handle that is to use git branch --merged, which lists only the branches that have already been merged, and then copy the name of each one and delete them with git branch -d branch-name. That works fine if you do that every time you merge a branch, but if you're like me, you'll quickly forget to do this, and once you realize it, you'll have several branches on the list again.

Now, to remove all merged branches at once, we can use the following command:

git branch --merged | egrep -v "(^\*|master|develop)" | xargs git branch -d

This will remove all branches that have been merged with exception of master and develop. You can even create an alias to in your shell environment to not have to type or copy that every time you need it.

Careful with the -d flag. If you change it to  -D (capital case), you might end up removing unmerged branches and losing hours of work
]]>
<![CDATA[How to create a Rest API with Laravel]]> https://dberri.com/how-to-create-a-rest-api-with-laravel https://dberri.com/how-to-create-a-rest-api-with-laravel Sat, 16 May 2020 18:02:27 GMT Laravel makes it quick to get up and running with Rest APIs that you can use to feed data to mobile apps, javascript applications or other applications. In this post, I'll show you how easy it is to do it.

To make it simple, let's create an API that only delivers content about books and their authors. We're not going to add "create" and "update" functionality for now.

Setup

We can start by creating a new Laravel application. In your terminal execute the command: laravel new books-api. If you don't have Laravel installed globally, you can use Composer:

composer create-project --prefer-dist laravel/laravel books-api
Keep in mind that by the time of this article, I'm using Laravel version 7.10.3

That will create a new folder books-api, you can go inside and edit the .env file. We need to setup the database access for the application:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=<YOUR-DB-NAME>
DB_USERNAME=<YOUR-DB-USER>
DB_PASSWORD=<YOUR-DB-USER-PASSWORD>

To make sure it connects correctly, you can run php artisan migrate. The application already ships with database migrations for the User model. If no errors popped up, you're good to go.

Models, Migrations and Controllers

We will need at least a model for books and one for authors, so let's create them using Artisan's command: php artisan make:model Author -mcr.

This command should create three files:

  • app/Author.php : That's our model
  • app/Http/Controllers/AuthorController.php : A resource controller (created with the help of the cr flag)
  • and database/migrations/XXXX_create_authors_table.php: That's the database migration created with the help of the m flag in the command.

Let's start with the migration. Go to the newly created file and add the following code:

public function up()
{
    Schema::create('authors', function (Blueprint $table) {
        $table->id();
        $table->string('name'); // we add this line here
        $table->timestamps();
    });
}

Whatever fields you add here will be added to the authors table in the database. To learn what are the available methods, check out Laravel's documentaton.

Now let's do the same for books: php artisan make:model Book -mcr.

Then go to database/migrations/XXXXX_create_books_table.php and add the following fields inside the up function:

public function up()
{
    Schema::create('books', function (Blueprint $table) {
        $table->id();
        $table->foreignId('author_id');
        $table->string('title');
        $table->decimal('price', 6, 2)->nullable();
        $table->timestamps();

        $table->foreign('author_id')
            ->references('id')
            ->on('authors')
            ->onDelete('cascade');
    });
}

Here we are also adding a reference to the author who wrote the book using a foreign key. After you add any other fields you want, you run the migrations with: php artisan migrate. If you got no errors in the console, good job! Now let's keep going.

We also need to create a relationship between authors and books in the models:

app/Author:

class Author extends Model
{
    public function books()
    {
        return $this->hasMany('App\Book');
    }
}

app/Book:

class Book extends Model
{
    public function author()
    {
        return $this->belongsTo('App\Author');
    }
}

With these, we can call the relationships as properties from each model:

$book = Book::first(); // Book instance
$book->author; // Author instance

$author = Author::first(); // Author instance
$author->books; // Collection of Books

If you call them using the "method" form, it will return you a QueryBuilder instance, and you can use to chain other methods, like:

$author = Author::first(); // Author instance
$author->books()
	->where('published', true)
    ->get(); // Collection of Books

Factories and Seeders

Now that we have the database setup, we need some data to test the API. In the real world, either you will already have the data, or maybe you can create it manually. I like to using factories and seeders, because it's less work and it's useful for automated testing. Let's create a factory for authors and for books:

php artisan make:factory AuthorFactory -m Author
Factory created successfully.

php artisan make:factory BookFactory -m Book
Factory created successfully.

Now if you go to the database/factories folder, you will see both files created.

In AuthorFactory, let's use the faker library to create random Author data:

$factory->define(Author::class, function (Faker $faker) {
    return [
        'name' => $faker->name,
    ];
});

And we do the same for books, with the catch that it will receive the author_id as a parameter:

$factory->define(Book::class, function (Faker $faker, $author_id) {
    return [
        'author_id' => $author_id,
        'title' => $faker->sentence,
        'price' => $faker->randomFloat(2, 5, 100)
    ];
});

Now, we create a seeder for Authors:

php artisan make:seeder AuthorTableSeeder
Seeder created successfully.

In that seeder (which is in database/seeders/AuthorTableSeeder) we create 5 authors and 5 books for each author using the followinf code:

public function run()
    {
        factory(App\Author::class, 5)->create()
            ->each(function ($author) {
                factory(App\Book::class, 5)->create([
                    'author_id' => $author->id
                ]);
            });
    }

It calls the factory for the Author model and for each one created, it creates 5 books using basically the same syntax. Now, to finish it up, we call this seeder in the DatabaseSeeder class:

public function run()
    {
        $this->call(AuthorTableSeeder::class);
    }

With all migrations, factories and seeders in place, we run php artisan migrate --seed. You should see a list of all the migrations and seeders run.

Routes

We need routes to access the data, so we can go to routes/api.php and add them there. Routes added to that file will already have a /api prepended to the route, so keep that in mind. I want to see a list of authors, a list of books and some details of a specific book. So, I can start by adding those three routes at the end of the file:

Route::resource('authors', 'AuthorController')->only('index');
Route::resource('books', 'BookController')->only(['index', 'show']);

Now, since we created a resource controller in the beginning of this tutorial, we can now use the Route's resource static method. You pass as arguments the name of the route and a controller to map each of these seven routes:

  • Index
  • Create
  • Store
  • Show
  • Edit
  • Update
  • Delete

If you go to the controllers, you will see that all of those methods are in the there. Since we're developing a Rest API, we would not even need a route for create and edit, because those are meant to return a view with the forms for creating and editing the resource, respectively. As stated before we only need a list of authors, a list of books, and details of a specific book, so we use the  only() method to limit the resource routes.

Of course, we didn't need all of that boiler plate code, so might as well create each of those routes and methods from scratch, but I wanted to show you these methotds, because they save you time in your day-to-day.

Now, let's implement index() in the AuthorController, so go to app/Http/Controllers/AuthorController.php and add this code:

public function index()
{
    $authors = Author::all();

    return response()->json($authors);
}

Since we only have 5 authors (created by the seeder, remember?), we would not even need pagination, so let's query all the authors.

In BookController we need to implement index() for the list of books and show() for the details of the specific book:

public function index()
{
    $books = Book::with('author')->paginate(10);

    return response()->json($books);
}

public function show(Book $book)
{
    return response()->json($book);
}

The with() queries the relationship and already returns a book with its author.

The string you pass to this method must be equal to the name of the method you gave to the relationship in the Book model.

Since we have at least 25 books, let's create a pagination query 10 books every time.

In the case of show(), Laravel already resolves the book id passed to the route and gives us the Book instance as an argument.

Now if you run Laravel's server using php artisan serve, you can access http://localhost:8000/api/authors or http://localhost:8000/api/books in your browser or in app like Postman or Insomnia and you will get a JSON response like this:

{
  "current_page": 1,
  "data": [
    {
      "id": 1,
      "author_id": 6,
      "title": "Inventore voluptatem iure veniam quis nesciunt aut.",
      "price": "42.19",
      "created_at": "2020-05-16T17:39:22.000000Z",
      "updated_at": "2020-05-16T17:39:22.000000Z",
      "author": {
        "id": 6,
        "name": "Brandyn Gorczany",
        "created_at": "2020-05-16T17:39:22.000000Z",
        "updated_at": "2020-05-16T17:39:22.000000Z"
      }
    },
    ...
  ],
  "first_page_url": "http:\/\/localhost:8000\/api\/books?page=1",
  "from": 1,
  "last_page": 3,
  "last_page_url": "http:\/\/localhost:8000\/api\/books?page=3",
  "next_page_url": "http:\/\/localhost:8000\/api\/books?page=2",
  "path": "http:\/\/localhost:8000\/api\/books",
  "per_page": 10,
  "prev_page_url": null,
  "to": 10,
  "total": 25
}

If you want to access details of a book,  just go to http://localhost:8000/api/books/1 where "1" is the id of the book you want to access. This will return this response:

{
  "id": 1,
  "author_id": 6,
  "title": "Inventore voluptatem iure veniam quis nesciunt aut.",
  "price": "42.19",
  "created_at": "2020-05-16T17:39:22.000000Z",
  "updated_at": "2020-05-16T17:39:22.000000Z"
}

So, there you have it. It doesn't take too much time to create a Rest API with Laravel, as a bonus you already have factories and seeders setup to use in automated tests.

Stay tuned because in the next posts you'll learn how to authenticate in the API using Laravel Passport and how to use Eloquent's API Resources to fine tune what you want to display in each route.

]]>
<![CDATA[Let’s build a tab navigation with Alpine.js]]> https://dberri.com/lets-build-a-tab-navigation-with-alpine-js https://dberri.com/lets-build-a-tab-navigation-with-alpine-js Sat, 06 Jun 2020 14:06:14 GMT From the docs: it is

a rugged, minimal framework for composing JavaScript behavior in your markup.

I like to think of it as a lighter and lower cost Vue.js mixed with TailwindCSS. The syntax is very similar to Vue.js and you sprinkle it in your HTML just like TailwindCSS.

I found out about Alpine.js while following Caleb Porzio, an active member of the Laravel community. At the time I saw the Github link and to be honest didn’t care too much or was skeptical about it: “Ok, it’s just another JS framework, next week a new one comes out”.

Then I heard him talk about it in his podcast No Plans To Merge and it started to spark my interest. I took another look at the docs and was like: “well, I could just use Vue.js or plain JS, no need to do it with something else”. It was not until I heard him and Adam Wathan discuss it in the Full Stack Radio podcast that I finally took Alpine.js for a ride.

In the episode, they discuss the use cases for the framework and it made sense to me. Here’s what made me want to use it: let’s say you are building a website that does not need too much JavaScript. There’s only one thing here and there, like a modal, a dropdown menu or tabs navigation. Of course, you could just write the JavaScript for that and don’t worry about it. It will be a bit of a pain to switch contexts and think about the imperative way of doing it with JS (get elements, toggling classes, etc
) or you could add Vue.js and create a component and all that. Seems a little overkill for just a simple interactive element. Or you could use Alpine.js and do it in a declarative way all in the HTML.

In the documentation, the author states that the framework’s syntax is entirely borrowed from Vue.js, so you will find things like x-on:click, x-bind, x-show, x-for which are basically the same as v-on:click, v-bind and so on. If you know Vue.js, it’s a breeze to learn Alpine.js, but even if you don’t, I think it is simple enough to pick up and understand the concepts.

What are we going to build?

Tab navigation representation

It's a simple tab navigation component. It's not the most exciting thing to do with JS, but it will be great to show you what Alpine.js can do. We are going to add TailwindCSS just so we don't have to worry too much about CSS and focus on Alpine's features. We get the framework form a CDN, so it's as easy as pasting the link in the HTML and be ready to go. You can go to this Github repository to get the code and follow along, or use the develop branch to get the final result.

The initial HTML body looks like this:

<div class="bg-gray-100 text-gray-800">
    <nav class="bg-gray-300">
      <ul class="flex">
        <li class="px-4 py-2 bg-gray-100">
          <a href="#option-1">Option 1</a>
        </li>
        <li class="px-4 py-2">
          <a href="#option-2">Option 2</a>
        </li>
        <li class="px-4 py-2">
          <a href="#option-3">Option 3</a>
        </li>
      </ul>
    </nav>

    <div class="p-4">
      <h2 class="text-xl mb-4">Here, you have the content of <strong>Option 1</strong></h2>
      <p class="mb-2">Qui ipsorum...</p>
    </div>

    <div class="p-4">
      <h2 class="text-xl mb-4">Here, <strong>Option 2</strong> contents are shown</h2>
      <p class="mb-2">Qui ipsorum...</p>
    </div>

    <div class="p-4">
      <h2 class="text-xl mb-4">And here, only <strong>Option 3</strong> contents should be displayed</h2>
      <p>Qui ipsorum...</p>
    </div>
  </div>

If you open this with your browser, the styles will be there, but all the content (for all tabs) are shown at the same time. Now let's sprinkle some Alpine.js to only show a single tab's content:

<div class="bg-gray-100 text-gray-800" x-data="{ selected: 'option-1' }">
    <nav class="bg-gray-300">
      <ul class="flex">
        <li class="px-4 py-2 bg-gray-100">
          <a href="#option-1" x-on:click="selected = 'option-1'">Option 1</a>
        </li>
        <li class="px-4 py-2">
          <a href="#option-2" x-on:click="selected = 'option-2'">Option 2</a>
        </li>
        <li class="px-4 py-2">
          <a href="#option-3" x-on:click="selected = 'option-3'">Option 3</a>
        </li>
      </ul>
    </nav>

    <div x-show="selected === 'option-1'" class="p-4">
      ...
    </div>

    <div x-show="selected === 'option-2'" class="p-4">
      ...
    </div>

    <div x-show="selected === 'option-3'" class="p-4">
      ...
    </div>
  </div>

Here we are greeted by three directives: x-data, x-on:click and x-show.

x-data declares a new component scope. You can pass a JS object to it, and every element that is wrapped by the element which contains the x-data declaration, will have access to the JS object you passed to it. So, for example, if I had declared x-data in the nav element, only nav, ul, li and a would have access to that data. Since we want to use selected in the tab's content elements, we wrap everything with another element and use x-data there. You can have multiple x-data declarations in your page, just remember what each component has access to.

x-on:click attaches a click event listener to that element. The directive part is actually only x-on, the second part (click) is what event you want to listen to. You could for instance use x-on:keydown.escape to listen for presses on the escape key. Take a look at the docs to learn all the other events you can listen to. So, x-on:click can receive a function or an expression. Since we only want to change the state of selected, we can add this short expression directly, like x-on:click="selected = 'option-1'". This will change the selected value in the x-data directive.

Finally, we have x-show. You can pass an expression that resolves to true or false and it will toggle the display: none; style on the element.

Ok, so with that, we should already have a basic tabs functionality:

Wait, I mean, it's working but the tabs' styles are not changing to reflect their state. Well, let me present you x-bind:class (if you know Vue.js, this is not going to be a big surprise):

<ul class="flex">
        <li class="px-4 py-2" x-bind:class="{ 'bg-gray-100': selected === 'option-1' }">
          <a href="#option-1" x-on:click="selected = 'option-1'">Option 1</a>
        </li>
        <li class="px-4 py-2" x-bind:class="{ 'bg-gray-100': selected === 'option-2' }">
          <a href="#option-2" x-on:click="selected = 'option-2'">Option 2</a>
        </li>
        <li class="px-4 py-2" x-bind:class="{ 'bg-gray-100': selected === 'option-3' }">
          <a href="#option-3" x-on:click="selected = 'option-3'">Option 3</a>
        </li>
      </ul>

Here, we pass an object to the x-bind:class directive where the key is the class that should be applied and the value should be an expression that resolves to true or false. If it is true, the class is applied, else it is not. With that, this component is done.

Now let's add some fluff. First, just like Vue.js, we can use a shorter syntax, where x-on can be replaced by @, and x-bind can be replaced by ::

<li class="px-4 py-2" :class="{ 'bg-gray-100': selected === 'option-1' }">
          <a href="#option-1" @click="selected = 'option-1'">Option 1</a>
        </li>

Now, for the grand finale let’s add some transitions to the content boxes, so it’s easy on the eyes:

<div x-show.transition.in.opacity.duration.750ms="selected === 'option-1'" class="p-4">
      ...
    </div>

    <div x-show.transition.in.opacity.duration.750ms="selected === 'option-2'" class="p-4">
      ...
    </div>

    <div x-show.transition.in.opacity.duration.750ms="selected === 'option-3'" class="p-4">
      ...
    </div>

Yep, that’s it. It’s that easy. You can basically chain several options to make your transition look better. By default, if you only add x-show.transition it will add an in and out opacity plus scale transition with 200ms of duration. I changed that in this demo to only transition in, only change opacity and to last 750ms. If you want to take a look at other options, check out the docs.

That’s it. With that little amount of code we were able to add tabs navigation to the application. Alpine.js is great when you want to make simple stuff like this, but it can also be used to create more complex interactions such as forms. In a future post I’ll show you how 😎.

]]>
<![CDATA[Let's build an ajax form with Alpine.js]]> https://dberri.com/lets-build-an-ajax-form-with-alpine-js https://dberri.com/lets-build-an-ajax-form-with-alpine-js Tue, 23 Jun 2020 00:07:38 GMT In the previous post, we built a tab navigation with Alpine.js and I said I wanted to bring you a more complex example. So, let’s build a regular contact form like this:

The catch is that we will send the data through ajax and handle all the form data with Alpine. I have done this countless times with vanilla JS or jQuery and it is always a monotonous task. You have to get all of the elements by reference, access their values and then send the data. Alpine (and other frontend frameworks) make this task a breeze.

As I said, this will be a simple form (name, email, message submit button) , but if you get the idea behind the implementation, you can apply it in more advanced situations. You can go to  this Github repository  to get the code and follow along from the master branch, or use the develop branch to get the final result. This is the important part:

<form action="/contact" method="POST" class="w-64 mx-auto">
	<div class="mb-4">
		<label class="block mb-2">Name:</label>
		<input type="text" name="name" class="border w-full p-1">
	</div>
    <div class="mb-4">
		<label class="block mb-2">E-mail:</label>
        <input type="email" name="email" class="border w-full p-1">
	</div>
	<div class="mb-4">
		<label class="block mb-2">Message:</label>
		<textarea name="message" class="border w-full p-1"></textarea>
	</div>
	<button class="bg-gray-700 hover:bg-gray-800 text-white w-full p-2">Submit</button>
</form>

That’s the basic HTML structure of the form. Up to now, there’s no javascript at all, it’s just a regular form that would work with a page reload. Now, let’s sprinkle some Alpine.js on it. Last time, I added the data object inline inside the x-data. This time, since that object will be more convoluted, I’ll show you that you can do most of the “heavy lifting” inside a script tag as such:

<script>
    function contactForm() {
      return {
        formData: {
          name: '',
          email: '',
          message: ''
        },
      }
    }
</script>

Then you just need to add that function call inside the x-data:

<form action="/contact" method="POST" class="w-64 mx-auto" x-data="contactForm()">

Now, let me present you the x-model directive. This keeps input elements in sync with the component data. We have the formData object inside the component scope, so we can use them in the inputs and textareas like this:

<form action="/contact" method="POST" class="w-64 mx-auto" x-data="contactForm()">
    <div class="mb-4">
      <label class="block mb-2">Name:</label>
      <input type="text" name="name" class="border w-full p-1" x-model="formData.name">
    </div>

    <div class="mb-4">
      <label class="block mb-2">E-mail:</label>
      <input type="email" name="email" class="border w-full p-1" x-model="formData.email">
    </div>

    <div class="mb-4">
      <label class="block mb-2">Message:</label>
      <textarea name="message" class="border w-full p-1" x-model="formData.message"></textarea>
    </div>
    <button class="bg-gray-700 hover:bg-gray-800 text-white w-full p-2">Submit</button>
</form>

In vanilla JavaScript, you would probably have to grab the element with something like getElementById and then access its value. With x-model, you don’t have to worry about it. As you type in the input element, your data object is automatically updated with whatever you typed.

Now, as for the ajax part, let’s just use the fetch API, so we don’t have to pull an external dependency, but you can adapt this to your needs of course:

function contactForm() {
	return {
		formData: {
			name: '',
			email: '',
			message: ''
		},
		message: '',
        
		submitData() {
			this.message = ''

			fetch('/contact', {
				method: 'POST',
				headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(this.formData)
            })
			.then(() => {
				this.message = 'Form sucessfully submitted!'
			})
			.catch(() => {
				this.message = 'Ooops! Something went wrong!'
			})
		}
	}
}

and add this paragraph before the form closing tag:

<p x-text="message"></p>

If you don’t understand what the .then and .catch statements are, dont' worry, you can check out this article about Promises. I’ll probably do a blog post about it in the future, stay tuned. Basically, this whole submitData method will do a POST request to the /contact route and pass the form data as a stringified JSON. If everything is successful the .then block is executed, if there's and error in the response, the .catch is executed.

Now, we have to call this method upon form submission. The form element emits a submit event, so we can listen to it using the x-on directive, and since we don’t want to reload the page we add the .prevent event modifier to sort of “hijack” the form submission and use our own method “submitData”:

<form action="/contact" method="POST" class="w-64 mx-auto" x-data="contactForm()" @submit.prevent="submitData">

That's it! You’ve got yourself a working ajax form built with Alpine.js. But let’s take a step forward and add some dynamic styling to the submit button to improve the user experience:

Add this style tag inside the head (I'll just add this style because as of now, TailwindCSS does not support disabled state out of the box):

<style>
    button:disabled {
      cursor: not-allowed;
      opacity: 0.5;
    }
</style>

Now, replace the old submit button with this one:

<button class="bg-gray-700 hover:bg-gray-800 disabled:opacity-50 text-white w-full p-2 mb-4" x-text="buttonLabel" :disabled="loading"></button>

The two interesting bits are the x-text directive and the :disabled. We will use the x-text to change the button's label dynamically and :disabled to, well, disable the button while the form is being submitted.

Update the contactForm function with the following:

loading: false,
buttonLabel: 'Submit',

submitData() {
	this.buttonLabel = 'Submitting...'
	this.loading = true;
	this.message = ''
    
	fetch('/contact', {
		method: 'POST',
		headers: { 'Content-Type': 'application/json' },
		body: JSON.stringify(this.formData)
	})
	.then(() => {
    	this.message = 'Form sucessfully submitted!'
    })
	.catch(() => {
		this.message = 'Ooops! Something went wrong!'
	})
	.finally(() => {
		this.loading = false;
		this.buttonLabel = 'Submit'
	})
}

That's it (again and finally)! We have a fully working ajax form built with Alpine.js and with some UX sugar. Do you want to see something specific using Alpine.js? @ me!

]]>
<![CDATA[Web scraping with Puppeteer]]> https://dberri.com/web-scraping-with-puppeteer https://dberri.com/web-scraping-with-puppeteer Mon, 06 Jul 2020 16:59:41 GMT Today, I decided to bring sort of a different topic to the blog: web scraping.
Sometimes, I find myself wanting to analyse or visualize some data that is not available through an API or is not really structured, so I turn to web scraping. This is a data extraction method where the user or an automated software copies specific data from a website. I used to use Python to do that, but recently I came across puppeteer and that is the Node library we’re going to use today.

According to the docs, puppeteer is “a Node library which provides a high-level API to control Chrome or Chromium over the DevTools Protocol.” This means we can do things like: crawl simple web pages or even SPAs (single page applications), automate form submissions, UI testing, generate screenshots and PDFs, and more.

Assuming you have Node.js installed in your computer, you can run this snippet as a .js file and quickly see how it works.

const puppeteer = require('puppeteer');

(async () => {
	// Launch the headless browser
	const browser = await puppeteer.launch();

	// open a new page
	const page = await browser.newPage();

	// go to the specified url
	await page.goto('https://example.com');

	// take a screenshot
	await page.screenshot({path: 'screenshot.png'});

	// close the browser
	await browser.close();
})();

If you want to see what the browser is doing instead of just waiting for the results, you can change the headless mode:

const browser = await puppeteer.launch({
	headless: false
});

This will open up a browser window as soon as the script starts running and you will see each step as they happen.

Now, the cool thing about using puppeteer for web scraping is that you can use “vanilla” JavaScript syntax to find elements and data on the page. You will have access to the document interface inside the evaluate method. Let’s try it on the Google News page:

const puppeteer = require('puppeteer');

(async () => {
	const browser = await puppeteer.launch();
	const page = await browser.newPage();

	await page.goto('https://news.google.com/news/');

	const data = await page.evaluate(() => {
		// Find all anchor tags whose parent is an H3
		const headlineNodes = document.querySelectorAll('h3 > a')
		// Transform the NodeList in an array and map it to get the textContent of each anchor

		return {
			headlines: Array.from(headlineNodes).map(a => a.textContent)
		}
	});

	console.log(data);

	await browser.close();
})();

As I write this post, these are the headlines it returned:

{
  headlines: [
    "POLITICO's Election Forecast: Trump, Senate GOP in trouble",
    'Trump campaign “strongly” encourages face masks at outdoor rally in New Hampshire.',
    'Facebook, WhatsApp Suspending Review of Hong Kong Requests for User Data',
    'Trump celebrates Fourth of July by stoking division over pandemic and race',
    '7-Year-Old Among 13 Killed in Weekend Shootings in Chicago',
    'LA County New COVID-19 Cases Shatter Daily Record In First Report Since Data Processing Changes'
  ]
}

Google News has an infinite scroll behaviour. This means that when you first load the page, only a few articles are shown and the others are loaded as you scroll down the page. You can mimic this behaviour to get more data by using a combination of window.scrollBy and setInterval inside the evaluate method. Something like this (beware this can cause an infinite loop, make sure to create an exit strategy that meets your requirements):

const data = await page.evaluate(async () => {

    await new Promise((resolve) => {
      var totalHeight = 0;
      var distance = 100;
      var timer = setInterval(() => {
        var scrollHeight = document.body.scrollHeight;
        window.scrollBy(0, distance);
        totalHeight += distance;

        if (totalHeight >= scrollHeight) {
          clearInterval(timer);
          resolve();
        }
      }, 100);
    })

    const headlineNodes = document.querySelectorAll(‘h3 > a’)
    return {
      headlines: Array.from(headlineNodes).map(a => a.textContent)
    }
  });

And that’s it. Hopefully you can see how this technique can be useful to automate boring tasks and maybe create APIs where there isn't one. On a final note, be respectful of the website you’re scraping. You should follow the rules stated in the /robots.txt for each website, make sure to agree with the terms of service and check if scraping is actually legal wherever you are doing it. And try to not DDOS them when running this in loops :)

]]>
<![CDATA[How to build a real time chat app with Node.js and Socket.io]]> https://dberri.com/how-to-build-a-real-time-chat-app-with-node-js-and-socket-io https://dberri.com/how-to-build-a-real-time-chat-app-with-node-js-and-socket-io Sun, 09 Aug 2020 14:33:47 GMT Lots of applications rely on real time data delivery to provide value to the user. From instant messaging, to online multiplayer games, IoT, ad servers, and stock exchange brokers, at one point or another in your career you might be challenged to build something like that. And with Node.js and Socket.io, it became so simple that you will might as well learn it now.

But before we start building the app, let's talk about some topics and approaches that you could use to build a real time application.

Regular polling

A good and simple way to summarise this is if you have an application that periodically (let’s say every 10s) sends a request to the server like asking: “Hey do you have any new information for me?”. Now, this can work in some situations, but you can imagine what would happen if hundreds of clients kept bombing the server with this amount of request every few seconds. Been there, done that, it was a very stressful day


Long Polling

Long polling is similar to regular polling, but after a request to the server, the connection hangs and the server will only close the connection with a response once there’s new information. The client, after receiving the response, immediately sends a new request waiting for new information. This is a good option for delivering messages without delay but the server architecture must be able to handle multiple pending connections. Depending on the type of technology used, each pending connection can take up a lot of memory, which was the case when I tried this option
  it was a very long day.

WebSocket

While regular polling and long polling make use of HTTP, WebSocket is another communication protocol that enables two-way communication between the server and the client. After the connection is opened, the client can send messages to the server, and receive event-driven responses without having to poll the server for a reply.

Socket.io

In their website, it says: ”Socket.IO enables real-time, bidirectional and event-based communication.”.  It tries to establish a WebSocket connection if possible, but will fall back to HTTP long polling if not. Which is an important distinction to consider when you’re thinking about building something on top of it.

Their website also lists examples of applications that make good use of Socket.io like real-time analytics that push data to clients (like counters, charts and logs) or instant messaging and chat (like what we will be doing) and document collaboration where users editing a document can see other users changes in real time (think Google Docs). One can also think of how games could make use of this technology to send and receive multiplayer data.

It’s incredibly easy to integrate it in a Node.js application (they say it works on every platform, but I haven’t tried).

Let’s start 🚀

This is what the chat app will look like by the end of this tutorial:

Screenshot of the chat application

It should go without saying that we need Node.js installed, so if you still don’t have, go to their website and download at least the LTS version.

With that comes npm, the node package manager. I prefer Yarn (and that’s what I’ll be using throughout the tutorial), but feel free to use npm if you want. With that, go ahead and create a folder to store the application files. Now, open your terminal and navigate to the newly created folder (e.g. cd realtime-chat) and run yarn init -y which will quickly create a package.json file and you will be able to add the only dependency we need: yarn add socket.io.

Now, we need am HTML page where the users will be able to use the chat and a Node.js server. So, go ahead and create an index.html and a server.js files.

With that, let’s open package.json and edit a few lines. First, let’s change the main from index.js to server.js, and in scripts we can remove the test script and add "start": "node server.js" which will enable us to run yarn start from the root folder of the application and start up our server. That part of your package.json should look like this:

“main”: “server.js”,
“scripts”: {
  “start”: “node server.js”
}

The interface

Since HTML is not the focus here, you can go ahead and copy this to your index.html file:

<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>RealTime</title>
  <link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet">
</head>

<body>
  <div class="bg-white overflow-hidden overflow-hidden shadow rounded-lg px-4 py-4 sm:px-6 w-4/5 mx-auto mt-8">
    <h2 class="text-2xl leading-8 font-extrabold text-gray-900 sm:text-3xl sm:leading-9">
      Chat
    </h2>

    <div class="px-4 py-5 sm:p-6" id="message-box">
      <!-- Content goes here -->
    </div>

    <div class="border-t border-gray-200 px-4 py-4 sm:px-6">
      <form id="form" action="#" method="POST" class="grid grid-cols-1 row-gap-6">
        <div>
          <div class="mt-1 relative rounded-md shadow-sm">
            <input id="input" placeholder="Start typing..."
              class="form-input py-3 px-4 block w-full transition ease-in-out duration-150">
          </div>
        </div>
        <button type="submit"
          class="w-full inline-flex items-center justify-center px-6 py-3 border border-transparent text-base leading-6 font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-500 focus:outline-none focus:border-indigo-700 focus:shadow-outline-indigo active:bg-indigo-700 transition ease-in-out duration-150">
          Send message
        </button>
      </form>
    </div>

    <div class="border-t border-gray-200 px-4 py-4 sm:px-6">
      <h3 class="px-4 py-4">Who's online:</h3>
      <ul id="peer-list"
        class="px-6 py-3 max-w-0 w-full whitespace-no-wrap text-sm leading-5 font-medium text-gray-900">
        <!-- Content goes here -->
      </ul>
    </div>

  </div>
</body>
</html>

This is the basic structure of the chat app. There’s a box to display all messages, a form to type the message and a button to send it. All of the important parts have ids so that we can retrieve them in JavaScript later. Here, I’m using TailwindCSS to make it look good fast.

The server

Now, open server.js and add the following:

const fs = require('fs');
const http = require('http');
const SocketIO = require('socket.io');

// Prepares HTML file to be served
const content = fs.readFileSync(__dirname + '/index.html', 'utf8');
const httpServer = http.createServer((req, res) => {
  res.setHeader('Content-Type', 'text/html');
  res.setHeader('Content-Length', Buffer.byteLength(content));
  res.end(content);
})

// Creates socket.io connection
const io = SocketIO(httpServer);

// Handles "connect" event
io.on('connect', socket => {
	// Handles "message" event sent by client
  socket.on('message', data => {
		// Emits new message to every connected client
		io.emit('newMessage', {
			message: data
		})
	})
});

// Starts up server
httpServer.listen(3000, () => {
  console.log("đŸ”„ Listening on http://localhost:3000");
})

This enough for the basic functionality of the app. We could further simplify things by using a framework like express, but for now, a classic Node.js server will suffice. It serves the index.html file and then creates a Socket.io connection on line 14. Then we can use the event listening functionality to listen for a “connect” event emitted from the client and handle that connection. You can create your own event keywords (like  “connect”), but you have to keep in mind that there are a few keywords that should not be used as they conflict with the ones implemented by Socket.io. A few examples include connect, disconnect, reconnect and error. A full list of these event names can be found here.

On line 16 we listen for an event named “message” and pass a callback to handle the data received by that event. Then on line 18 we emit an event named “newMessage” to all connected sockets. Note that we listened on socket which is an individual client connected and we emit with io which is sort of a pool of sockets. You can always refer to this emit cheatsheet to see all the options you have, like emitting events to all connected sockets but the emitter, or emitting to “rooms” or sending privately from socket to socket.

Now, I want to make things more interesting and assign random names to the clients send these names to all clients so they know who’s connected and able to chat. Let’s add this:

const animals = [
  'fish',
  'cat',
  'tiger',
  'bear',
  'bull',
  'fox'
]

const colors = [
  'red',
  'green',
  'blue',
  'yellow',
  'purple',
  'pink'
]

/**
 * Generates a random name based on an animal and a color
 * 
 * @return {String}
 */
function randomName() {
  const color = colors[Math.floor(Math.random() * colors.length)]
  const animal = animals[Math.floor(Math.random() * animals.length)]

  return `${color}-${animal}`;
}

// Stores the names and ids of connected clients
const sockets = {}

// Creates socket.io connection
const io = SocketIO(httpServer);

Then, inside the “connect” event handling, let’s add a few new even handlers:

// Handles “connect” event
io.on('connect', socket => {
  sockets[socket.id] = randomName();
  socket.emit('name-generated', sockets[socket.id]);
  io.emit('update-peers', Object.values(sockets));

  // Handles “message” event sent by client
  socket.on('message', data => {
    // Emits new message to every connected client
    io.emit('newMessage', {
      sender: sockets[socket.id],
      message: data
    })
  });

  // Handles “disconnect” event
  socket.on('disconnect', () => {
    delete sockets[socket.id]
    io.emit('update-peers', Object.values(sockets))
  })
})

Here we’re basically wait for a client to connect, then we assign a random name to their socket id and send their “random name” so they know who they are. Then we send the list of connected socket names. We also need to handle the disconnect event, so if anyone disconnects, we update the list of connected sockets and send that to everyone in the chat to update their user interface.

Cool, now let’s implement the client so it can connect to the server and do its magic.

The client

Go to the index.html file and before closing the body tag, add the following:

<script src="/socket.io/socket.io.js"></script>
<script>

</script>

This will “import” the Socket.io script (when you’re building a more complex application and are using a module bundler, this will probably look different, as the import will happen in another JavaScript file, but this is out of the scope of this article).

Let’s start the program by getting access to a few elements that we will use throughout the script:

<script>
    const form = document.getElementById('form');
    const input = document.getElementById('input');
    const msgBox = document.getElementById('message-box');
    const peerList = document.getElementById('peer-list');
</script>

Now, in order to make use of Socket.io, we need to call it and store it in a variable, then we will start listening and emitting events:

<script>
  const form = document.getElementById('form');
  const input = document.getElementById('input');
  const msgBox = document.getElementById('message-box');
  const peerList = document.getElementById('peer-list');

  const socket = io();

  // Handles the "name-generated" event by storing the client's name in a variable
  socket.on('name-generated', () => ());

  // Handles the "update-peers" event by updating the peers list
  socket.on('update-peers', () => ());

  // Handles "newMessage" event and add that message to the chat
  socket.on('newMessage', () => ());

</script>

All of the events listed above with socket.on() are emitted by the server at some point, they are still not implemented (i.e. we still don’t do anything after we listened for those events, but we will do it shortly. Before that, let’s handle the submission of a message:

/**
 * Retrieves message from input and emits to the server
 * 
 * @param {Object} evt Event fired by the form submission
 */
function submitHandler(evt) {
  evt.preventDefault();
  socket.emit('message', input.value);
  input.value = ''
  msgBox.focus();
}

form.addEventListener('submit', submitHandler)

Here, we attach an event listener to the form. It will listen for the “submit” event and the submitHandler will prevent the default (just so the form does not trigger a page reload or navigating to the action attribute) and then we emit a “message” event containing the input field value. Then we clear the field and focus on something that is not a field, so if the user is in a mobile device, the keyboard goes away.

Now let’s go back to the other socket’s event listeners, an we will implement them. First, the simplest one, we listen for the “name-generated” event, if you remember, this is the event the server emits after generating a random name for the client. We need to store this name to use in other functions, so let’s create a variable in the same scope as the socket listeners like this:

let myName = ''
const socket = io();

// Handles the “name-generated” event by storing the client’s name in a variable
socket.on('name-generated', name => {
  myName = name
});

And now, let’s handle the “newMessage” event. This event is emitted by the server whenever a socket emits the “message” event. In other words, someone sends a message to the server and the server broadcasts this message to everyone connected:

// Handles “newMessage” event and add that message to the chat
socket.on('newMessage', ({ sender, message }) => {
  let name = document.createElement('strong');
  name.textContent = `${sender} says: `

  let msgEl = document.createElement('span');
  msgEl.textContent = message

  let paragraph = document.createElement('p');
  paragraph.appendChild(name);
  paragraph.appendChild(msgEl);

  msgBox.appendChild(paragraph);
});

Here, we expect the server to send an object containing the message and the sender’s name. We use this information to create a paragraph element that will be something like this: “blue-fish says: I am a new message”. And then appends this paragraph in the message box.

Let’s finish this by implementing the list of online clients:

// Handles the “update-peers” event by updating the peers list
socket.on('update-peers', peers => {
  peerList.innerHTML = ''

  const template = `<li class=“flex items-center space-x-3 lg:pl-2”>
    <div class=“flex-shrink-0 w-2 h-2 rounded-full bg-%PEER_COLOR%-600”></div>
      <span>%PEER_NAME%</span>
  </li>`

  for (const peer of peers) {
    let name = peer
    if (name === myName) {
      name += ' (you)'
    }
    peerList.innerHTML += template.replace('%PEER_NAME%', name).replace('%PEER_COLOR%', peer.split('-')[0])
  }
});

This might seem a little complex, but we just clear the list of online peers whenever we listen to the “update-peers” event and then create an HTML template to attach to the DOM with the names and colors of the connected clients, including yourself (which will use myName variable to add an indication that it’s you).

And that’s it! Now if you go run yarn start in your terminal and go to http://localhost:3000 you should see the chat page and if you connect with other browser windows, tabs or devices you will see the growing list of users connected. And if you close those windows, leaving the chat, the list will also update.

I hope you liked this article and will create awesome applications with this new tool under your belt đŸ»

]]>
<![CDATA[How I added Dark Mode to my blog using TailwindCSS]]> https://dberri.com/how-i-added-dark-mode-to-my-blog-using-tailwindcss https://dberri.com/how-i-added-dark-mode-to-my-blog-using-tailwindcss Fri, 30 Oct 2020 20:50:25 GMT If you’re here, you probably already know what dark mode is, so I’m not going to bore you with a long story about it. But if you want to read more about, here’s a very interesting article.

TL;DR: Dark mode is a color scheme of interfaces that display light text and elements on a dark background. Some say it’s for aesthetics only. Others say it mitigates digital eye strain, or even involved in the regulation of the circadian rhythm. Also, on AMOLED screens, it’s known to save more energy.

With that said, let’s dive right into the content:

A quick trick to make it “look like dark mode”

If you want to add dark mode to your website really quick, here’s a tip by Rik Schennink that I found on Dev.to:

html.dark-mode {
  filter: invert(100%);
}

html.dark-mode img {
  filter: invert(100%);
}

This will literally invert the colors of your website (although keeping the images the same color). That means white will become black and vice-versa, but also red will become green and blue will turn into orange (picture the color wheel now). In some cases, this will be fine, really, but if your UI has more colors and especially brand colors, inverting everything is not really what you want. I tried this on my blog just to see if I could get away with it and for the background and text it did work quite well, but for the tags (each has a distinct color) and for the header menu items, the inverted colors looked
 weird...

Enters prefer-colour-scheme (or how to properly add dark mode)

Remember media queries? Yes, those @media that makes your block of CSS apply only at specific conditions (like min or max width of viewport). Well, what if I told you that not only can you use that to make a responsive layout, but you can also recognise when the user has dark mode activated on his OS or user-agent (browser, etc)? Yeah! That blew my mind when I figured that there are many many more media features you can use.

There’s one called prefers-reduced-motion which means the user prefers less motion on the page (the name of the property gives it away, I guess), inverted-colors which means the user agent has inverted colors, and yes, there’s one called prefers-color-scheme  which detects if the user, well, prefers a dark or light color scheme. If the user does not express any preference, it is assumed to be light.

Here’s how we can use this:

body {
  color: #464646;
  background-color: #FFF;
}

@media (prefers-color-scheme: dark) {
  body {
    color: #FFF;
    background-color: #3E3E3E;
  }
}

Now, if we had this setting in our CSS, and the user visited our website without any active color scheme preference, the font color would be that dark gray and background would be white. If they visit with a dark mode setting active on their system, the website would automatically apply the white color to the font and the darker color to the background.

What I like the most about this setting is that the user does not need to care about this setting on each website they visit. They can set this on their browser or OS, and it will be automatically detected and applied. I, for example, don’t like to use dark mode all the time, so I configured my OS to apply it only at night, so all the websites that use this CSS media feature will apply the light color scheme during the day and the dark mode during the night. Pretty cool, huh?

You could stop right here and go to your CSS and start applying this all over your website, but if you are already using TailwindCSS I’ll show you a cool trick that will make dark mode development much more enjoyable.

How to add custom media queries in TailwindCSS

So, let’s say I have a title of an article in my blog with the following TailwindCSS classes:

<h1 class="text-black text-2xl sm:text-3xl md:text-4xl mb-2">
	How to build a real time chat app with Node.js and Socket.io
</h1>

Nothing new here, just sets the title to be black and a different sizes at different viewports. Now, this is what I want to do:

<h1 class="text-black dark:text-gray-400 text-2xl sm:text-3xl md:text-4xl mb-2">
	How to build a real time chat app with Node.js and Socket.io
</h1>

This would be cool right? Just like we have the different sizes (sm, md, lg and so on) I would like to have the dark mode to be an option like that, so I can choose a color and immediately choose what that element will look like on dark mode. In order to do that, we need to add a plugin to TailwindCSS. So go to your tailwind.config.js and in the extends section, add:

module.exports = {
  theme: {
    extend: {
      screens: {
        dark: { raw: '(prefers-color-scheme: dark)' }
      }
    }
  }
}

That piece of code will tell TailwindCSS to add a custom media query to its set and now you can use just like the other ones.  By the way, you can use the same trick to style for any of those media features.

Now you could do: bg-white dark:bg-black or text-blue dark:text-purple or you know, go crazy with it! (Ok, maybe not, think of your users first).

Adding that scheme and using it inline and in CSS

If you’ve been using TailwindCSS for some time, you know that not always you can get the desired result only using the created classes, so you would have to write some CSS or PostCSS with `@apply` for example. Since we added that custom media query to the config file, you can also do something like this:

@screen dark {
  .MyArticle {
    @apply text-white;
  }
}

And that’s it! Hopefully you got inspired to add dark mode (or use an exotic media feature) in your web projects :) Are you going add dark mode to a project you’re working on? I’d love to see how you’ve done it, so tweet  @ me

Pro tip: if you’re in a website that does not support dark mode and you want to read something in dark mode, try the browser’s “reading mode”. For me at least, it seems to be easier on the eyes.
]]>
<![CDATA[2020 in Review]]> https://dberri.com/2020-in-review https://dberri.com/2020-in-review Wed, 13 Jan 2021 08:32:46 GMT What a crazy year 2020 was, huh? So much stuff happened, ups and downs and ups again


I had finally left a job that required me to go to the office in the end of 2019, so I was already only working from home by the time we were requested to that in order to fight the pandemic. To be fair, even before I left that job I was already working from home as a freelancer and I felt very productive when doing so. The downsides were that I was not going to see that many people anymore and I wouldn’t have to commute. Yeah, I actually liked commuting only because I did so in 15 minutes riding my bike 😬.

Anyway, I decided to write this post to reflect on what I achieved last year to give me some perspective. Sometimes I get frustrated because it looks like I’m not achieving my goals but I tend to forget all the great things I did achieve along the way. I plan on doing this post every year from now on with this objective in mind.

So, to get started I’ll write about the projects I started or launched this year:

This Blog / Website

dberri.com

Yeah, so this was a long time coming. I was planning on launching a website or blog for quite sometime in 2019 but did not have the time or patience to set it up. In January, I decided I was going to do it and use the same stack I was using the my job at the time: Nuxt. I set up a local installation of Ghost CMS and used the JSON output to feed Nuxt which then creates a static site during a build in Netlify.

The first post went live on January 31st, 2020. Since then, I wrote 15 posts. That’s a little more than one post per month but it is 15 posts more than I had in 2019, so that’s a big win 😅. I still don’t think this stack is perfect for what I want, but it does the job well and while I don’t have too many posts, it will suffice. I played around with GraphCMS and seems cool but I’m still not sold on the idea of using it for this blog specifically (I might write a post about GraphCMS in the future because it is really cool, so stay tuned).

The purpose of writing and publishing these articles is to share things I’m learning, help other developers who are struggling to grasp concepts that I also had struggled to learn and improve my writing skills and the way I convey information. I also do some research while I write, so that makes me consolidate the knowledge on the topics. For this year, I plan to write at least 12 posts or one post per month. Let’s see in my 2021 review if accomplished this. đŸ€ž

project-name is not defined

stocks.dberri.com

I don’t have a name for this one yet, even though I launched it on May 1st, 2020. I basically developed it to “scratch my own itch” since I didn’t find anything similar on the web at that time. It’s a small application that helps me balance the risk in my investment portfolio. The user can type a stock ticker in the text field and add it, then assign a grade and the amount of shares they have. They do that for all the companies in their portfolio and while at it, the application highlights which stocks to buy next to keep the portfolio balanced according to the grades they assigned. If my explanation was not clear enough, here is the “about” page I wrote where I also added some examples: http://stocks.dberri.com/en-US/about .

I also developed this project using Nuxt, but since there is some API usage and it needs a Node.js server, I decided to host it on Heroku. It was also the first time I used the serverless and hosted a function in AWS Lambda to fetch prices and some other stock data.

A few months after I launched it, I discovered a similar application while watching a YouTube channel about personal finances, so I have some plans for this application going forward. For one, everything is stored in LocalStorage which works fine for me, but then I can't really use it in different browsers or devices, so I plan on improving the UX by using some authentication and database so the users can use the application on multiple devices. Maybe even a PWA would be cool 😎

usdbrl

npmjs.com/package/usdbrl-cli

I was quite excited to work on this one and launch it. It was the first npm package that I published. USD-BRL CLI is a tool that allows developers to fetch the exchange rate of USD/BRL  directly on the terminal.

To file taxes in Brazil for foreign earnings, one needs to convert that income to USD using the closed exchange rate of the payment date and then convert to BRL using the exchange rate on the 15th workday of the previous month. After a few months doing this manually, it struck me that I could automatize the process by fetching the data from the official Brazilian Central Bank website.

My plan with this was to also learn how to create CLI tools using Node.js and that goal was achieved 😬. Now, I use it every month and it does it job well, so I don’t have any plans to build upon it. Let’s see đŸ€·â€â™‚ïž.

2WEBP Optimizer

image-optimizer.dberri.com

The idea for this one came from the fact that I had to optimize a few images for a website I was building on my day job and I couldn’t find any online tool  that would convert images to the webp format and resize it to the sizes I wanted to. I also wanted to learn Vue 3 which was building up hype the whole year but I didn’t have the time to spend on it before. I also wanted to build something more elaborate with serverless and this was the perfect opportunity for it. I didn’t want this to be one of the many applications I have in my “dead side-projects folder”, so, to create some public accountability, I told my girlfriend about it so she would keep asking me about the progress of the development and I gave myself a deadline (December 31st, 2020).

Everyday, I built a small part of it, starting with the serverless functions. The backend is hosted on AWS, and I use Lambda, API Gateway, Cloudwatch, S3 and DynamoDB, which is all managed by the serverless framework. The frontend is hosted on Netlify as a simple Vue SPA. It was quite rewarding to finally hit the deploy button on the deadline and sip some wine to celebrate.

Now, this one is not completely done yet. It’s like an MVP, it does the job I want it to do, but I still want to iron out a few details, build a few features and advertise it so people can find it and use it. Hopefully the users will be very happy about it.

What I learned?

I started the year learning React and React Native. Back when I started to fell comfortable writing JavaScript, I decided to pick a framework and at that time Vue 2 had been released and was picking up steam and I started to read about it and comparisons with React which was already popular. My idea was to first learn Vue because it seemed to have a good learning curve, and it was bundled with Laravel which for me served as validation since I was and still am a big fan of that PHP framework (*Vue does not come with the Laravel installation anymore). Even though I decided to start with Vue, I always wanted to learn React too, just to see how they both differ, and what problems they solve and in which ways. Since now I already had a very good grasp of Vue and know how JavaScript frameworks work more or less, I decided to learn React and use it in a few side projects. It was a very good experience in my opinion, and it’s good to have another tool under my belt. I still prefer working with Vue and that pays the bills, so đŸ€·â€â™‚ïž

Because of my job and the requirements for the projects, I learned and used Laravel Nova,  learned how to use Twig in Laravel instead of Blade and also learned and used Alpine.js. All of these things might become blog posts in the future. Alpine.js already features in a few of them from last year, and this year I plan on bringing more related content.

I’m also learning quite a bit about accessibility, animations and performance on the web, and I’m very thankful for my coworkers who are helping me with this through code reviews, tips and so on.

What I want to learn in 2021?

Well, this year I’ll double down on learning and applying accessibility aspects correctly on the applications and websites I build, learn more about animations and motion design and keep improving the performance of the stuff I work on (gotta catch those 100s in Lighthouse 😜).

I’m currently learning Laravel Livewire while I build a side project to help my girlfriend with her business and hopefully I’ll be able to bring you more content and tutorials featuring it here.

And that’s a wrap. I wish you all a great 2021 and go after your goals 🚀

]]>
<![CDATA[How to use Twig in Laravel]]> https://dberri.com/how-to-use-twig-in-laravel https://dberri.com/how-to-use-twig-in-laravel Wed, 27 Jan 2021 21:05:44 GMT Laravel comes bundled with its own templating engine called Blade which is very powerful and a breeze to use, but there are times when it's not the best tool for the job. In my case, I first had to replace Blade with Twig in Laravel in order to use Miyagi for component development, and that made me spend a few hours out of my comfort zone learning how to integrate it in Laravel and because of that I'll share my lessons with you.

First you need to install Twig itself and a package called TwigBridge which  will allow you to seamlessly use it in Laravel. Open your terminal (who am I kidding, it's probably already open) and navigate to your application root folder, and run the following command:

composer install rcrowe/twigbridge twig/twig

After the installation is complete, you can run php artisan vendor:publish --provider="TwigBridge\ServiceProvider" which will publish the pacakge's configuration file at config/twigbridge.php. In this file you will be able to tweak a few things like which Laravel Facades are made available to Twig, as well as filters and global functions. With that, you are ready to start using Twig templates, so go ahead and create a new view inside resources/views called welcome.twig (if you don't already have one) to test that:

<!DOCTYPE html>
<html lang="{{ app.getLocale }}">
    <head>
        <!-- other regular head stuff -->
    </head>
    <body class="antialiased">
        <div class="relative flex items-top justify-center min-h-screen bg-gray-100 dark:bg-gray-900 sm:items-center sm:pt-0">        
            {% if Route.has('login') %}
                <div class="hidden fixed top-0 right-0 px-6 py-4 sm:block">
                    {% if auth_check() %}
                        <a href="{{ url('/home') }}" class="text-sm text-gray-700 underline">Home</a>
                    {% else %}
                        <a href="{{ route('login') }}" class="text-sm text-gray-700 underline">Login</a>

                        {% if Route.has('register') %}
                            <a href="{{ route('register') }}" class="ml-4 text-sm text-gray-700 underline">Register</a>
                        {% endif %}
                    {% endif %}
                </div>
            {% endif %}

            <div class="max-w-6xl mx-auto sm:px-6 lg:px-8">
                <div class="mt-8 bg-white dark:bg-gray-800 overflow-hidden shadow sm:rounded-lg">
                    <!-- irrelevant content -->

                    <div class="ml-4 text-center text-sm text-gray-500 sm:text-right sm:ml-0">
                        Laravel v{{ app.version }}
                    </div>
                </div>
            </div>
        </div>
    </body>
</html>

I adapted the original welcome.blade.php view that comes with a fresh installation to show you how it would like like when using Twig. Notice the "Route" facade is readily available but instead of using the static method call like Route::has() you use Twig's dot notation: Route.has(). Other global functions like route, url and app are also available.

If it's a fresh install of Laravel, your base route will already point to the "welcome" view, otherwise just create a route in the routes/web.php file like this:

Route::get('/', function () {
	return view('welcome');
});

Now, let's go a little bit further and use components in the application. Go ahead and create resources/views/components/navbar/navbar.twig and add this content:

<nav>
  <ul>
    <li>
      <a href="{{ url('/') }}">Home</a>
    </li>
    {% for item in items %}
      <li>
        <a href="{{ item.url }}">{{ item.label }}</a>
      </li>
    {% endfor %}
  </ul>
</nav>

and in the welcome.twig view, you can include it just after opening the body tag:

{% include "./components/navbar/navbar.twig" with {
    items: [
      {
        url: url('/nachos'),
        label: 'Nachos'
      },
      {
        url: url('/tacos'),
        label: 'Tacos'
      }
    ]
} %}

And just like that, now you're able to include, embed and extend Twig templates in Laravel. Though, the more your application grow and the more components you have, it might become unwieldy to write all those paths to components. To fight that, you can use Twig namespaces. Instead of writing ../../components/component-name.twig you can write it like this: @components/component-name.twig. All you need to do is add this snippet to the boot method in app/Providers/AppServiceProvider.php:


$loader = new \Twig\Loader\FilesystemLoader();
$loader->addPath(base_path() . '/resources/views/components', 'components');
\Twig::getLoader()->addLoader($loader);

where base_path() . '/resources/views/components' is the path to the component directory and components is how you will call it (i.e. @components). You can add multiple paths like this that point to different (or the same) directories.

If you need to add some custom functionality that is not provided by a built in filter or function, you can create it in a plain php file, something like app/Twig/Functions.php and inside you could add:

<?php
 
namespace App\Twig;
 
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
 
class Functions extends AbstractExtension
{
    public function getFunctions()
    {
        return [
            new TwigFunction('now', [$this, 'now']),
        ];
    }
 
    public static function now()
    {
      return date('d/m/Y H:i:s');
    }
}

Then, go to config/twigbridge.php and add 'App\Twig\Functions', to enabled extensions like:

'extensions' => [
    'enabled' => [
        // ... other enabled extensions ...
        'App\Twig\Functions'
    ]
]

And then in your views you can use your function like:

<p>{{ now() }}</p>

You can do the same with filters in app/Twig/Filters.php:

<?php
 
namespace App\Twig;

use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;

class Filters extends AbstractExtension
{
    public function getFilters()
    {
        return [
            new TwigFilter('count_words', [$this, 'countWords']),
        ];
    }
 
    public static function countWords($sentence)
    {
      return count(explode(' ', $sentence));
    }
}

then in config/twigbridge.php:

'extensions' => [
    'enabled' => [
        // ... other enabled extensions ...
        'App\Twig\Functions',
        'App\Twig\Filters'
    ]
]

and you will be able to use it like this in your views:

<p>{{ 'Laravel has wonderful, thorough documentation covering every aspect of the framework. Whether you are new to the framework or have previous experience with Laravel, we recommend reading all of the documentation from beginning to end.'|count_words }}</p>

And that pretty much covers lots of use cases you would need with Twig in Laravel. Hope this article helps you save some hours of searching for answers in StackOverflow and documentation. If you find any other use cases not covered in this post, let me know and I'll update it. Until the next post!

]]>
<![CDATA[Let’s build an accessible modal with Alpine.js]]> https://dberri.com/lets-build-an-accessible-modal-with-alpine-js https://dberri.com/lets-build-an-accessible-modal-with-alpine-js Sun, 28 Mar 2021 13:07:28 GMT The simplest example of a modal is the one you can find in Alpine.js’ own documentation, and it is for a dropdown modal which would be like this:

<div x-data="{ open: false }">
    <button @click="open = true">Open Dropdown</button>

    <ul
        x-show="open"
        @click.away="open = false"
    >
        Dropdown Body
    </ul>
</div>

Very straight forward, you will just control the "open" state of the modal and change with the button click event. There’s also something very cool which is the "away" event modifier. That ensures that when the modal is open, if a click happens outside of the modal tree, it will hide the it. We will use these basic concepts and build a "regular" modal. As in other Alpine.js' posts, I’ll use TailwindCSS for the styling, so all you need to do is add these two lines in the <head> section of your page (just remember that it is not a purged version of TailwindCSS, so don’t really use it for production):

<link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.x.x/dist/alpine.min.js" defer></script>

Ok, now, we’re ready to start building stuff. Let’s begin by adding a container that will hold Alpine.js' state:

<div x-data="{ open: false }">
</div>

Everything that Alpine.js controls and is related to the modal will need to be inside this <div>. You can have multiple containers like this to control different aspects of the page, but they would be independent. So, inside this container, we will add a button to open the modal and the modal’s markup as well:

<div x-data="{ open: false }">
    <button x-ref="modal1_button"
            @click="open = true"
            class="w-full bg-indigo-600 px-4 py-2 border border-transparent rounded-md flex items-center justify-center text-base font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:w-auto sm:inline-flex">
            Open Modal
    </button>

    <div role="dialog"
         aria-labelledby="modal1_label"
         aria-modal="true"
         tabindex="0"
         x-show="open"
         @click="open = false; $refs.modal1_button.focus()"
         @click.away="open = false; $refs.modal1_button.focus()"
         class="fixed top-0 left-0 w-full h-screen flex justify-center items-center">
        <div class="absolute top-0 left-0 w-full h-screen bg-black opacity-60"
             aria-hidden="true"
             x-show="open"></div>
        <div @click.stop=""
             x-show="open"
             class="flex flex-col rounded-lg shadow-lg overflow-hidden bg-white w-3/5 h-3/5 z-10">
          <div class="p-6 border-b">
            <h2 id="modal1_label">Header</h2>
          </div>
          <div class="p-6">
            Content
          </div>
        </div>
    </div>
</div>

This will get you a very simple modal window when you click on the "Open modal" button. No transitions, no flair, just a plain modal. Let's break down the markup:

<button data-modal-open="modal_1"
        @click="open = true"
        class="...">
  Open Modal
</button>

This is the button that will trigger the modal to open (classes ommited), other than the known @click="open = true" which you are probably familiar with, we have the x-ref="modal1_button" attribute. This is there so we can retrieve a reference to the button element and set focus to it once the modal is closed which is helpful for people who use the keyboard to navigate around the page. Onto the next part:

<div role="dialog"
     aria-labelledby="modal1_label"
     aria-modal="true"
     tabindex="0"
     x-show="open"
     @click="open = false; $refs.modal1_button.focus()"
     @click.away="open = false; $refs.modal1_button.focus()"
     class="...">
     ...
</div>

This is the modal container. You'll notice the `role` attribute and it's set to "dialog" which according to W3 is a way to identify the element that serves as the dialog container. Then, we have the aria-labelledby attribute, which will set the accessible name of the container to the modal title (h2 tag). Next is aria-modal attribute which tells accessibility technologies that the content underneath this dialog won't be available for interaction while it's open. x-show is probably self-explanatory and then we have $refs.modal1_button.focus() which will use the x-ref we set in the button to set focus to it once the modal is closed.

Next we have this empty div which is used as a modal backdrop, nothing special about it so we add the aria-hidden attribute which just hides this div from accessbility technologies:

<div class="absolute top-0 left-0 w-full h-screen bg-black opacity-60"
     aria-hidden="true"
     x-show="open"></div>

Then, we finally reach the modal contents:

        <div @click.stop=""
             x-show="open"
             class="...">
          <div class="p-6 border-b">
            <h2 id="modal1_label">Header</h2>
          </div>
          <div class="p-6">
            Content
          </div>
        </div>

The only important parts here are the id we set in the h2 tag, which must be equal to the one we set in aria-labelledby earlier and the stop event modifier set to the @click event. This will prevent the click event from bubbling up to the modal container, which would listen to it and close the modal.

That covers the markup, now let's tackle the animations:

<div role="dialog"
     aria-labelledby="modal1_label"
     aria-modal="true"
     tabindex="0"
     x-show="open"
     @click="open = false; $refs.modal1_button.focus()"
     @click.away="open = false"
     class="fixed top-0 left-0 w-full h-screen flex justify-center items-center">
        <div aria-hidden="true"
             class="absolute top-0 left-0 w-full h-screen bg-black transition duration-300"
             :class="{ 'opacity-60': open, 'opacity-0': !open }"
             x-show="open"
             x-transition:leave="delay-150"></div>
        <div data-modal-document
             @click.stop=""
             x-show="open"
             x-transition:enter="transition ease-out duration-300"
             x-transition:enter-start="transform scale-50 opacity-0"
             x-transition:enter-end="transform scale-100 opacity-100"
             x-transition:leave="transition ease-out duration-300"
             x-transition:leave-start="transform scale-100 opacity-100"
             x-transition:leave-end="transform scale-50 opacity-0"
             class="flex flex-col rounded-lg shadow-lg overflow-hidden bg-white w-3/5 h-3/5 z-10">
          <div class="p-6 border-b">
              <h2 id="modal1_label" x-ref="modal1_label">Header</h2>
          </div>
          <div class="p-6">
              Content
          </div>
        </div>
</div>

Here we set an opacity animation to the modal backdrop: it starts with the opacity-0 class and once the open property changes to true, it will replace opacity-0 with opacity-60. This transition is handled by the TailwindCSS classes transition duration-300 which should be self-explanatory, but if you want more details, check it out here. An interesting in this element is that we use Alpine's x-transition:leave to add a delay when closing the modal. This will make sure that the backdrop will start to fade out after the rest of the modal is already half way through its transition.

In the modal dialog itself, we use a more granular approach to transition it using various x-transition properties:

x-transition:enter will set the classes that will be will be attached to element the entire "enter" transition. So we use it to add the transition property, duration and easing.

x-transition:enter-start set the classes that define the initial state of the elements and x-transition:enter-end are the classes that defined the end state of the "enter" transition. Here we're saying that the modal should start with a 0% opacity and scaled down to 50% its size and should end with a 100% opacity and scaled up to its original size.

x-transition:leave-start` and x-transition:leave-end will do the opposite of the enter transitions, so we also do the opposite with the dialog box: start from original size and 100% opacity to 50% its size and 0% opacity.

And that wraps it! If you're new to Alpine.js, check out this post and I'll see you in the next one =)

]]>
<![CDATA[How to create a toast notification with Alpine.js]]> https://dberri.com/how-to-create-a-toast-notification-with-alpine-js https://dberri.com/how-to-create-a-toast-notification-with-alpine-js Sat, 29 May 2021 15:02:30 GMT Today I’ll show how to create a piece of UI that comes up very often when we want to communicate the result of an action to the user: toast notifications! For those who don’t know, this is supposed to be a small message bubble/dialog that shows up for a few moments and go away and it’s commonly used to show the user the result of an action like an Ajax request. Like in other Alpine.js tutorials, we will use TailwindCSS to style it, so here’s the basic markup:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Alpine Toast Notification</title>
    <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css” rel=“stylesheet">
    <script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.x.x/dist/alpine.min.js" defer></script>
</head>
<body>
	<div x-data="toastNotification()"></div>
	<script>
		function toastNotification() {
            return {}
		}
  </script>
<body>

You probably noticed that this time we will manage Alpine.js from the script  tag instead of doing it inline like we did previously. This is because we want to add a little more functionality to it and doing it inline would be a mess.

So, the idea is to have a small dialog that slides up from the bottom right corner of the screen and then slides down after a few seconds. The title, the message and the color will be customizable and we also need something to trigger it. I’ll just create a button for now, but you’ll see that you can improve it and use it in an Ajax request easily. Here’s the markup for the button:

<button x-on:click=“openToast()” class=“bg-purple-200 hover:bg-purple-300 text-purple-500 rounded px-6 py-4 m-4”>Open Toast</button>

With this, we know that we will need an openToast  inside our toastNotification object which will be called when clicking the button (x-on:click). If you are using it with Ajax, you would call this function after the request was finished.

The toast notification itself will have this markup:

<div
    x-show="open"
    class="w-96 p-4 rounded h-32 fixed bottom-4 right-4 transform-gpu transition-transform duration-400 ease"
    x-class="success ? 'bg-green-500' : 'bg-red-500'"
    x-transition:enter-start="translate-y-full"
    x-transition:enter-end="translate-y-0"
    x-transition:leave-start="translate-y-0"
    x-transition:leave-end="translate-y-full"
    >
    <p class="text-white"><strong x-text="title"></strong></p>
    <p class="mt-2 text-sm text-white" x-text="message"></p>
</div>

Remember that the notification and the button markup must go inside the div that declares x-data="toastNotification()" otherwise it won’t work.

Let’s go step by step:

x-show="open": This means that we will need a variable called open which will be a boolean and when it's `true`, the notification is open, and when it's false the notification will be closed.

There's nothing too interesting about the classes, but notice that we're using fixed which positions the div fixed in relation to the viewport. Then we use bottom-4 and right-4 to make it stick to the bottom right of the screen with a little margin. We also define a dynamic class using x-class: if a boolean variable called success is true, then it will be a green notification, otherwise it will be red.

Next, we use x-transition to declare that the toast will slide up when opening and slide down when closing.

Finally, we have two p tags that represent the notification title and the message. Both use variables to define those attributes and they are injected into the tags using x-text.

Now we can go back to our `toastNotification` function and defined all of these variables and functions.

function toastNotification() {
    return {
        open: false,
        title: "Toast Title",
        message: "Toast message",
        success: false,
        openToast() {
            this.open = true
            setTimeout(() => {
                this.open = false
            }, 5000)
        }
    }
}

We start with the boolean property that controls when the notificaation is open. Then we define the title and message strings which hold the data that is displayed by the notification. We then define the boolean success property which toggles the notification between green (`true`) and red (`false`). Finally we have the openToast function which sets the open property to true, opening the notification, and 5 seconds later it sets it back to false, effectivelly closing the notification.

And this is it. One could improve this little snippet by adding the possibility of changing the title, message and success properties on demand, for example after a successful update or after a failed Ajax request. Until the next post 👋

]]>
<![CDATA[The different ways to do routing in Laravel]]> https://dberri.com/the-different-ways-to-do-routing-in-laravel https://dberri.com/the-different-ways-to-do-routing-in-laravel Thu, 03 Jun 2021 13:42:01 GMT Routing in Laravel is very flexible. You can define the routes to your app in so many ways, with so many modifiers, each with a different purpose or better suited to a specific use case. Today, I want to show you a few ways that helped me and that I use very frequently while working with Laravel.

The most basic one, is the first one shown in the documentation:

use Illuminate\Support\Facades\Route;

Route::get('/greeting', function () {
    return 'Hello World';
});

This uses a closure and means that when a user hits navigates to [your app host]/greeting they will be greeted with a simple "Hello World" string. Technically, you can implement your entire application in this closure. Nothing will stop you if you try to add all your bussiness logic in there, but of course that's not very effective and if you have more routes it becomes very ugly.

When you just create a new Laravel application, it already comes with one basic route defined for / which looks like this:

use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    return view('welcome');
});

This is a more elaborate version of the first one, but in this case, it is going to return a view. This view is a Blade file located in `resources/views` which is named welcome.blade.php. So, now you can start composing views using blade and if there's not much going on in your view (e.g. it's a static page) you don't need to create a controller just to return a view.

Speaking of controllers, there are a few ways you can point your route to a controller or controller method. The default way that appears in the documentation looks like this:

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;

Route::get('/user', [UserController::class, 'index']);

When a request hits /user the method "index" in the UserController class will be called. Previously, I used to define routes with a different syntax (which as far as I know is still valid and working in Laravel 8:

use Illuminate\Support\Facades\Route;

Route::get('/user', 'UserController@index');

Notice that it's the same controller and method, but instead of an array, you pass a string declaring the controller and method separated by a @ symbol. Another thing you'll notice is that we don't need the use statement for this class because Laravel will automatically try to find that the UserController class in the App\Http\Controllers namespace.  Even though this works the same way as the previous example, I prefer the previous one because the it comes with some IDE niceties, like clicking on a class and navigating to its definition, or if you move the class file to another directory, it will warn you the use statement is not valid anymore.

Just a quick and related note, you can do the same with model relationships:

class User {
	public function books() {
    	return $this->hasMany('Book');
    }
}
use App\Book;

class User {
	public function books() {
    	return $this->hasMany(Book::class);
    }
}

Invocable controllers

Now, if your controller is a little complex and you use it for a single action with the __invoke method, you don't need to pass an array with controller and method to the route declaration, you can just pass the class as an argument, like this:

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;

Route::get('/user', UserController::class);

Resource routes

You can also do a similar route declaration with resource controllers. This type of controller is that classic "CRUD" class, where you have index, show, create, store, edit, update, and destroy methods. Then you can define the route to this controller like this:

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;

Route::resource('users', UserController::class);

This will create a route for each of the controller methods and will name them, just like if you had created them manually following this pattern:

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;

Route::get('/users', [UserController::class, 'index'])->name('users.index');
Route::get('/users/{user}', [UserController::class, 'show'])->name('users.show');
Route::get('/users/create', [UserController::class, 'create'])->name('users.create');
Route::post('/users', [UserController::class, 'store')->name('users.store');
Route::get('/users/{user}/edit', [UserController::class, 'edit'])->name('users.edit');
Route::patch('/users/{user}', [UserController::class, 'update'])->name('users.update');
Route::delete('/users/{user}', [UserController::class, 'destroy'])->name('users.destroy');

And if you don't want a few of those routes you can tell the resource method which ones you don't need:

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;

Route::resource('users', UserController::class)->except(['edit', 'udpate']);

Or the other way around, if you only need a few routes:

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;

Route::resource('users', UserController::class)->only(['index', 'show']);

And finally, if you are developing an API, you probably don't need the create and edit routes which usually navigate the user to a form. If that's the case, you can define the routes like this:

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;

Route::apiResource('users', UserController::class);

There is also a plural form of each one of these two methods, if you want to define multiple resource controllers:

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;
use App\Http\Controllers\BookController;

Route::resources([
	'users' => UserController::class
	'books' => BookController::class
]);

// or

Route::apiResources([
	'users' => UserController::class
	'books' => BookController::class
]);

One last case we can cover is nested resources. For example, if you want to update a specific book of a specific user, you could define the route as:

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserBookController;

Route::update('/users/{user}/books/{book}', [UserBookController::class, 'update']);

Or, using the resource syntax:

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserBookController;

Route::resource('users.books', UserBookController::class);

Much cleaner!

And that's it! I mean, there is a lot more to cover like middlewares, route grouping,  namespaces, Route Model Binding, rate limiting, and so on. But I'll write more about those in the future. If you're curious and want to dig deeper, I suggest you dive into Laravel's documentation. See you next time 👋

]]>
<![CDATA[Destructuring Assignment in JavaScript]]> https://dberri.com/destructuring-assignment-in-javascript https://dberri.com/destructuring-assignment-in-javascript Fri, 04 Jun 2021 14:16:04 GMT Today, I wanted to bring you one of my favorite modern JavaScript features: Destructuring Assignment! I use it almost everyday because it is so helpful in so many situations. So, let's get started. The destructuring assingment is an expression that allows you to extract values from arrays and properties from object into variables. To give you a very simple example:

const obj = { a: 1, b: 2 }
const { a } = obj
console.log(a) // 1

const arr = [1, 2]
const [firstValue, secondValue] = arr
console.log(firstValue) // 1
console.log(secondValue) // 2

In the first example, we define an object with properties "a" and "b" and in the second line we use destructuring assignment to extract property "a" into a variable with the same name. In the second example we do something similar with an array. We define a new variable called "firstValue" which holds the value in the first position in the array and "secondValue" for the value in the second position. It's the equivalent of doing:

const arr = [1, 2]
const firstValue = arr[0]
const secondValue = arr[1]
console.log(firstValue) // 1
console.log(secondValue) // 2

By default, when destructuring an object you use the name of the property, but you can also rename it in the same expression if you need:

const obj = { language: 'JavaScript' }
const { language: lang } = obj
console.log(lang) // 'JavaScript'

We extract the "language" property from the object but define a variable "lang" to hold its value.

You can also combine the destructuring assignment with the spread operator (another favorite of mine) to hold multiple values like this:

const arr = [1, 2, 3, 4]
const [firstValue, secondValue, ...rest] = arr
console.log(rest) // [3, 4]

When destructuring arrays, you have to pay attention to the order of variables. In the code snippet above, firstValue holds the value in the first position of arr, secondValue holds the value in the second position and `rest` holds all the other values. Knowing this, how can we ignore one value if we need the value in position one and the value in position three? Simple:

const arr = [1, 2, 3, 4]
const [firstValue, , thirdValue] = arr
console.log(firstValue) // 1
console.log(thirdValue) // 3

I tend to use object destructuring more often to get a nested value inside an API response object, for example:

const response = {
	data: {
        user: {
            name: "David",
        }
    }
}

// instead of
const name = response.data.user.name

// you can do
const { name } = response.data.user

Let's say you have a promise called fetchUser that returns that same response object in the code snippet above but you only need "name" of the user which is nested deep inside the response, you can do something like this:

const { data: { user: { name } } } = await fetchUser()

In this snippet, the only constant that will be declared is name which is useful when you only want part of the object returned by the function. If you want to use the same expression for function parameters, you can:

fetchUser().then(({ data: { user: { name } } }) => name)

Or you can define a function that destructures it's arguments, so you can pass the full object to the function call:

const user = {
    name: "David"
}

function printName({ name }) {
    console.log(name)
}

printName(user) // 'David'

Another cool use case for destructuring arrays is swapping variables in a one liner:

let a = 1
let b = 2

[a, b] = [b, a]

One last thing I want to show you is that you can give these variables a default value if, for example, the extracted value is undefined:

const arr = [1]
const [first, second = 2] = arr;
console.log(first) // 1
console.log(second) // 2

const obj = { a: '1' }
const { a, b = '2' } = obj
console.log(a) // '1'
console.log(b) // '2'

And that's a wrap for today. I hope you can see now how helpful this JavaScript expression is, and can incorporate in your day to day coding :) If you have any questions, reach out to me 👋

]]>
<![CDATA[How to squash commits in Git]]> https://dberri.com/how-to-squash-commits-in-git https://dberri.com/how-to-squash-commits-in-git Mon, 07 Jun 2021 16:23:19 GMT Today, I'd like to show you a quick tip that can help you during big git merges, future rebases or just to keep your branches and commit list cleaner. I'm a big fan of commiting often and with small changes. But, when inevitably merging to the main branch, I like to have only meaningful commits.

Let's say you created a feature branch based on the main branch and have many commits already, most of them still work in progress (the feature is still not fully implemented). If you use git log --pretty=oneline you would have something similar to this:

2ac7ce3 (HEAD -> feature-branch) Finishes feature implementation
8e417e1 Fixes a bug
68e88a0 Adds another thing
eea6731 wip Adds something
bde8671 (main) #123 Feature XYZ

The latest four commits are part of the feature branch and are together they represent the final feature. So, before merging it to the main branch, if you'd like to combine those commits with a meaningful message, you can run:

git rebase -i HEAD~4

Which means you will rebase interactively (the -i flag) and want to start from the current commit (HEAD) until the fourth commit from that reference, which in this example is eea6731.

That command will open up the list of commits with pick in front of the hash, like this:

pick eea6731 wip Adds something
pick 68e88a0 Adds another thing
pick 8e417e1 Fixes a bug
pick 2ac7ce3 Finishes feature implementation

# Rebase bde8672..2ac7ce3 onto bde8672 (4 commands)

Now, you will need to select the commits you want to squash into one, always from the newest to the oldest. To do that, type "i" to go into "insert mode" and replace "pick" with "s":

pick eea6731 wip Adds something
s 68e88a0 Adds another thing
s 8e417e1 Fixes a bug
s 2ac7ce3 Finishes feature implementation

# Rebase bde8672..2ac7ce3 onto bde8672 (4 commands)

You need to leave at least one commit without "s" because that's where the other commits will "fall onto". After selecting the ones you want, type esc and :wq to save the changes and leave the editor. This will open the editor again, and this time you can change the commit messages. Since this is the commit that will end up landing on master, you can be explicit about which feature you are implementing here, with a change set or whatever you think is necessary:

# This is a combination of 4 commits.
# This is the 1st commit message:

wip Adds something

# This is the commit message #2:

Adds another thing

# This is the commit message #3:

Fixes a bug

# This is the commit message #4:

Finishes feature implementation

If you want to omit a few of the messages, you can just add a # in front of the message. This will turn that message into a comment and won't show up in the commit list:

# This is a combination of 4 commits.
# This is the 1st commit message:

#wip Adds something

# This is the commit message #2:

#Adds another thing

# This is the commit message #3:

#Fixes a bug

# This is the commit message #4:

Implements Feature XYZ (issue #42)
* Adds A, B and C
* Removes X
* Fixes bug Y

When you finish, you can leave the editor the same you you did before (`esc` then :wq) and you'll have finished squashing the commits. Now, when you use git log you will notice that all the commits you squashed are gone, leaving only the ones you want with the message you want. And that's a wrap for today's post. See you on the next one 👋

]]>
<![CDATA[How to format relative dates using native JavaScript]]> https://dberri.com/relative-dates-in-native-javascript https://dberri.com/relative-dates-in-native-javascript Tue, 02 Nov 2021 08:30:00 GMT In the previous post, I showed you how you can leverage the Internationalization API to format dates using the user's locale. In this post, I'll show you how you can use the same API to create relative dates.

Relative dates are very common in applications where you want show the user the amount of time that has passed or will pass until something happens rather than  the specific date and time when something happened. For example, instead of showing that a post was published on 01/11/2021, or Nov 1st, 2021, you can show: "published yesterday" or "published 1 day ago" or if it's in the future: "this post will be published in 2 days". All of this can be achieved with the Intl API, although you might need to check browser support because this feature is relatively new.

To create the relative date formatter, you need to pass two arguments: the locale and an object with options:

const formatter = new Intl.RelativeTimeFormat('en-US', {
    numeric: 'always',
    style: 'long'
})

And to actually format a date you need to pass the number which represents the relative difference (this can be positive for the future and negative for the past) and the "unit" you want your output to be displayed ("day", "month", etc...):

formatter.format(1, "day") // "in 1 day"
formatter.format(-2, "month") // "2 months ago"
formatter.format(4, "year") // "in 4 years"
formatter.format(5, "hour") // "in 5 hours"

You can also use the option: numeric: auto for a more "natural" language:

const formatter = new Intl.RelativeTimeFormat('en-US', {
    numeric: 'auto',
})

formatter.format(1, "day") // "tomorrow"
formatter.format(-1, "day") // "yesterday"
formatter.format(-1, "month") // "last month"
formatter.format(1, "year") // "next year"

An then there's the short and narrow options for style (which can be similar depending on the locale):

let formatter = new Intl.RelativeTimeFormat('en-US', {
    style: 'short',
})

formatter.format(-2, "month") // "2 mo. ago"
formatter.format(4, "year") // "in 4 yr."

formatter = new Intl.RelativeTimeFormat('en-US', {
    style: 'narrow',
})

formatter.format(-2, "month") // "2 mo. ago"
formatter.format(4, "year") // "in 4 yr."
formatter.format(-2, "minute") // "2 min. ago"

And that's it for the relative date formatter. Of course, you still have to do some of the "heavy lifting" of coming up with the date difference, but that can be as simple as:

const diff = new Date(2021, 9, 10) - new Date();
const seconds = diff / 1000; // -1937124.765
const minutes = seconds / 60; // -5158.739066666666
const hours = minutes / 60; // -85.97898444444444

const formatter = new Intl.RelativeTimeFormat('en-US', {
    numeric: 'auto',
})

formatter.format(hours, 'hour'); // 85.979 hours ago

Which you can then round or improve as per your application's requirements.

Ok, that's it for relative date formatting using the Intl API. See you on the next post!

]]>
<![CDATA[Useful JavaScript array methods]]> https://dberri.com/useful-javascript-array-methods https://dberri.com/useful-javascript-array-methods Mon, 02 Aug 2021 12:35:14 GMT Let's walk through the array methods I find more useful and that I use on a daily basis. Each of these methods has their own use case, and even though you can achieve the same results using a combination of a for loop and a few auxiliary variables, understanding them and using them where appropriate will make your code a lot more readable and simpler.

forEach

The first one we'll talk about is the forEach. This one resembles a for loop the most, but you can call it directly on a an array and have the each item of the array passed to the callback along with the current index. In other words, it will execute the provided function once for each element. For example:

['cat', 'dog', 'fish'].forEach((animal, index) => {
    console.log([index, animal]);
})
// [0, 'cat']
// [1, 'dog']
// [2, 'fish']

You can also create the function to be executed, beforehand and pass it to the method (the same applies to all the other array methods:

function printIndexAndAnimal(index, animal) {
	console.log([index, animal]);
}

['cat', 'dog', 'fish'].forEach((animal, index) => printIndexAndAnimal(index, animal))

Also useful to note is that the forEach method (and all the other methods mentioned in this article) also passes the array itself as the third argument in the callback.

filter

This is a very handy method and I think I use it almost everyday. Like the name suggests, you can use it to filter an array, and it outputs another array with the elements that pass the test you provide in the callback function. For example, if you have an array of numbers, you can create another array with only the numbers that are greater than a threshold. Or if you have an array of objects that contain an id, you can create another array that does not contain an element with a specific id using filter. E.g.

const filteredArray = [1, 2, 3].filter(element => element > 1);

console.log(filteredArray)
// [2, 3]

const products = [
	{ id: 1, name: 'Computer' },
	{ id: 2, name: 'Pen' },
   	{ id: 3, name: 'Guitar' },
]

const filteredProducts = products.filter(product => product.id !== 2)

console.log(filteredProducts)
// [{ id: 1, name: 'Computer' }, { id: 3, name: 'Guitar' }]

find

You can use this method when you want to find one element in an array that satisfy a test function. This method will return either the first element that matches that test function otherwise it will return undefined.

const products = [
	{ id: 1, name: 'Computer' },
	{ id: 2, name: 'Pen' },
   	{ id: 3, name: 'Guitar' },
]

const pen = products.find(product => product.id === 2)

console.log(pen)
// { id: 2, name: 'Pen' }

const cat = products.find(product => product.id === 'cat')
console.log(cat)
// undefined

some

This method returns either true or false if at least one element in the array matches a provided test function. It's useful when you want to make sure that at least one of the elements in the array satisfy a condition but you don't really want to manipulate that element or filter it out of the array:

function hasOneCat(element) {
	return element === 'cat';
}

cosnt hasCat = ['fish', 'cat', 'dog'].some(animal => hasOneCat(animal))
console.log(hasCat)
// true

cosnt hasCat = ['fish', 'tiger', 'dog'].some(animal => hasOneCat(animal))
console.log(hasCat)
// false

every

This one behaves similarly to some but in order to return true, all elements in the array must satisfy the condition in the test function:

function isAboveFreezingCelsius(temperature) {
	return temperature > 0;
}

cosnt allElementsAreAboveFreezing = [10, 2, 1, 3, 5, 100].every(temp => isAboveFreezingCelsius(temp))
console.log(allElementsAreAboveFreezing)
// true

cosnt hasCat = [0, 1, 8, 10, -1].every(temp => isAboveFreezingCelsius(temp))
console.log(allElementsAreAboveFreezing)
// false

map

This is another method I use almost everyday and it's very useful when you want to manipulate items in the array and return another array in which the function has been applied. One use case could be convert every element in an array to a different format and output that to a different variable without changing the original array:

function fromFahrenheitToCelsius(temperature) {
	return (temperature - 32) / (9/5) 
}

const converted = [212, 98.6, 32, 0, -40].map(temp => fromFahrenheitToCelsius(temp))
console.log(converted)
// [100, 37, 0, -17.78, -40]

reduce

Reduce is a little more complicated than the others. You can manipulate the array in a deeper level. I like to think of it as a mix of filter and map on the same method, but this can be used for so much more. You can use reduce to create another array with filtered and converted elements or you can even use it to reduce an array of numbers into a single result. When using reduce, not only you provide a function (called reducer) but you can also provide an initial value. Reduce's callback provides the current value in the itereation and an accumulator. The result of your function is assigned to the accumulator which carries on to the next iteration.

Let's start with a simple example, summing an array:

cosnt initialValue = 0;
cosnt result = [1, 2, 3, 4, 5].reduce((accumulator, currentValue) => {
	accumulator += currentValue
    return accumulator;
}, initialValue);
console.log(result);
// 15

Now, on to a more complex one. Let's split an array into two groups removing duplicates using reduce:

const originalArray = [2, 2, 43, 5, 11, 7, 9, 4, 20, 0, 4];
const initialValue = { lessThanTen: [], greaterThanTen };

function reducer(acc, value) {
	if (acc.lessThanTen.includes(value) || acc.greaterThanTen.includes(value)) {
    	return acc;
    }

	if (value < 10) {
    	acc.lessThanTen.push(value);
    } else {
    	acc.greaterThanTen.push(value);
    }
    return acc;
}

const result = originalArray.reduce((acc, value) => reducer(acc, value))
console.log(result)
// { lessThanTen: [2, 5, 7, 9, 4, 0], greaterThanTen: [43, 11, 20] }

I hope this article gave you a better idea of how all these methods work and after some practice you will have more tools on your belt and can help you improve your code's readability and performance. The best part about these methods is that besides the language syntax, the logic works the same in other languages, not only JavaScript :)

]]>
<![CDATA[Formatting dates in JavaScript using the user's locale]]> https://dberri.com/formatting-dates-in-javascript-using-the-users-locale https://dberri.com/formatting-dates-in-javascript-using-the-users-locale Mon, 01 Nov 2021 12:12:42 GMT Currently, there are multiple libraries to format dates in JavaScript. I used moment.js for a long time, but the bundle size was always a turn down for me. Then I switched to date-fns, which has a simple API and supports tree-shaking, and I have one project where I'm using luxon. They all work fine and have their use-cases, but in my opinion some times we end up bringing external libraries into our projects without really needing them, or without checking for a native approach first. I am guilty of that 😉 but lately I've tried to always search for a native approach first, before bringing in a dependency, making sure to assess whether the bigger bundle size is worth it or not.

So, let's get into it. What I want to show you is a simple use case where we need to format dates differently depending on user locale. In Brazil, the most common date format is DD/MM/YYYY or DD/MM/YY where D = Day, M = Month and Y= Year. In the US, day and month switch places and sometimes you don't add the leading zero and in Germany, it's common to use dots instead of slashes as dividers (DD.MM.YYYY). To make sure we account for all these formats, we can leverage ECMAScript Internationalization API in our application.

Let me show you an example:

const myDate = new Date(2021, 10, 1);
let formatter = new Intl.DateTimeFormat('en-US');
console.log(formatter.format(myDate)) // "11/1/2021"

formatter = new Intl.DateTimeFormat('pt-BR');
console.log(formatter.format(myDate)) // "01/11/2021"

formatter = new Intl.DateTimeFormat('de-DE');
console.log(formatter.format(myDate)) // "1.11.2021"

You can also do it with a one-liner if you are not going to use the formatter later:

const myDate = new Date(2021, 10, 1);
console.log(new Intl.DateTimeFormat('pt-BR').format(myDate)) // "01/11/2021"

Now, instead of hard coding the language code, you can either use the user's preferred language (from the browser) or your the language the user set for your website:

const myDate = new Date(2021, 10, 1);
const langCode = document.documentElement.lang || navigator.language;
const formatter = new Intl.DateTimeFormat(langCode);
console.log(formatter.format(myDate)) // "01/11/2021"

You can also specify options for the date format:

const myDate = new Date(2021, 10, 1);
const formattedDate = new Intl.DateTimeFormat('en-US', {
    dateStyle: 'short',
    timeStyle: 'short'
}).format(myDate);
console.log(formattedDate) // "11/1/21, 12:00 AM"

const formattedDateMedium = new Intl.DateTimeFormat('en-US', {
    dateStyle: 'medium',
    timeStyle: 'medium'
}).format(myDate);
console.log(formattedDateMedium) // "Nov 1, 2021, 12:00:00 AM"

const formattedDateLong = new Intl.DateTimeFormat('en-US', {
    dateStyle: 'long',
    timeStyle: 'long'
}).format(myDate);
console.log(formattedDateLong) // "November 1, 2021 at 12:00:00 AM GMT-3"

const formattedDateFull = new Intl.DateTimeFormat('en-US', {
    dateStyle: 'full',
    timeStyle: 'full'
}).format(myDate);
console.log(formattedDateFull) // "Monday, November 1, 2021 at 12:00:00 AM Brasilia Standard Time"

The options are very flexible: you can set different formats for calendar, week, year (2-digit or numeric), month (numeric, 2-digit, long, short and narrow), weekday, wheter to use the 12-hour time, timezone. You can checkout the full list here.

I hope that after reading this post you will be better equipped to make a decision on whether or not you need an external library for handling date formatting. See you on the next post!

]]>
<![CDATA[Formatting numbers in JavaScript]]> https://dberri.com/formatting-numbers-in-javascript https://dberri.com/formatting-numbers-in-javascript Wed, 03 Nov 2021 09:00:00 GMT In the last couple of posts, I showed you how you can format dates and relative dates using the native Internationalization API. Today, I'll we're going to format regular numbers using the same API. Yes, Intl is not only used for date formatting, there's a whole range of use cases including numbers, lists and plurals.

So, when I say we are going to format numbers, what I mean is: numbers are not represented the same way in different cultures. For example, in Brazil we the most common way to represent numbers is like so: 1.234.567,89. The comma is the decimal separator and the period is the thousands separators. In other cultures those are switched, or the thousands separator is not used. If your application is served in other locales, you can use the Intl API to resolve these for you and you don't even need to plug in another dependency.

Let's see how we can use it:

const myNumber = 1234657.89;

const formatter = new Intl.NumberFormat('pt-BR');

console.log(formatter.format(myNumber)); // 1.234.567,89

const formatterUS = new Intl.NumberFormat('en-US');

console.log(formatter.format(myNumber)); // 1,234,567.89

If you've read the previous posts, you'll probably be familiar with the syntax. You first instantiate the formatter with the locale and then pass the parameters you want to format. Of course, you can also pass an options object to the formatter if you want to further customize the number format. Let check out a few options:

const myNumber = 1234567.89;

let formatter = new Intl.NumberFormat('pt-BR', {
    style: 'currency',
    currency: 'BRL'
});
console.log(formatter.format(myNumber)); // R$ 1.234.567,89

formatter = new Intl.NumberFormat('en-US', {
    style: 'currency',
    currency: 'USD'
});
console.log(formatter.format(myNumber)); // $ 1,234,567.89

formatter = new Intl.NumberFormat('en-US', {
    style: 'currency',
    currency: 'USD',
    currencyDisplay: 'code' // default: 'symbol'
});
console.log(formatter.format(myNumber)); // USD 1,234,567.89

formatter = new Intl.NumberFormat('en-US', {
    style: 'currency',
    currency: 'USD',
    currencyDisplay: 'name'
});
console.log(formatter.format(myNumber)); // 1,234,567.89 US dollars

There are also options to customize the way it displays negative values, for example instead of using $ -1.00 it can display ($1.00):

const myNumber = -1234567.89; // notice the negative sign
const formatter = new Intl.NumberFormat('en-US', {
    style: 'currency',
    currency: 'USD',
    currencySign: 'accounting'
});
console.log(formatter.format(myNumber)); // ($1,234,567.89)

And, if you are working with currencies or percentages, the number of fraction digits is already set using  ISO 4217, but if you're working with regular numbers, you can set that option too:

const myNumber = 1234567.00;
formatter = new Intl.NumberFormat('en-US');
console.log(formatter.format(myNumber)); // 1,234,567

formatter = new Intl.NumberFormat('en-US', {
    minimumFractionDigits: 2
});
console.log(formatter.format(myNumber)); // 1,234,567.00

formatter = new Intl.NumberFormat('en-US', {
    maximumFractionDigits: 3
});
const myNumber2 = 1234567.891011
console.log(formatter.format(myNumber2)); // 1,234,567.891

You can customize the notation as well:

formatter = new Intl.NumberFormat('en-US', {
    style: 'currency',
    currency: 'USD',
    notation: 'standard' // default
});
console.log(formatter.format(myNumber)); // $1,234,567.89

formatter = new Intl.NumberFormat('en-US', {
    style: 'currency',
    currency: 'USD',
    notation: 'scientific'
});
console.log(formatter.format(myNumber)); // $1,23E6

formatter = new Intl.NumberFormat('en-US', {
    style: 'currency',
    currency: 'USD',
    notation: 'engineering'
});
console.log(formatter.format(myNumber)); // $1,23E6

formatter = new Intl.NumberFormat('en-US', {
    style: 'currency',
    currency: 'USD',
    notation: 'compact'
});
console.log(formatter.format(myNumber)); // $1.2M

There are still plenty of options we did not cover but I think the most popular ones are those in the examples, but if you can check out the full list here. And this is it for this post. See you on the next one!

]]>
<![CDATA[How this pattern made me write reusable Vue components with little effort]]> https://dberri.com/container-presentational-pattern-in-vue https://dberri.com/container-presentational-pattern-in-vue Sat, 07 May 2022 18:54:37 GMT A long time ago, when I started to learn Vue.js, I reached out to people who were experienced in the framework to ask for tips and get directions on what to learn and how to structure code. One tip that stuck with me was: "Always separate the logic from the presentational component”. I thought, well that seems reasonable, I'll try that. But to be honest, at that time, I did not actually understand what they meant specifically. So, with time, I wrote more and more Vue code, and got to write large SPAs until I finally understood why people told me to separate logic from the presentational layer, and most importantly, I found a great pattern that solves that problem.

Let's say you have a Vue SFC (single file component) which sends a request to the server, stores the items in state (like VueX or Pinia) and then renders a list of items. More experienced developers might already see the problem just by reading that sentence, but I took me some time. I started to have problems writing components like this because when you create unit tests for these components you have to mock so many things: the request to the server, the response, the state... the same thing happens if you want to add the component to a component library like Storybook. It's a pain. Now, if the component only take the list of items to render, render them and emit events, your life becomes a lot easier because you can test only the interface of the component i.e. if it renders x when you pass x as a prop and it emits event y when you interact in some way with the component.

The same thing happens with the logic you took away from the presentational component. When you want to test it, you can test just the bits that are important to the logic. You don't need to worry about how or who is going to render what. You just care about the functions and the flow of data.

Did I peak your interest? Ok, great! Let's see some code. I created a repo with a starter project so that you can follow along, you can clone the repo here.

To reach the point of that starter project you can run npm init vue@latest and when asked to “Add Pinia for state management” you select "Yes". After it finishes, go to the project directory and install the dependencies (npm install) and then you can run the project (npm run dev). Even though this is a Vue 3 example, I already applied this same pattern in Vue 2 and it works the same (and it will probably work the same in any other frontend framework).

If you cloned the repository, open it in your code editor and you should see a very simple example:

// src/components/PetList.vue
<script setup>
import { storeToRefs } from 'pinia'
import { onMounted } from 'vue';
import { usePets } from '../stores/pets'

const store = usePets();
const { pets } = storeToRefs(store)

onMounted(() => {
    store.fetchCats();
})

const emit = defineEmits(['click']);

function handleClick(index) {
    emit('click', index);
}

defineExpose({
    pets,
    handleClick
})
</script>

<template>
  <ul>
      <li v-for="(pet, i) in pets">
          <button @click="handleClick(i)">
              <img :src="pet" />
          </button>
      </li>
  </ul>
</template>

First, don't worry about the template style or anything like that. Let's focus on the script tag first:

the App.vue file only renders a PetList component and this Vue component basically renders an image list, but in the script part, it sends a request to an API through Pinia when the component is mounted, which returns a list of cat images and uses the state to get this list and finally expose them to the template to render.

This is the store:

// src/stores/pets.js
import { defineStore } from 'pinia';

export const usePets = defineStore('pets', {
    state: () => {
        return {
            pets: [],
        };
    },

    actions: {
        async fetchCats() {
            try {
                const cats = await fetch(
                    '<https://api.thecatapi.com/v1/images/search?limit=10&order=DESC>'
                ).then(res => res.json());
                this.pets = cats.map(cat => cat.url);
            } catch (e) {
                //
            }
        },
		}
})

What happens if later the business wants to render another list but this time with images of dogs?

Well, one option would be to copy the entire component, replace the logic to fetch and render dogs and call it a day. You still would have problems to test the component and now if something changes in the template, you have to change in both components. You won't forget it, right?

Another option would be to pass a prop to the component which works as a flag: catOrDog and based on this prop you could use if/else everywhere to render cat or dog images. You keep the template in one place but honestly the script might becomes very messy and full of “this vs that” paths.

Enter "Container/Presentational pattern" 🎉

As its name suggest, this pattern will allow us to separate the presentational component from the business logic, encouraging separation of concerns. The container can fetch, handle and modify the data that will be shown to the user. Their responsibility is to pass that data (which they contain) to a presentational component. The presentational component will actually display (present) that data to the user.

Let's refactor this code to use containers for the logic and keep the presentational component (the template) very clean and with a clear interface of props and events:

// src/components/PetList.vue
<script setup>
const props = defineProps({
  pets: {
    type: Array,
    default: () => [],
  }
});

const emit = defineEmits(['click']);

function handleClick(index) {
    emit('click', index);
}

defineExpose({
    pets: props.pets,
    handleClick
})
</script>

<template>
  <ul class="pet-list">
      <li v-for="(pet, i) in pets">
          <button @click="handleClick(i)" class="pet-list__button">
              <img :src="pet" class="pet-list__img" />
          </button>
      </li>
  </ul>
</template>

Notice that the template part almost didn't change. The script part on the other hand is a lot simpler: you define props and events that the component might emit and that's it. If your pass cat images it will render cat images, if you pass dog images it will render dog images. If in the future the business decides to render a list for an entire zoo, you're covered. Component unit tests become a breeze and you can add the component to Storybook or other component libraries very easily.

Now, let's create a container for the CatList:

// src/components/CatList.container.js
import { storeToRefs } from 'pinia';
import { onMounted, h } from 'vue';
import { usePets } from '../stores/pets';
import PetList from './PetList.vue';

export default {
    setup() {
        const store = usePets();
        const { cats } = storeToRefs(store);

        onMounted(() => {
            store.fetchCats();
        });

        function handleOnClick(index) {
            console.log('Clicked on cat picture #' + index);
        }

        return () =>
            h(PetList, {
                pets: cats.value,
                onClick: handleOnClick,
            });
    },
};

This container is responsible for fetching the cat images when it is mounted, get the images from state and render the PetList SFC component passing the list as a prop. It also listens for events that the PetList component might emit and handles them.

I like to use a convention for naming containers: [Name of the component].container.js so I know what to expect when I'm working on these files.

Now, in your App.vue, instead of importing PetList.vue you will have to import CatList.container.js and render that just like you render a regular Vue component. For any purposes, it is a regular Vue component, but instead of rendering a template, it returns an h function which actually renders the component.

Now, let's create the DogList container:

// src/components/DogList.container.js
import { storeToRefs } from 'pinia';
import { onMounted, h } from 'vue';
import { usePets } from '../stores/pets';
import PetList from './PetList.vue';

export default {
    setup() {
        const store = usePets();
        const { dogs } = storeToRefs(store);

        onMounted(() => {
            store.fetchDogs();
        });

        function handleOnClick(index) {
            console.log('Clicked on dog picture #' + index);
        }

        return () =>
            h(PetList, {
                pets: dogs.value,
                onClick: handleOnClick,
            });
    },
};

Notice that this almost identical to CatList.container but instead of fetchCats it calls fetchDogs in the onMountedhook. This is just a simple example, in the wild the logic inside these containers can vary a lot but the important part is that your PetList.vue is still the same. It still accepts the same props and as long as other containers respect this interface, it should render a nice list of images.

That's it for today! I hope that with this article you now have a better understanding of this pattern and can take a "shortcut" with this knowledge so you don't go into the same pitfalls I went :)

]]>
<![CDATA[The 11 books I read in 2021]]> https://dberri.com/the-11-books-i-read-in-2021 https://dberri.com/the-11-books-i-read-in-2021 Sat, 07 May 2022 18:54:30 GMT I decided to write this post to look back and reflect on the books I’ve read in the past year and also to recommend the ones I liked reading. Before I started my career in software development I used to read a lot. I was a bookworm. Most of the reading was done in my commute to college or high school classes (or during the boring classesđŸ€·đŸ»). But after I started my career, since it’s not what I studied in college, I knew I had a lot to learn in web and software development, so I read less and less in favor of studying software development and I started to miss it. So for the past few years I added “reading” as my New Years resolutions, specifically to read at least one book a month which I realized this year that this is not a smart goal because I started to optimize short books just to get done with the goal and steered away from longer books which are not necessarily bad, sometimes it is quite the contrary.

Anyway, I managed to read eleven books cover to cover. I try to mix the genres I read during the year to not get bored, otherwise I’d probably only stay with the thrillers.

Here is the list, not in the order I’ve read them, categorized by “genre” (in quotes because this is how I categorize them in my head:

Fiction

The Fireman - Joe Hill

I love to read books by Joe Hill. I get so immersed in the story that I can just read hours without realizing it. Stephen King has the same effect on me. This book was no exception. I picked this up in January, and the premisse caught my attention: “a worldwide pandemic of spontaneous combustion that threatens to reduce civilization to ashes”. It was a great book in my opinion.

Red Mars - Kim Stanley Robinson

This one was in my list for a few years before I finally picked it up this year. It was
 underwhelming. Here’s the premisse: “For eons, sandstorms have swept the desolate landscape. For centuries, Mars has beckoned humans to conquer its hostile climate. Now, in 2026, a group of 100 colonists is about to fulfill that destiny.” I think terraforming is a very interesting concept and that’s where I thought this book was going to focus more, but turns out it was very slow and the terraforming aspect of it was only the background for political intrigues. It is not a bad book, don’t get me wrong, I think I was just expecting something different. It’s the first book of a trilogy, but it didn’t entice me to pick up the next ones.

Rendezvous with Rama - Arthur C. Clark

This book is also set in space! Here’s the gist of it: astronomers found a humongous object (dubbed Rama) is hurtling through the solar system at inconceivable speed and a probe confirms it is not a natural object, but a spacecraft! So, space explorers prepare to land in Rama and discover what it really is. In my opinion it is a very fast paced book, and I think it could have explored some aspects a little bit more, but it was a good book overall.

Nonfiction but science

Astrophysics for People in a Hurry - Neil DeGrasse Tyson

This is a very good book to leave you wondering about our universe. Tyson explains many questions like “What is the nature of space and time? How do we fit within the universe? How does the universe fit within us?”

The Drunkard’s Walk - Leonard Mlodinow

This book is also about one of the topics I’m most interested in: randomness. And it also explains how it affects our daily lives. It is a very interesting read, brushing over the study of randomness, how it started and why. It also reminded me a little of Think Fast and Slow but this one feels a lot more technical and historical.

Soft skill improvements

To Sell Is Human - Daniel H. Pink

I reckon that selling is one of the most important topics for an entrepreneur. You can build the “best” product but don’t think it will sell itself. With that in mind, I decided to start learning more about this. This books was not that helpful in my opinion, there are many popular topics so I didn’t feel like I really learned anything new.

Steal like an artist - Austin Klein

This one I picked up almost randomly when visiting a bookstore. Yeah, even though I read most of my books in a Kindle device, I still love to wander around a nice bookstore. So, I found this book and thought it was very interesting and focused on improving one’s creativity. I’m very interested on this topic because as a programmer and entrepreneur, creativity is one of the pillars of the profession. Anyway, I’ve read this book in one sitting, it’s pretty short and there are many illustrations. I feel like the book is focused on making you increase your references and be open to different things that are not usually in your daily routine to spark creativity. Good stuff.

Ideology

What is Seen and What is Not Seen - Frédéric Bastiat

This is a great book, I didn’t learn anything new from it, but helped me organize and clarify some ideas I had around what happens when the state (or other entities) redirects resources by enforcement of law. Usually something not obvious and sometimes more important is impacted and the results are not immediate but will be felt in the long term. This book has the famous story of the broken window, that goes more or less like this: the price paid to fix a broken window is good business for the glass store but is ultimately bad for society as the resources to fix the broken window could have been invested in something more useful.

Liberalism - Adam Smith

This book is part of a larger collection from Adam Smith (The Wealth of Nations) and contains only the Theory of Price Definition in the Capitalist System and the concept of the Invisible Hand. In his own words: "By pursuing his own interest he frequently promotes that of the society more effectually than when he really intends to promote it". The author demonstrates that each individual, doing what is specific to them the best way to increase the productivity and the wealth of a nation. The concept of the invisible hand is very interesting and states that supply and demand uses prices and profits as signals to the producers what society requires. Producers want profits, so they produce what society requires, at the correct quantity to stay in a competitive price.

Anatomy of the State - Murray N. Rothbard

This book is what makes Murray Rothbard be known as state's greatest enemy. It portrays different scenarios where the state ends freedom, destroys civilization and threatens all lives, property and social well being. As the title suggests, jsust like in an anatomy lesson, the author shows why the state is not the benevolent being that helps the poor and guides our civilization but a parasite.

Civil Disobedience - Henry David Thoreau

To finish off, this book calls for citizens to put their values above their government. We know that we must follow the law, but what do you do when law is unfair? Such as it was so many times in the history of governments. This book is a call to action for everyone to refuse to participate in, or encourage an unjust institution.

]]>
<![CDATA[Build validation that you can be proud of in Laravel]]> https://dberri.com/build-validation-that-you-can-be-proud-of-in-laravel https://dberri.com/build-validation-that-you-can-be-proud-of-in-laravel Sun, 08 May 2022 13:22:00 GMT Today I wanted to bring you the topic of validation in the backend using Laravel. For me, this is part of what makes this framework so elegant and fluent. Even though it allows you validate your input data using multiple approaches, it gives you guard rails to ensure that it will work well and will stay organized as your application grows.

Let's jump into the code. I created a starter project that you can use to follow along. Just clone the repo from here. It's a simple CRUD project with a Rest API to show, store, update and remove bird sightings from the application. Currently it doesn't have any validation at all. Whatever it receives from the clients, it will try to store or update in the database, which is can be very bad even if you have validation on the client code. Let's start fixing that with Form Requests.

Form Requests

To be honest, if you have only a couple of rules, you might not need a Form Request, you can just validate the request inside the controller method like:

// app/Http/Controllers/BurdSightingController.php

public function create(Request $request)
{
    $request->validate([
        'common_name' => 'required|string|max:255',
    ]);

    $sighting = BirdSighting::create($request->validated());
    return response()->json($sighting, 201);
}

But if you want a cleaner interface with the controller and a special place where all the validation happens, then you can create a FormRequest using an artisan command:

php artisan make:request CreateBirdSightingRequest

This will create the following file:

// app/Http/Requests/CreateBirdSightingRequest.php

class CreateBirdSightingRequest extends FormRequest
{
    public function authorize()
    {
        return false;
    }

    public function rules()
    {
        return [
            //
        ];
    }
}

The authorize method can be used to determined if the current user is authorized to perform that operation, so you can, for example, make use of Gates and Policies or even simpler rules like if the user has a specific property. Make sure to return a boolean in that method: true means that the user is authorized and false means the user is not authorized and will respond with a 403 HTTP status response.

The rules method is where the actual validation rules go. Laravel has dozens of built-in validation rules to add here. So, in our case, we want to validate fields in order to create a bird sighting:

    public function rules()
    {
        return [
            'common_name' => 'required|string|max:255',
            'species' => 'required|string|max:255',
            'sighted_at' => 'required|date',
            'quantity' => 'nullable|integer|min:1',
            'latitude' => 'required|numeric',
						'longitude' => ['required', 'numeric'],
        ];
    }

You will notice that for longitude I used a different syntax. Laravel supports both strings with rules a separated by |and arrays with rules are separated by commas. As far as I know, the string syntax can only be used with built-in rules. If you create a custom validation rule (and I'll show you how) then you have to use the array syntax.

Custom validation messages

Form Requests also allow you to add custom validation messages for each field and rule. TO do that you need to override the messages method in the Form Request you created, for example:

    public function messages()
    {
        return [
            'common_name.required' => 'A common name for the bird you saw is required',
            'sighted_at.required' => 'An approximate date and time for the sighting is required',
        ];
    }

These messages will override the default validation message for the required rule which you can find in resources/lang/validation.php.

Finally, you have to use this Form Request in your method, so go back to the controller and replace Request $requestwith CreateBirdSightingRequest $request

    public function create(CreateBirdSightingRequest $request)
    {
        $sighting = BirdSighting::create($request->validated());
        return response()->json($sighting, 201);
    }

You will also notice that we replaced $request->all() with $request->validated() to retrieve the validated fields from the request.

Now if you send data to that endpoint and it does not conform to the rules you added, you'll get a 422 HTTP status response with the error messages for each field.

Organizing rules

Now you will need another form request for the update method which might have a different set of rules and speaking of set of rules, when the application starts to grow and rules start to get too "scattered" in the form request, we can create rule classes that make those sets reusable and more legible. I like to create a Rules directory inside app/ and create a class that will provide the rules I need:

// app/BirdSightingRules.php

class BirdSightingRules
{
    public static function birdRules()
    {
        return [
            'common_name' => 'required|string|max:255',
            'species' => 'required|string|max:255',
            'quantity' => 'nullable|integer|min:1',
        ];
    }

    public static function locationRules()
    {
        return [
            'sighted_at' => 'required|date',
            'latitude' => 'required|numeric',
            'longitude' => ['required', 'numeric'],
        ];
    }

    public static function updateRules()
    {
        return [
            // 
        ];
    }
}

Then back in the form request:

    public function rules()
    {
        return array_merge(
            BirdSightingRules::birdRules(),
            BirdSightingRules::locationRules()
        );
    }

Custom rules

Laravel has so many built-in rules that it might take some time for you to need to build a custom rule, but sometimes your application might just have a specific trait that requires a custom validation rule. If that's the case, artisan has you covered:

php artisan make:rule SightedInMarch

It will create a file under app/Rules which contains a custom rule with the following methods:

// app/Rules/SightedInMarch.php

class SightedInMarch implements Rule
{
    public function passes($attribute, $value)
    {
        //
    }

    public function message()
    {
        return 'The validation error message.';
    }
}

Inside the passes method you can create your custom rule which needs to return a boolean and inside message you just need to return a string with an explanation of why it failed the validation:

    public function passes($attribute, $value)
    {
        return preg_match('/^[0-9]{4}-03-[0-9]{2}/', $value);
    }

    public function message()
    {
        return 'Why are you watching birds in March?';
    }

Then you go back to you set of rules and use this custom rule with the sighted_at attribute:

// app/Rules/BirdSightingRules.php

    public static function locationRules()
    {
        return [
            'sighted_at' => ['required', 'date', new SightedInMarch],
            'latitude' => 'required|numeric',
            'longitude' => ['required', 'numeric'],
        ];
    }

Now all form requests that use locationRules will automatically validate the sighted_at attribute using that new custom rule. And with that, we wrap another article. See you on the next one!

]]>
<![CDATA[So, let's retry that?]]> https://dberri.com/so-lets-retry-that https://dberri.com/so-lets-retry-that Sat, 24 Sep 2022 13:08:35 GMT A few weeks ago, I had to implement some code that would need to retry an operation with different parameters if it failed on the first run but only if it did with a specific exception. I thought about it for a few minutes and before I tried to implement it myself, I decided to search Laravel's documentation to see if there was a helper or something that I could use. Turns out there is a helper called: retry. Yes, it was exactly what I was looking for and more.

According to the docs, retry accepts the number of attempts, the callback where your implementation goes and a third (optional) parameter that can either be a number of milliseconds or a closure to change the time it will wait before the next attempt. It also accepts a fourth (also optional) parameter: a closure that returns the condition in which the method should retry. For example, if you want to retry only if a specific exception was thrown.

If the callback you implement throws an exception, the retry method will catch that and if it still has more attempts, it will retry, otherwise it will throw that exception. On the other hand, if your callback is successful, the retry method will return the value your callback returned. Very straightforward, huh?

Ok, now that you have an overview of how it works, let's see some code. As an example, let's create a function that gives you three chances of guessing a random number:

function guessTheNumber($num) {
	$value = rand(0, 10);
	if ($value === $num) {
	    return true;
    }
    throw new \Exception('You guessed the wrong number!');
}

function tryYourLuck() {
	return retry(3, function() {
    	return guessTheNumber(5);
    }, 100);
}

The first function (guessTheNumber) accepts a value and compares it to a random one. If they are equal, return true, otherwise throw an exception. It is just a silly example to show how retry works. The second function (tryYourLuck) is where we call guessTheNumber with our guessed value (5) and since we have three chances, we call retry with 3 as the first parameter. Just to show you how it works, I'm also passing a third parameter to retry which is the amount of milliseconds the function should wait before retrying. Now, if we call tryYourLuck and it guessTheNumber returns true in any of the three attempts, tryYourLuck will also return true. But, if it retries three times and all of them threw an exception, then tryYourLuck will throw the last exception.

The feature that really helped me was the option to pass a closure as the fourth argument and use that to decide if we the method should retry. The closure accepts the exception as its first parameter, so we can do something like:

class MyException extends Exception { }

function guessTheNumber($num) {
	$value = rand(0, 10);
	if ($value === $num) {
	    return true;
    }
    throw new MyException('You guessed the wrong number!');
}

function tryYourLuck() {
	return retry(3, function() {
    	return guessTheNumber(5);
    }, 100, function($exception) {
    	return $exception instanceof MyException;
    });
}

Here we are telling the retry method that it should only retry if the exception if caught was MyException. If it catches any other exception, it should not retry at all.

And with that, I wrap up this blog post. Until next time!

]]>