<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: RD</title>
    <description>The latest articles on DEV Community by RD (@raevilman).</description>
    <link>https://dev.to/raevilman</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2114%2F3ca87c1e-fb40-4914-99f7-76a568935379.png</url>
      <title>DEV Community: RD</title>
      <link>https://dev.to/raevilman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/raevilman"/>
    <language>en</language>
    <item>
      <title>Spring Reusable Pagination and Sorting</title>
      <dc:creator>RD</dc:creator>
      <pubDate>Sat, 28 Jun 2025 05:57:33 +0000</pubDate>
      <link>https://dev.to/raevilman/spring-reusable-pagination-and-sorting-17ki</link>
      <guid>https://dev.to/raevilman/spring-reusable-pagination-and-sorting-17ki</guid>
      <description>&lt;p&gt;Ever wish you could add pagination and sorting to your REST APIs with minimal effort? &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://central.sonatype.com/artifact/com.therdnotes/spring-page-sort-endpoints/overview" rel="noopener noreferrer"&gt;Below guide has been released as a library on Maven Central here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Imagine adding a single annotation to your controller methods and having all the query parameter parsing, validation, and error handling handled automatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@GetMapping&lt;/span&gt;
&lt;span class="nd"&gt;@PageSortConfig&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;defaultSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;maxSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;validSortFields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"createdAt"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"updatedAt"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FileDto&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;listFiles&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PageSortRequest&lt;/span&gt; &lt;span class="n"&gt;pageSortRequest&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Use pageSortRequest values for your database queries&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this article, I'll show you how to build such a framework from scratch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Index
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create the PageSortRequest Model&lt;/li&gt;
&lt;li&gt;Create the Configuration Annotation&lt;/li&gt;
&lt;li&gt;Implement the Argument Resolver&lt;/li&gt;
&lt;li&gt;Register the Argument Resolver&lt;/li&gt;
&lt;li&gt;Using the Framework&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 1: Create the PageSortRequest Model
&lt;/h2&gt;

&lt;p&gt;First, we need a class to hold pagination and sorting parameters. We'll use Java's record feature for an immutable representation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;PageSortRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;sortBy&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;sortDir&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="no"&gt;PAGE_DEFAULT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="no"&gt;SIZE_DEFAULT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="no"&gt;SORT_BY_DEFAULT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"createdAt"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="no"&gt;SORT_DIR_DEFAULT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"asc"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Compact constructor with defaults&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;PageSortRequest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Default values&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;PAGE_DEFAULT&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;SIZE_DEFAULT&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sortBy&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;sortBy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isBlank&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="n"&gt;sortBy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;SORT_BY_DEFAULT&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sortDir&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;sortDir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isBlank&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;isValidSortDirection&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sortDir&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;sortDir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;SORT_DIR_DEFAULT&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;sortDir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sortDir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toLowerCase&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isValidSortDirection&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"asc"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equalsIgnoreCase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s"&gt;"desc"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equalsIgnoreCase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Utility methods&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isAscending&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"asc"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equalsIgnoreCase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sortDir&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getSqlSortDirection&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;isAscending&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"ASC"&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"DESC"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This record encapsulates four common parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;page&lt;/code&gt; - the page number (zero-based)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;size&lt;/code&gt; - items per page&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sortBy&lt;/code&gt; - field name to sort by&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sortDir&lt;/code&gt; - sort direction ("asc" or "desc")&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The compact constructor provides default values and normalization, so we don't have to handle null values elsewhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Create the Configuration Annotation
&lt;/h2&gt;

&lt;p&gt;Next, we need an annotation to configure pagination and sorting behavior on a per-endpoint basis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Target&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ElementType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;METHOD&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Retention&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RetentionPolicy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;RUNTIME&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nd"&gt;@interface&lt;/span&gt; &lt;span class="nc"&gt;PageSortConfig&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * Minimum page number (default: 0)
     */&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;minPage&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="cm"&gt;/**
     * Default page number when not specified or invalid (default: 0)
     */&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;defaultPage&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="cm"&gt;/**
     * Minimum size/limit per page (default: 1)
     */&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;minSize&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="cm"&gt;/**
     * Maximum size/limit per page (default: 100)
     */&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;maxSize&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="cm"&gt;/**
     * Default page size when not specified or invalid (default: 25)
     */&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;defaultSize&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="cm"&gt;/**
     * Valid field names that can be used for sorting
     */&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;validSortFields&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="o"&gt;{};&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This annotation lets developers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set boundaries for page size&lt;/li&gt;
&lt;li&gt;Define default values&lt;/li&gt;
&lt;li&gt;List allowed sort fields to prevent SQL injection attacks&lt;/li&gt;
&lt;li&gt;Configure each endpoint individually&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 3: Implement the Argument Resolver
&lt;/h2&gt;

&lt;p&gt;Now we need to create a class that implements Spring's &lt;code&gt;HandlerMethodArgumentResolver&lt;/code&gt; interface to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Extract query parameters&lt;/li&gt;
&lt;li&gt;Apply validation rules&lt;/li&gt;
&lt;li&gt;Create the &lt;code&gt;PageSortRequest&lt;/code&gt; object
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="nd"&gt;@Slf4j&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PageSortArgumentResolver&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;HandlerMethodArgumentResolver&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;supportsParameter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MethodParameter&lt;/span&gt; &lt;span class="n"&gt;parameter&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;parameter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getParameterType&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PageSortRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="nf"&gt;resolveArgument&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MethodParameter&lt;/span&gt; &lt;span class="n"&gt;parameter&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ModelAndViewContainer&lt;/span&gt; &lt;span class="n"&gt;mavContainer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                  &lt;span class="nc"&gt;NativeWebRequest&lt;/span&gt; &lt;span class="n"&gt;webRequest&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;WebDataBinderFactory&lt;/span&gt; &lt;span class="n"&gt;binderFactory&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Extract annotation from method if present&lt;/span&gt;
        &lt;span class="nc"&gt;Method&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parameter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMethod&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;PageSortConfig&lt;/span&gt; &lt;span class="n"&gt;pageSortConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;
                &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAnnotation&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PageSortConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Get default values from annotation&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;defaultPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pageSortConfig&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;pageSortConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;defaultPage&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;defaultSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pageSortConfig&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;pageSortConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;defaultSize&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Parse request parameters&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;pageParam&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;webRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getParameter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"page"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;sizeParam&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;webRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getParameter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"size"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;sortByParam&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;webRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getParameter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sortBy"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;sortDirParam&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;webRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getParameter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sortDir"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;defaultPage&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;defaultSize&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pageParam&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;pageParam&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parseInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pageParam&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NumberFormatException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Use default&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sizeParam&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;sizeParam&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parseInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sizeParam&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NumberFormatException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Use default&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Apply validation if the annotation is present&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pageSortConfig&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;validatePage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pageSortConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;minPage&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="n"&gt;validateSize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pageSortConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;minSize&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;pageSortConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;maxSize&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="n"&gt;validateSortBy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sortByParam&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pageSortConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validSortFields&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="n"&gt;validateSortDir&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sortDirParam&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PageSortRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sortByParam&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sortDirParam&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;validatePage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;minPage&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;minPage&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ResponseStatusException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BAD_REQUEST&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                    &lt;span class="s"&gt;"Page number cannot be less than "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;minPage&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;validateSize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;minSize&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;maxSize&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;minSize&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ResponseStatusException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BAD_REQUEST&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                    &lt;span class="s"&gt;"Page size cannot be less than "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;minSize&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;maxSize&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ResponseStatusException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BAD_REQUEST&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                    &lt;span class="s"&gt;"Page size cannot be greater than "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;maxSize&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;validateSortBy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;sortBy&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;validSortFields&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// If validSortFields is empty, no sorting is allowed&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;validSortFields&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;sortBy&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;sortBy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isBlank&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ResponseStatusException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BAD_REQUEST&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                    &lt;span class="s"&gt;"Sorting is not allowed for this resource"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// If validSortFields is specified, sortBy must be one of them&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;validSortFields&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;sortBy&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;sortBy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isBlank&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;validFieldsSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;validSortFields&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toSet&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;validFieldsSet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sortBy&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ResponseStatusException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BAD_REQUEST&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="s"&gt;"Invalid sort field. Valid options are: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;", "&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;validFieldsSet&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;validateSortDir&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;sortDir&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sortDir&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;sortDir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isBlank&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
                &lt;span class="o"&gt;!(&lt;/span&gt;&lt;span class="s"&gt;"asc"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equalsIgnoreCase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sortDir&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s"&gt;"desc"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equalsIgnoreCase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sortDir&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ResponseStatusException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BAD_REQUEST&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                    &lt;span class="s"&gt;"Invalid sort direction. Valid options are: asc, desc"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This class does the heavy lifting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extracts query parameters&lt;/li&gt;
&lt;li&gt;Handles parsing errors&lt;/li&gt;
&lt;li&gt;Enforces min/max constraints&lt;/li&gt;
&lt;li&gt;Validates sort fields against the allowed list&lt;/li&gt;
&lt;li&gt;Throws appropriate HTTP 400 errors with descriptive messages&lt;/li&gt;
&lt;li&gt;Creates the &lt;code&gt;PageSortRequest&lt;/code&gt; instance with all validated parameters&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 4: Register the Argument Resolver
&lt;/h2&gt;

&lt;p&gt;Finally, we need to register our custom argument resolver with Spring MVC:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Configuration&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WebMvcConfig&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;WebMvcConfigurer&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;PageSortArgumentResolver&lt;/span&gt; &lt;span class="n"&gt;pageSortArgumentResolver&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;WebMvcConfig&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PageSortArgumentResolver&lt;/span&gt; &lt;span class="n"&gt;pageSortArgumentResolver&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pageSortArgumentResolver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pageSortArgumentResolver&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;addArgumentResolvers&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;HandlerMethodArgumentResolver&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;resolvers&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;resolvers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pageSortArgumentResolver&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration class implements Spring's &lt;code&gt;WebMvcConfigurer&lt;/code&gt; interface and adds our custom resolver to the Spring MVC configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the Framework
&lt;/h2&gt;

&lt;p&gt;Now, any controller method can easily accept pagination and sorting parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@GetMapping&lt;/span&gt;
&lt;span class="nd"&gt;@PageSortConfig&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;defaultSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;maxSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;validSortFields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"createdAt"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"updatedAt"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TasksBoardDto&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getAllBoards&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PageSortRequest&lt;/span&gt; &lt;span class="n"&gt;pageSortRequest&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Getting all boards with pagination: {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pageSortRequest&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Use pageSortRequest in your service layer&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;boardsService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAllTasksBoards&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;pageSortRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;page&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; 
        &lt;span class="n"&gt;pageSortRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;pageSortRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sortBy&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;pageSortRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSqlSortDirection&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this framework, your API endpoints automatically support:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;?page=2&amp;amp;size=10&lt;/code&gt; for pagination&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;?sortBy=name&amp;amp;sortDir=desc&lt;/code&gt; for sorting&lt;/li&gt;
&lt;li&gt;Input validation with clear error messages&lt;/li&gt;
&lt;li&gt;Security against SQL injection through sort field validation&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;This pagination and sorting framework provides:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A clean and consistent API for clients&lt;/li&gt;
&lt;li&gt;Automatic parameter parsing and validation&lt;/li&gt;
&lt;li&gt;Security against invalid inputs&lt;/li&gt;
&lt;li&gt;Reusability across all your endpoints&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By centralizing this logic, you save time, reduce code duplication, and provide a better developer experience—both for your API users and your fellow developers.&lt;/p&gt;

</description>
      <category>java</category>
      <category>spring</category>
      <category>springboot</category>
      <category>microservices</category>
    </item>
    <item>
      <title>How I use multiple browsers</title>
      <dc:creator>RD</dc:creator>
      <pubDate>Tue, 21 Sep 2021 11:43:31 +0000</pubDate>
      <link>https://dev.to/raevilman/how-i-use-multiple-browsers-2e0</link>
      <guid>https://dev.to/raevilman/how-i-use-multiple-browsers-2e0</guid>
      <description>&lt;p&gt;For instance, on my phone, I have three browsers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Default set to Firefox.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Firefox Focus, pinned on right bottom for quick access.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Google Chrome, pinned on left bottom for quick access&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the January, I &lt;a href="https://twitter.com/raevilman/status/1355399469576056832?s=20"&gt;tweeted&lt;/a&gt; about 'How I use multiple Google Chrome profiles?'&lt;/p&gt;

&lt;p&gt;But for past couple of months, I have started using multiple browsers along with multiple Chrome profiles.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4BVxmQvD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/raevilman/the-rd-notes/master/notes/me/assets/youtube.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4BVxmQvD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/raevilman/the-rd-notes/master/notes/me/assets/youtube.png" alt="YouTube"&gt;&lt;/a&gt;&lt;br&gt;
Interested in watching the video version of this thread.&lt;br&gt;
I have upload the vlog on YouTube &lt;a href="https://youtu.be/qg7NZWLgL8E"&gt;here&lt;/a&gt;. More [verbose] info.&lt;/p&gt;




&lt;p&gt;So as mentioned above, I use Chrome, Firefox, Firefox Focus on my phone,&lt;br&gt;&lt;br&gt;
here's how they fit for different purpose.&lt;/p&gt;

&lt;h3&gt;
  
  
  The default browser: Firefox.
&lt;/h3&gt;

&lt;p&gt;This comes in situation when I am clicking links in the apps like twitter, email, chats etc.&lt;/p&gt;

&lt;p&gt;Because those are random links thus I don't want them to be linked with my Google account, as I am logged into the Chrome, thus separate browser.&lt;/p&gt;

&lt;p&gt;So by setting Firefox as default, I am segregating the random links I open via apps, from my Google account, which can result in Google algos recommending useless stuff, which anyways happens but still.&lt;/p&gt;

&lt;h3&gt;
  
  
  Temp browser: Firefox Focus
&lt;/h3&gt;

&lt;p&gt;I use it for quick searches, that I don't want to be attached to my profile. &lt;/p&gt;

&lt;p&gt;Eg: &lt;br&gt;
Searches like ongoing trends, news or sports highlights, this temp browser works well &lt;br&gt;
and these searches doesn't get attached to my interests in the Google account.&lt;/p&gt;

&lt;h3&gt;
  
  
  My online identity: Chrome
&lt;/h3&gt;

&lt;p&gt;Here I am logged into most of my online accounts. &lt;/p&gt;

&lt;p&gt;I open Chrome when I want to access these platforms, which are linked to my Google account. &lt;/p&gt;

&lt;p&gt;Like Twitter, GitHub etc. are all here in Chrome.&lt;/p&gt;




&lt;p&gt;So that is  it, that's the way how I use browsers for now.&lt;br&gt;
Which has evolved from my last January tweet for sure.&lt;/p&gt;

&lt;p&gt;May be more improvements coming in the future 🤷‍♀️  &lt;/p&gt;

&lt;p&gt;|  HIH&lt;br&gt;&lt;br&gt;
|  Take care&lt;br&gt;&lt;br&gt;
~ &lt;a class="mentioned-user" href="https://dev.to/raevilman"&gt;@raevilman&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>multiple</category>
      <category>browsers</category>
      <category>chrome</category>
      <category>firefox</category>
    </item>
    <item>
      <title>Debug Vercel Serverless Functions Locally</title>
      <dc:creator>RD</dc:creator>
      <pubDate>Fri, 17 Sep 2021 10:11:23 +0000</pubDate>
      <link>https://dev.to/raevilman/debug-vercel-serverless-functions-locally-558l</link>
      <guid>https://dev.to/raevilman/debug-vercel-serverless-functions-locally-558l</guid>
      <description>&lt;p&gt;This note is about how I managed to debug Vercel Serverless Functions locally.&lt;/p&gt;

&lt;h2&gt;
  
  
  VLog
&lt;/h2&gt;

&lt;p&gt;If you prefer to watch the video instead of reading article,&lt;br&gt;&lt;br&gt;
its available at &lt;a href="https://youtu.be/giEL-ZLE6C4"&gt;https://youtu.be/giEL-ZLE6C4&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Length: 05:22 mins  &lt;/p&gt;
&lt;h2&gt;
  
  
  debug.js
&lt;/h2&gt;

&lt;p&gt;As the vercel functions are exporting a function which takes &lt;code&gt;(req, res)&lt;/code&gt;,&lt;br&gt;&lt;br&gt;
I imported this function in another file and called it by passing fake/empty &lt;code&gt;(req, res)&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
For this, created a file &lt;code&gt;src/debug.js&lt;/code&gt; with following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../api/hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Debug started&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Debug ended&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Debug config
&lt;/h2&gt;

&lt;p&gt;Then added a file &lt;code&gt;.vscode/launch.json&lt;/code&gt;, with following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"configurations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pwa-node"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"request"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"launch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Launch Program"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"skipFiles"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;node_internals&amp;gt;/**"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"program"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${workspaceFolder}&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;src&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;debug.js"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the above file, I have now got a debug configuration in VS Code's &lt;code&gt;Run and Debug (CTRL+SHIFT+D)&lt;/code&gt; side window.&lt;br&gt;&lt;br&gt;
Now I can click(play button) and start the debugging.  &lt;/p&gt;

&lt;p&gt;Do not forget to add the breakpoint(s) in your Vercel Function script file.  &lt;/p&gt;
&lt;h2&gt;
  
  
  Fake more
&lt;/h2&gt;

&lt;p&gt;At this point, I was able to debug and fix my code, but the API function didn't run till end as I was using &lt;code&gt;res.json()&lt;/code&gt; method to return the response, which clearly was missing in our fake &lt;code&gt;res&lt;/code&gt; object passed initially.  &lt;/p&gt;

&lt;p&gt;Debugging output:  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1ik-7uR9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/raevilman/the-rd-notes/master/notes/vercel/debug-stopped.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1ik-7uR9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/raevilman/the-rd-notes/master/notes/vercel/debug-stopped.webp" alt="Debug output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So to make it work, I passed fake &lt;code&gt;json()&lt;/code&gt; method as part of &lt;code&gt;res&lt;/code&gt; object, which just prints to the console.  &lt;/p&gt;

&lt;p&gt;Now the &lt;code&gt;debug.js&lt;/code&gt; file looks like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../api/hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Debug started&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;json&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;RESPONSE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Debug ended&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Debugging now prints as below:  &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--raeCg82w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/raevilman/the-rd-notes/master/notes/vercel/debug-output.webp" alt="Debug output"&gt;
&lt;/h2&gt;

&lt;p&gt;That's it about this note.&lt;br&gt;&lt;br&gt;
HIH&lt;/p&gt;

&lt;p&gt;~ &lt;a href="https://twitter.com/raevilman"&gt;@raevilman&lt;/a&gt; 🐦 &lt;/p&gt;

</description>
      <category>debug</category>
      <category>vercel</category>
      <category>serverless</category>
      <category>functions</category>
    </item>
    <item>
      <title>REST API Flowchart with Swimlanes</title>
      <dc:creator>RD</dc:creator>
      <pubDate>Mon, 13 Sep 2021 16:42:55 +0000</pubDate>
      <link>https://dev.to/raevilman/rest-api-flowchart-with-swimlanes-36lc</link>
      <guid>https://dev.to/raevilman/rest-api-flowchart-with-swimlanes-36lc</guid>
      <description>&lt;h2&gt;
  
  
  Thoughts
&lt;/h2&gt;

&lt;p&gt;In one of the upcoming meeting, I was required to showcase the flow of one of the API I had built. Of course, opening the IDE and walking through the code isn't &lt;del&gt;a good&lt;/del&gt; an option, when the audience is not of [active] programmers.  &lt;/p&gt;

&lt;p&gt;So to present it visually, flowchart is the one that came to my mind first.&lt;br&gt;&lt;br&gt;
But as a programmer those swimlanes from the sequence diagram, which helps me separate different systems, were also poking my brain a lot.  &lt;/p&gt;

&lt;p&gt;So I decided to mix them.  &lt;/p&gt;

&lt;p&gt;Below is how a typical REST API flow will look when pictured using flowcharts with swimlanes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Frest-api%2Frest-api-flowchart-with-swimlanes.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Frest-api%2Frest-api-flowchart-with-swimlanes.png" alt="REST API Flowchart with Swimlanes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice! how the &lt;code&gt;client&lt;/code&gt; swimlane is showing all the possible response codes&lt;br&gt;&lt;br&gt;
I liked the outcome. So thought of taking a note to be referred to in future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus:
&lt;/h2&gt;

&lt;p&gt;This diagram was created using &lt;code&gt;draw.io&lt;/code&gt; software and you can find its source file &lt;a href="https://github.com/raevilman/the-rd-notes/blob/master/notes/rest-api/rest-api-flowchart-with-swimlanes.drawio" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;HIH&lt;br&gt;
~ &lt;a href="https://twitter.com/raevilman" rel="noopener noreferrer"&gt;@raevilman&lt;/a&gt; 🐦 &lt;/p&gt;

</description>
      <category>rest</category>
      <category>api</category>
      <category>flowchart</category>
      <category>swimlanes</category>
    </item>
    <item>
      <title>Node API using Vercel Serverless Functions</title>
      <dc:creator>RD</dc:creator>
      <pubDate>Mon, 13 Sep 2021 16:36:49 +0000</pubDate>
      <link>https://dev.to/raevilman/node-api-using-vercel-serverless-functions-jc4</link>
      <guid>https://dev.to/raevilman/node-api-using-vercel-serverless-functions-jc4</guid>
      <description>&lt;p&gt;This note is about how to setup, build and deploy an API using Vercel Serverless Functions.&lt;/p&gt;

&lt;h2&gt;
  
  
  VLog
&lt;/h2&gt;

&lt;p&gt;If you prefer to watch the video instead of reading article,&lt;br&gt;&lt;br&gt;
its available at &lt;a href="https://youtu.be/TE9MNxEeOI4"&gt;https://youtu.be/TE9MNxEeOI4&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Length: 14:38 mins  &lt;/p&gt;

&lt;p&gt;For sure, the video version has some more info(verbose 😀) in it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setup Vercel
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create an account at Vercel.&lt;/li&gt;
&lt;li&gt;install Vercel CLI and log in
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn global add vercel
vercel login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Setup Project
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Initiate the project using below commands and add Vercel NPM module as dev dependency.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;node-api-using-vercel
&lt;span class="nb"&gt;cd &lt;/span&gt;node-api-using-vercel
yarn init &lt;span class="nt"&gt;-y&lt;/span&gt;
yarn add vercel &lt;span class="nt"&gt;-D&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Create API
&lt;/h2&gt;

&lt;p&gt;Next, lets create an API endpoint &lt;code&gt;/hello&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;api
&lt;span class="nb"&gt;cd &lt;/span&gt;api
&lt;span class="nb"&gt;touch &lt;/span&gt;hello.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following code to &lt;code&gt;hello.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;module.exports &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;req, res&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    res.json&lt;span class="o"&gt;({&lt;/span&gt;
      msg: &lt;span class="s1"&gt;'hello there, how are you!!'&lt;/span&gt;
    &lt;span class="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Test API
&lt;/h2&gt;

&lt;p&gt;To test the API, start the local dev server using&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Your API should be exposed on &lt;code&gt;localhost:3000/api/hello&lt;/code&gt; and hitting this endpoint will return below response&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"msg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hello there, how are you!!"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Path Segments
&lt;/h2&gt;

&lt;p&gt;You can easily have path segments by naming your file like &lt;code&gt;[file_name.js]&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
When a file's name is wrapped in the square brackets, it is treated as a (dynamic) path segment&lt;br&gt;&lt;br&gt;
and its value is assigned to a variable with a name same as file name, &lt;code&gt;file_name&lt;/code&gt; in above case.&lt;br&gt;&lt;br&gt;
This variable is then passed under &lt;code&gt;req.query&lt;/code&gt; object to the API code.&lt;/p&gt;

&lt;p&gt;So if we create a directory &lt;code&gt;users&lt;/code&gt; under &lt;code&gt;api&lt;/code&gt; directory and&lt;br&gt;&lt;br&gt;
then create a file &lt;code&gt;[user_id].js&lt;/code&gt; file in it with following code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;user_id&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Hello &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!`&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when we hit the endpoint &lt;code&gt;localhost:3000/api/users/123&lt;/code&gt;, it will respond back as below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"msg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello 123!"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Vercel Config
&lt;/h2&gt;

&lt;p&gt;You can configure your Vercel Project with various options available at &lt;a href="https://vercel.com/docs/cli#project-configuration"&gt;https://vercel.com/docs/cli#project-configuration&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;But lets see one option &lt;code&gt;rewrites&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;To avoid &lt;code&gt;api&lt;/code&gt; being part of the endpoint, we can define a rewrite rule.&lt;br&gt;&lt;br&gt;
For that create &lt;code&gt;vercel.json&lt;/code&gt; in project root with following content.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"rewrites"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/users/:user_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"destination"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/api/users/:user_id"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart the server using &lt;code&gt;vercel dev&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;Now you can call the API using &lt;code&gt;localhost:3000/hello&lt;/code&gt;&lt;br&gt;&lt;br&gt;
instead of &lt;code&gt;localhost:3000/api/hello&lt;/code&gt;&lt;/p&gt;




&lt;p&gt;Thats it about this note.&lt;br&gt;&lt;br&gt;
HIH&lt;/p&gt;

</description>
      <category>node</category>
      <category>api</category>
      <category>vercel</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Setup terminal with zsh on windows</title>
      <dc:creator>RD</dc:creator>
      <pubDate>Sun, 06 Dec 2020 07:50:43 +0000</pubDate>
      <link>https://dev.to/raevilman/setup-hyper-terminal-with-zsh-on-windows-2fen</link>
      <guid>https://dev.to/raevilman/setup-hyper-terminal-with-zsh-on-windows-2fen</guid>
      <description>&lt;p&gt;Below diagram explains what we are going to do.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fterminal-with-zsh-on-windows.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fterminal-with-zsh-on-windows.png" alt="terminal with zsh on windows"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So to list the steps, we'll&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install WSL (Windows subsystem for linux)&lt;/li&gt;
&lt;li&gt;Install Ubuntu from Microsoft store&lt;/li&gt;
&lt;li&gt;Install zsh shell&lt;/li&gt;
&lt;li&gt;Install oh my zsh&lt;/li&gt;
&lt;li&gt;Install PowerLevel10k&lt;/li&gt;
&lt;li&gt;Plugins&lt;/li&gt;
&lt;li&gt;Choose a terminal&lt;/li&gt;
&lt;li&gt;Points worth noting&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Installations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  WSL
&lt;/h3&gt;

&lt;p&gt;I just enabled 'Windows Subsystem for Linux' in  Windows Feature and restarted the system.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fenable-windows-subsystem-for-linux.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fenable-windows-subsystem-for-linux.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can follow the instructions on &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/install-win10" rel="noopener noreferrer"&gt;Microsoft website&lt;/a&gt;.  &lt;/p&gt;




&lt;h3&gt;
  
  
  Ubuntu
&lt;/h3&gt;

&lt;p&gt;For this, visit this &lt;a href="https://www.microsoft.com/en-us/p/ubuntu/9nblggh4msv6" rel="noopener noreferrer"&gt;Microsoft Store&lt;/a&gt; webpage and install it.  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Download size 444.5MB on 05-12-2020&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After it is installed. Open it from start menu to continue installation.&lt;br&gt;&lt;br&gt;
Setup will ask for a username for linux subsystem.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fwsl-setup.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fwsl-setup.png" alt="WSL Setup"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After entering username, the setup will finish.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fwsl-setup-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fwsl-setup-2.png" alt="WSL Setup"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Update the packages with following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt upgrade
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  ZSH
&lt;/h3&gt;

&lt;p&gt;Install ZSH with following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;zsh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make &lt;code&gt;zsh&lt;/code&gt; the default shell with following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; chsh &lt;span class="nt"&gt;-s&lt;/span&gt; /usr/bin/zsh 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart the Ubuntu app and you should be greeted with following screen:    &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fzsh_welcome_ubuntu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fzsh_welcome_ubuntu.png" alt="zsh welcome screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Complete the configuration as per your liking.  &lt;/p&gt;




&lt;h3&gt;
  
  
  OH MY ZSH
&lt;/h3&gt;

&lt;p&gt;Next, lets install 'OH MY ZSH' with following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Below is the screenshot of completed installation.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Foh_my_zsh_installed_ubuntu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Foh_my_zsh_installed_ubuntu.png" alt="Oh my zsh"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  PowerLevel10k
&lt;/h3&gt;

&lt;p&gt;Time to spice up the terminal with a nice theme.  &lt;/p&gt;

&lt;p&gt;But before that, Install the recommended font 'Meslo Nerd Font':&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why?&lt;br&gt;&lt;br&gt;
&lt;em&gt;Icons will render properly with this font&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can download the fonts from this &lt;a href="https://github.com/romkatv/powerlevel10k#meslo-nerd-font-patched-for-powerlevel10k" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; page.  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To install a font, open it and click install button on top&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Install PowerLevel10k
&lt;/h4&gt;

&lt;p&gt;Now, for PowerLevel10k, you can follow the guide at &lt;a href="https://github.com/romkatv/powerlevel10k" rel="noopener noreferrer"&gt;https://github.com/romkatv/powerlevel10k&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Below are the steps I've taken:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Installation of PowerLevel10k for Oh My Zsh&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone --depth=1 https://github.com/romkatv/powerlevel10k.git $ZSH_CUSTOM/themes/powerlevel10k
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set &lt;code&gt;ZSH_THEME="powerlevel10k/powerlevel10k"&lt;/code&gt; in &lt;code&gt;~/.zshrc&lt;/code&gt;.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Restart the Ubuntu app.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You will be prompted with the configuration wizard for PowerLevel10k. If not, type &lt;code&gt;p10k configure&lt;/code&gt; if the configuration wizard doesn't start automatically.  &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fpowerlevel10-config-wizard-ubuntu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fpowerlevel10-config-wizard-ubuntu.png" alt="PowerLevel10k Config"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After doing the configuration, my terminal looked like below:  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fpowerlevel10-config-done-ubuntu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fpowerlevel10-config-done-ubuntu.png" alt="PowerLevel10k Config Done"&gt;&lt;/a&gt;  &lt;/p&gt;




&lt;h3&gt;
  
  
  Plugins
&lt;/h3&gt;

&lt;h4&gt;
  
  
  zsh-autosuggestions
&lt;/h4&gt;

&lt;p&gt;This plugin will suggest command as you write from the terminal history.&lt;br&gt;&lt;br&gt;
Just use &lt;code&gt;→&lt;/code&gt; right arrow key to complete the command. &lt;/p&gt;

&lt;p&gt;Link: &lt;a href="https://github.com/zsh-users/zsh-autosuggestions" rel="noopener noreferrer"&gt;https://github.com/zsh-users/zsh-autosuggestions&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;Steps I followed:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Installation&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;&lt;p&gt;To activate the autosuggestions, add it to plugin list in your .zshrc:&lt;br&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fzsh-plugins-ubuntu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fzsh-plugins-ubuntu.png" alt="ZSH Plugins"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;You will also need to force reload of your .zshrc:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;source ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;Try typing any command if its available in the history, you will see suggestion as below and then you press &lt;code&gt;-&amp;gt;&lt;/code&gt; right arrow key to complete it.&lt;br&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fzsh-plugin-autosuggestion-ubuntu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fzsh-plugin-autosuggestion-ubuntu.png" alt="ZSH AutoSuggestion plugin"&gt;&lt;/a&gt;  &lt;/p&gt;


&lt;h3&gt;
  
  
  Choose a terminal
&lt;/h3&gt;

&lt;p&gt;So far we have just configured a shell, zsh in this case.  &lt;/p&gt;

&lt;p&gt;Time to pick a terminal of choice.  &lt;/p&gt;

&lt;p&gt;Terminals are dumb. They are just UI layer. They take input and pass it on (to a shell for example).&lt;br&gt;
You can choose any terminal like Hyper, cmder, Windows Terminal etc etc.&lt;/p&gt;

&lt;p&gt;Up till now, we have been using the Ubuntu app as our terminal. You can continue using that and it works fine.  &lt;/p&gt;

&lt;p&gt;In case you want to switch, below i have notes on few of them.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fall-terminals.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fall-terminals.png" alt="All terminals"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;
  Windows Terminal
  &lt;h3&gt;
  
  
  Install
&lt;/h3&gt;

&lt;p&gt;Install it from &lt;a href="https://www.microsoft.com/en-us/p/windows-terminal-preview/9n0dx20hk701" rel="noopener noreferrer"&gt;Microsoft Store&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Font
&lt;/h3&gt;

&lt;p&gt;Open its settings from the dropdown and add &lt;code&gt;fontFace&lt;/code&gt; to the profile named &lt;code&gt;Ubuntu&lt;/code&gt; as shown below  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fwindows-terminal-profiles.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fwindows-terminal-profiles.png" alt="Windows Terminal Profile"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Default Profile
&lt;/h3&gt;

&lt;p&gt;By default it opens up PowerShell. You can change it by assigning the &lt;code&gt;GUID&lt;/code&gt; of &lt;code&gt;Ubuntu&lt;/code&gt; profile to the &lt;code&gt;defaultProfile&lt;/code&gt; in the settings.  &lt;/p&gt;



&lt;/p&gt;




&lt;p&gt;
  Hyper
  &lt;h3&gt;
  
  
  Install
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Download the installer from &lt;a href="https://hyper.is/" rel="noopener noreferrer"&gt;https://hyper.is/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Install it&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Font
&lt;/h3&gt;

&lt;p&gt;Make hyper use the custom font we installed earlier.&lt;br&gt;&lt;br&gt;
Open Hyper Terminal config file with &lt;code&gt;ctrl+,&lt;/code&gt; and add 'MesloLGS NF,' in front of the existing value for &lt;code&gt;fontFamily&lt;/code&gt; key.  &lt;/p&gt;
&lt;h3&gt;
  
  
  Shell
&lt;/h3&gt;

&lt;p&gt;Lets tie hyper with Window's bash now.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open Hyper's configuration file with &lt;code&gt;ctrl+,&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Scroll down and edit &lt;code&gt;shell&lt;/code&gt;'s value to &lt;code&gt;C:\\Windows\\System32\\bash.exe&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Configuration we did in last step, will always open &lt;code&gt;bash&lt;/code&gt; shell in Hyper.
To switch to ZSH on startup, Open your bash profile with
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vim ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Add following in the very beginning of the file&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Save and relaunch Hyper.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fhyper-color-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fhyper-color-1.png" alt="Hyper Theme"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;h3&gt;
  
  
  Colors
&lt;/h3&gt;

&lt;p&gt;The colors were a little bit bright for me. So I installed a theme for hyper terminal named 'hyper-material-theme' from &lt;a href="https://hyper.is/store/hyper-material-theme" rel="noopener noreferrer"&gt;Hyper Website&lt;/a&gt; using below command:  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠ Make sure you are running the hyper command from windows terminal. Meaning you are out zsh or linux terminal per se.&lt;br&gt;&lt;br&gt;
Use exit command to get out of zsh.&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hyper i hyper-material-theme
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now colors are nice!  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fhyper-themed.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fhyper-themed.png" alt="Hyper Theme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Issue
&lt;/h3&gt;

&lt;p&gt;One issue I noticed with hyper terminal is that it doesn't refresh/clear the screen after nano editor is closed.  &lt;/p&gt;

&lt;p&gt;As shown below, Hyper(on left) and Windows Terminal(on right) after closing nano editor.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fhyper-render-issue.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fhyper-render-issue.png" alt="Hyper render issue"&gt;&lt;/a&gt;&lt;/p&gt;



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




&lt;p&gt;
  Cmder
  &lt;h3&gt;
  
  
  Install
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Download the installer from &lt;a href="https://cmder.net/" rel="noopener noreferrer"&gt;https://cmder.net/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Install it&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Font
&lt;/h3&gt;

&lt;p&gt;Make Cmder use the custom font we installed earlier.&lt;br&gt;&lt;br&gt;
Open settings and select 'MesloLGS NF' as shown below  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fcmder-settings-font.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fcmder-settings-font.png" alt="Cmder font"&gt;&lt;/a&gt;  &lt;/p&gt;
&lt;h3&gt;
  
  
  Shell
&lt;/h3&gt;

&lt;p&gt;Lets tie cmder with Window's bash now.  &lt;/p&gt;

&lt;p&gt;Add a new task in cmder's settings window as shown below  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fcmder-settings-task.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraevilman%2Fthe-rd-notes%2Fmaster%2Fnotes%2Fsetup%2Fcmder-settings-task.png" alt="Cmder font"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Save and relaunch Cmder.
&lt;/li&gt;
&lt;/ul&gt;



&lt;/p&gt;




&lt;h3&gt;
  
  
  Points worth noting:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;h4&gt;
  
  
  ⚠ &lt;a href="https://devblogs.microsoft.com/commandline/do-not-change-linux-files-using-windows-apps-and-tools/" rel="noopener noreferrer"&gt;Do not change Linux files using Windows apps and tools&lt;/a&gt;
&lt;/h4&gt;&lt;/li&gt;
&lt;li&gt;
&lt;h4&gt;
  
  
  NodeJs Projects
&lt;/h4&gt;

&lt;p&gt;I have moved these node related notes to separate space &lt;a href="https://www.therdnotes.com/nvm-for-windows-subsystem-for-linux" rel="noopener noreferrer"&gt;here&lt;/a&gt; &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3&gt;
  
  
  Misc
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Do not try to copy text with &lt;code&gt;ctrl+c&lt;/code&gt; while a command is running 😁.
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;p&gt;Thats it for this note.&lt;br&gt;&lt;br&gt;
HIH&lt;br&gt;
~ RD&lt;/p&gt;




&lt;p&gt;This was originally published on &lt;a href="https://www.therdnotes.com/setup-zsh-on-windows" rel="noopener noreferrer"&gt;https://www.therdnotes.com/setup-zsh-on-windows&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;And I keep updating my notes with new findings... ✌&lt;/p&gt;

</description>
      <category>windows</category>
      <category>terminal</category>
      <category>zsh</category>
      <category>setup</category>
    </item>
    <item>
      <title>Setup New Windows Laptop</title>
      <dc:creator>RD</dc:creator>
      <pubDate>Thu, 22 Oct 2020 12:57:00 +0000</pubDate>
      <link>https://dev.to/raevilman/setup-new-windows-laptop-23g4</link>
      <guid>https://dev.to/raevilman/setup-new-windows-laptop-23g4</guid>
      <description>&lt;p&gt;This note is about all the steps I've take when setting up the new Windows machine.  &lt;/p&gt;

&lt;p&gt;Below are the steps in order:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User directory&lt;/li&gt;
&lt;li&gt;Uninstall bloatware&lt;/li&gt;
&lt;li&gt;Update system&lt;/li&gt;
&lt;li&gt;Partition drive&lt;/li&gt;
&lt;li&gt;Installations&lt;/li&gt;
&lt;li&gt;Configurations&lt;/li&gt;
&lt;li&gt;Issues&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  User Directory
&lt;/h2&gt;

&lt;p&gt;When setting up Windows, I used Outlook account to login into the OS.  &lt;/p&gt;

&lt;p&gt;While setting up the environment I found that the name of the folder for my user under &lt;code&gt;C:\Users&lt;/code&gt; wasn't correct and I knew that I wont be happy seeing this in future while using console or in general. So I decided to change before proceeding further.  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do not event think of just renaming it. It may mess up the system.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The steps I followed:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new local user with admin role from Settings &amp;gt; Accounts &amp;gt; Family &amp;amp; other users.
Mind the username as the folder will be created using this name under &lt;code&gt;c:\Users&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Copy the stuff (if any) from bad (original) user's folder to a common place like other drive partition.&lt;/li&gt;
&lt;li&gt;Sign out of the bad user account.&lt;/li&gt;
&lt;li&gt;Log in to the new user account.&lt;/li&gt;
&lt;li&gt;Remove the old user from Settings &amp;gt; Accounts &amp;gt; Family &amp;amp; other users.&lt;/li&gt;
&lt;li&gt;Sign in with Outlook account from new local account&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now you have the same Outlook account to log in to the system but your desired folder name for your user.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Uninstall bloatware
&lt;/h2&gt;

&lt;p&gt;Uninstall the pre-installed softwares that you know you wont need.&lt;br&gt;&lt;br&gt;
I remember uninstalling:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;McAfee Antivirus and Web Advisor&lt;/li&gt;
&lt;li&gt;Skype (I don't need this, so...)&lt;/li&gt;
&lt;li&gt;Removed apps like Solitaire, Adobe Express etc from start menu. I guess these were just shortcuts to installation.&lt;/li&gt;
&lt;li&gt;may be some more ...&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Update the system
&lt;/h2&gt;

&lt;p&gt;Put the system to download and install updates. Restarted it and then again put it on updates. After one or two restarts, the system was fully updated.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Partition the drive
&lt;/h2&gt;

&lt;p&gt;Simple reason, I don't want the user data to participate when backing up the system. Which can result in huge backup files.  &lt;/p&gt;

&lt;p&gt;After giving it a thought for some time, I decided that I need four partitions:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;System&lt;/li&gt;
&lt;li&gt;Code&lt;/li&gt;
&lt;li&gt;Programs&lt;/li&gt;
&lt;li&gt;Data&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  System
&lt;/h3&gt;

&lt;p&gt;This partition is for the Windows OS.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Code
&lt;/h3&gt;

&lt;p&gt;Home for all the source code I'll be dealing with.&lt;br&gt;&lt;br&gt;
It will have folders like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;git

&lt;ul&gt;
&lt;li&gt;raevilman (my git repositories)&lt;/li&gt;
&lt;li&gt;clones (other users repositories)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;local

&lt;ul&gt;
&lt;li&gt;experimental code&lt;/li&gt;
&lt;/ul&gt;


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

&lt;p&gt;Plus it will also store:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker volumes&lt;/li&gt;
&lt;li&gt;Virtual disks for VirtualBox etc&lt;/li&gt;
&lt;li&gt;etc&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Programs
&lt;/h3&gt;

&lt;p&gt;This is where I'll install heavy programs like games etc. So that the system drive is not overloaded.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data
&lt;/h3&gt;

&lt;p&gt;Personal data goes here. Music, Movies, Photos etc etc etc&lt;/p&gt;

&lt;p&gt;Bring up the calculator!  &lt;/p&gt;

&lt;p&gt;With the total of 952GB of storage. Below is how I've distributed the space among four partitions:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;System - 250GB&lt;/li&gt;
&lt;li&gt;Code - 100GB&lt;/li&gt;
&lt;li&gt;Programs - 200GB&lt;/li&gt;
&lt;li&gt;Data - 400GB&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;140GB is already taken by Fortnite and Apex Legends in the Programs partition 😯&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Installations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Antivirus
&lt;/h3&gt;

&lt;p&gt;I haven't bought any. So relying for now on Windows Defender.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Browser
&lt;/h3&gt;

&lt;p&gt;Chrome, you know that.&lt;br&gt;&lt;br&gt;
Download and set this as default under Settings &amp;gt; Apps &amp;gt;  Default Apps&lt;/p&gt;

&lt;h3&gt;
  
  
  Terminal
&lt;/h3&gt;

&lt;p&gt;I prefer to use &lt;a href="https://cmder.net/"&gt;Cmder&lt;/a&gt; over CMD or PowerShell.&lt;br&gt;&lt;br&gt;
Check the guide to setup Cmder &lt;a href="https://www.therdnotes.com/setup-cmder-terminal"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  IDEs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;VS Code.
Who doesn't love VS Code. The best tool from Microsoft.
Setup guide is &lt;a href="https://www.therdnotes.com/setup-vs-code"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;IntelliJ IDEA&lt;/li&gt;
&lt;li&gt;PyCharm&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Languages
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Python&lt;br&gt;&lt;br&gt;
Strangely, when I entered &lt;code&gt;python&lt;/code&gt; command in &lt;code&gt;cmd&lt;/code&gt; to check whether it is installed or not. It open python app page in Microsoft Store. So for now I did install it from the store.    &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Node.js&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Git
&lt;/h3&gt;

&lt;p&gt;Setting up git includes:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Installation&lt;/li&gt;
&lt;li&gt;Configure the ssh&lt;/li&gt;
&lt;li&gt;Configure user profile.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check the guide &lt;a href="https://www.therdnotes.com/setup-git-on-windows"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Other Utility Softwares
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Insomnia&lt;br&gt;&lt;br&gt;
I've replaced Postman with Insomnia REST Client.&lt;br&gt;&lt;br&gt;
Very nice, modern and clean UI in comparison to Postman's cluttered interface.&lt;br&gt;&lt;br&gt;
Switched from Postman mainly because of its flawed (and irritating) variables handling.&lt;br&gt;&lt;br&gt;
Download from &lt;a href="https://insomnia.rest/download"&gt;here&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;7-Zip&lt;br&gt;&lt;br&gt;
The free and open source file archiver. Download from &lt;a href="https://www.7-zip.org/download.html"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configurations
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Issues
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Bluetooth Audio Stuttering
&lt;/h3&gt;

&lt;p&gt;Faced this issue, where the audio to bluetooth connected headsets was stuttering/breaking a lot.&lt;br&gt;&lt;br&gt;
Fix for my case is explained &lt;a href="https://www.therdnotes.com/windows-bluetooth-audio-stutter-issue"&gt;here&lt;/a&gt;. &lt;/p&gt;




&lt;p&gt;This was originally published on &lt;a href="https://www.therdnotes.com/setup-new-windows-laptop"&gt;https://www.therdnotes.com/setup-new-windows-laptop&lt;/a&gt;. And I keep my notes up to date. 😊 &lt;/p&gt;

</description>
      <category>windows</category>
      <category>laptop</category>
      <category>setup</category>
    </item>
    <item>
      <title>Deploy AWS Lambda right from Your IDE</title>
      <dc:creator>RD</dc:creator>
      <pubDate>Sat, 25 Jul 2020 13:23:45 +0000</pubDate>
      <link>https://dev.to/raevilman/deploy-aws-lambda-right-from-your-ide-5a88</link>
      <guid>https://dev.to/raevilman/deploy-aws-lambda-right-from-your-ide-5a88</guid>
      <description>&lt;p&gt;Leveraging AWS Lambdas for coding microservices or better say utility functions over API, for different projects has been my go-to option.&lt;/p&gt;

&lt;p&gt;but deploying them after making changes is a bit brain tiring loop.&lt;/p&gt;

&lt;p&gt;therefore i developed a plugin for JetBrains IDEs which includes Intellij IDEA, GoLand, PyCharm and many others.&lt;/p&gt;

&lt;h3&gt;
  
  
  Old routine 🤕, dealing with lambda
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Open IntelliJ
 ↳Write code (AWS Lambda)
 ↳ Build artifacts
 ↳ Switch from IDE to browser
 ↳ Head to AWS Console and sign in (One time step)
 ↳ Open AWS Lambda or AWS S3 web page in console
 ↳ Browse to file/folder to upload your artifact to cloud and hit save
 ↳ If deploying more than one lambda artifact
 ↳ Open another tab, open AWS console, browse artifact and hit save
 ↳ Repeat last two steps for all lambdas to be deployed
 ↳ Switch back to IDE
 ↳ Continue coding
&amp;lt;Repeat till EOD&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  New routine 🤩
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Open IntelliJ
 ↳ Write code (AWS Lambda)
 ↳ Build artifact
 ↳ Deploy directly from IntelliJ IDE
&amp;lt;Repeat till EOD&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Bonus 🎄
&lt;/h3&gt;

&lt;p&gt;This plugin also helps in case you are deal with multiple AWS Named Profiles or AWS Organization&lt;/p&gt;

&lt;h3&gt;
  
  
  Demo
&lt;/h3&gt;

&lt;p&gt;YouTube: &lt;iframe width="710" height="399" src="https://www.youtube.com/embed/FgwptHeace4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Plugin Link
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://plugins.jetbrains.com/plugin/14742-aws-lambda-deployer"&gt;https://plugins.jetbrains.com/plugin/14742-aws-lambda-deployer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Originally posted on &lt;a href="https://www.therdnotes.com/projects/aws-lambda-deployer"&gt;theRDnotes.com&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Follow me on &lt;a href="https://twitter.com/raevilman"&gt;twitter&lt;/a&gt; 🎉, i generally post about different projects i am coding and their journey of development&lt;/p&gt;

</description>
      <category>aws</category>
      <category>lambda</category>
      <category>intellij</category>
      <category>plugin</category>
    </item>
  </channel>
</rss>
