<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Manuel Salinardi's blog]]></title><description><![CDATA[Manuel Salinardi's blog]]></description><link>https://blog.manuelsalinardi.dev</link><generator>RSS for Node</generator><lastBuildDate>Tue, 13 Oct 2026 12:26:06 GMT</lastBuildDate><atom:link href="https://blog.manuelsalinardi.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Fastify & Typescript: with the new Node.js flag --experimental-strip-types]]></title><description><![CDATA[Read the article in italian language

Since Node.js version v22.6.0, a new experimental flag has been introduced:
--experimental-strip-types
This flag allows us to run a .ts file directly with Node.js without needing external libraries or compiling t...]]></description><link>https://blog.manuelsalinardi.dev/fastify-typescript-with-the-new-nodejs-flag-experimental-strip-types</link><guid isPermaLink="true">https://blog.manuelsalinardi.dev/fastify-typescript-with-the-new-nodejs-flag-experimental-strip-types</guid><category><![CDATA[fastify]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[server]]></category><category><![CDATA[backend]]></category><dc:creator><![CDATA[Manuel Salinardi]]></dc:creator><pubDate>Tue, 01 Oct 2024 15:12:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1727793918819/c586d474-508f-4ac3-ac9e-3a3b0f47049f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><a target="_blank" href="https://blog.manuelsalinardi.it/fastify-typescript-con-il-nuovo-flag-experimental-strip-types-di-nodejs">Read the article in italian language</a></p>
</blockquote>
<p>Since Node.js version v22.6.0, a new experimental flag has been introduced:</p>
<p><a target="_blank" href="https://nodejs.org/docs/latest/api/cli.html#--experimental-strip-types"><strong>--experimental-strip-types</strong></a></p>
<p>This flag allows us to run a .ts file directly with Node.js without needing external libraries or compiling to JavaScript first, using the <a target="_blank" href="https://nodejs.org/docs/latest/api/typescript.html#type-stripping">"type stripping"</a> technique.</p>
<p>To use this new flag you need to use a Node.js version equal to or greater than v22.6.0</p>
<blockquote>
<p>In this article I will be using Node.js 22.8.0</p>
</blockquote>
<h2 id="heading-experimental-strip-typeshttpsnodejsorgdocslatestapiclihtml-experimental-strip-types-in-nodejs"><a target="_blank" href="https://nodejs.org/docs/latest/api/cli.html#--experimental-strip-types"><strong>--experimental-strip-types</strong></a> <strong>in Node.js</strong></h2>
<p>Let's create a file, for example node-typescript.ts</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> Person {
    name: <span class="hljs-built_in">string</span>
    surname: <span class="hljs-built_in">string</span>
}

<span class="hljs-keyword">const</span> manuel: Person = {
    name: <span class="hljs-string">'Manuel'</span>,
    surname: <span class="hljs-string">'Salinardi'</span>
} 

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Hello <span class="hljs-subst">${manuel.name}</span> <span class="hljs-subst">${manuel.surname}</span>`</span>)
</code></pre>
<p>Let's try to run it with node:</p>
<pre><code class="lang-bash">node node-typescript.ts
</code></pre>
<p>And boom!</p>
<pre><code class="lang-bash">interface Person {
          ^^^^^^

SyntaxError: Unexpected identifier <span class="hljs-string">'Person'</span>
    at wrapSafe (node:internal/modules/cjs/loader:1469:18)
    at Module._compile (node:internal/modules/cjs/loader:1491:20)
    at Module._extensions..js (node:internal/modules/cjs/loader:1691:10)
    at Module.load (node:internal/modules/cjs/loader:1317:32)
    at Module._load (node:internal/modules/cjs/loader:1127:12)
    at TracingChannel.traceSync (node:diagnostics_channel:315:14)
    at wrapModuleLoad (node:internal/modules/cjs/loader:217:24)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:166:5)
    at node:internal/main/run_main_module:30:49
</code></pre>
<p>Wow what a nice error, and rightly so because "interface" does not exist in Javascript but is a Typescript feature.</p>
<p>This is where the new experimental flag comes into play, allowing us to run Typescript files directly with Node.js.</p>
<pre><code class="lang-bash">node --experimental-strip-types node-typescript.ts
</code></pre>
<p>And now as output we will see:</p>
<pre><code class="lang-bash">Hello Manuel Salinardi
(node:98118) ExperimentalWarning: Type Stripping is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show <span class="hljs-built_in">where</span> the warning was created)
</code></pre>
<p>Wow it works!</p>
<p>We also see a warning that we are using an experimental flag.</p>
<h2 id="heading-experimental-strip-typeshttpsnodejsorgdocslatestapiclihtml-experimental-strip-types-in-fastify"><a target="_blank" href="https://nodejs.org/docs/latest/api/cli.html#--experimental-strip-types"><strong>--experimental-strip-types</strong></a> <strong>in Fastify</strong></h2>
<h3 id="heading-lets-create-the-fastify-project">Let’s create the Fastify project</h3>
<p>We use <a target="_blank" href="https://github.com/fastify/fastify-cli">fastify-cli</a> to create the Fastify project.</p>
<pre><code class="lang-bash">npx fastify-cli generate fastify-type-stripping --lang=ts --esm
</code></pre>
<p>Let's go into the "fastify-type-stripping" folder we just created and install the dependencies</p>
<pre><code class="lang-bash">npm install
</code></pre>
<p>Now let's launch the newly created server</p>
<pre><code class="lang-bash">npm start
</code></pre>
<p>If all goes well we should see output like this:</p>
<pre><code class="lang-bash">{<span class="hljs-string">"level"</span>:30,<span class="hljs-string">"time"</span>:1725951422786,<span class="hljs-string">"pid"</span>:8786,<span class="hljs-string">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,<span class="hljs-string">"msg"</span>:<span class="hljs-string">"Server listening at http://127.0.0.1:3000"</span>}
{<span class="hljs-string">"level"</span>:30,<span class="hljs-string">"time"</span>:1725951422787,<span class="hljs-string">"pid"</span>:8786,<span class="hljs-string">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,<span class="hljs-string">"msg"</span>:<span class="hljs-string">"Server listening at http://[::1]:3000"</span>}
</code></pre>
<h3 id="heading-lets-use-experimental-strip-typeshttpsnodejsorgdocslatestapiclihtml-experimental-strip-types">Let’s use <a target="_blank" href="https://nodejs.org/docs/latest/api/cli.html#--experimental-strip-types"><strong>--experimental-strip-types</strong></a></h3>
<p>fastify-cli generated this package.json:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"type"</span>: <span class="hljs-string">"module"</span>,
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"fastify-type-stripping"</span>,
  <span class="hljs-attr">"version"</span>: <span class="hljs-string">"1.0.0"</span>,
  <span class="hljs-attr">"description"</span>: <span class="hljs-string">"This project was bootstrapped with Fastify-CLI."</span>,
  <span class="hljs-attr">"main"</span>: <span class="hljs-string">"app.ts"</span>,
  <span class="hljs-attr">"directories"</span>: {
    <span class="hljs-attr">"test"</span>: <span class="hljs-string">"test"</span>
  },
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"test"</span>: <span class="hljs-string">"npm run build:ts &amp;&amp; tsc -p test/tsconfig.json &amp;&amp; FASTIFY_AUTOLOAD_TYPESCRIPT=1 node --test --experimental-test-coverage --loader ts-node/esm test/**/*.ts"</span>,
    <span class="hljs-attr">"start"</span>: <span class="hljs-string">"npm run build:ts &amp;&amp; fastify start -l info dist/app.js"</span>,
    <span class="hljs-attr">"build:ts"</span>: <span class="hljs-string">"tsc"</span>,
    <span class="hljs-attr">"watch:ts"</span>: <span class="hljs-string">"tsc -w"</span>,
    <span class="hljs-attr">"dev"</span>: <span class="hljs-string">"npm run build:ts &amp;&amp; concurrently -k -p \"[{name}]\" -n \"TypeScript,App\" -c \"yellow.bold,cyan.bold\" \"npm:watch:ts\" \"npm:dev:start\""</span>,
    <span class="hljs-attr">"dev:start"</span>: <span class="hljs-string">"fastify start --ignore-watch=.ts$ -w -l info -P dist/app.js"</span>
  },
  <span class="hljs-attr">"keywords"</span>: [],
  <span class="hljs-attr">"author"</span>: <span class="hljs-string">""</span>,
  <span class="hljs-attr">"license"</span>: <span class="hljs-string">"ISC"</span>,
  <span class="hljs-attr">"dependencies"</span>: {
    <span class="hljs-attr">"fastify"</span>: <span class="hljs-string">"^5.0.0"</span>,
    <span class="hljs-attr">"fastify-plugin"</span>: <span class="hljs-string">"^5.0.0"</span>,
    <span class="hljs-attr">"@fastify/autoload"</span>: <span class="hljs-string">"^6.0.0"</span>,
    <span class="hljs-attr">"@fastify/sensible"</span>: <span class="hljs-string">"^6.0.0"</span>,
    <span class="hljs-attr">"fastify-cli"</span>: <span class="hljs-string">"^7.0.1"</span>
  },
  <span class="hljs-attr">"devDependencies"</span>: {
    <span class="hljs-attr">"@types/node"</span>: <span class="hljs-string">"^22.1.0"</span>,
    <span class="hljs-attr">"c8"</span>: <span class="hljs-string">"^10.1.2"</span>,
    <span class="hljs-attr">"ts-node"</span>: <span class="hljs-string">"^10.4.0"</span>,
    <span class="hljs-attr">"concurrently"</span>: <span class="hljs-string">"^9.0.0"</span>,
    <span class="hljs-attr">"fastify-tsconfig"</span>: <span class="hljs-string">"^2.0.0"</span>,
    <span class="hljs-attr">"typescript"</span>: <span class="hljs-string">"^5.2.2"</span>
  }
}
</code></pre>
<p>Let's analyze the package.json start script:</p>
<pre><code class="lang-bash"><span class="hljs-string">"start"</span>: <span class="hljs-string">"npm run build:ts &amp;&amp; fastify start -l info dist/app.js"</span>
</code></pre>
<p>The "<strong>start</strong>" script consists of two commands:</p>
<ul>
<li><p><strong>npm run build:ts</strong></p>
</li>
<li><p><strong>fastify start -l info dist/app.js</strong></p>
</li>
</ul>
<p>So we see that it first runs the "<strong>build:ts</strong>" script:</p>
<pre><code class="lang-bash"><span class="hljs-string">"build:ts"</span>: <span class="hljs-string">"tsc"</span>
</code></pre>
<p>"<strong>build:ts</strong>" runs the command "<strong>tsc</strong>", which converts the TypeScript code into JavaScript according to the settings found in the tsconfig.json file, which in our case is:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"extends"</span>: <span class="hljs-string">"fastify-tsconfig"</span>,
  <span class="hljs-attr">"compilerOptions"</span>: {
    <span class="hljs-attr">"outDir"</span>: <span class="hljs-string">"dist"</span>,
    <span class="hljs-attr">"sourceMap"</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">"moduleResolution"</span>: <span class="hljs-string">"NodeNext"</span>,
    <span class="hljs-attr">"module"</span>: <span class="hljs-string">"NodeNext"</span>,
    <span class="hljs-attr">"target"</span>: <span class="hljs-string">"ES2022"</span>,
    <span class="hljs-attr">"esModuleInterop"</span>: <span class="hljs-literal">true</span>
  },
  <span class="hljs-attr">"include"</span>: [<span class="hljs-string">"src/**/*.ts"</span>]
}
</code></pre>
<p>As we can see, there's the property "outDir": "dist", which tells the compiler to put the compilation output, that is, the generated JavaScript files, in the "dist" folder.</p>
<p>Then the command <strong>fastify start -l info dist/app.js</strong> is executed, which starts our server from the <strong>dist/app.js</strong> file autogenerated by the TypeScript compiler.</p>
<p>So we see that every time we start the server, there's always this intermediate step of converting TypeScript files to JavaScript. Then the server is actually started from the JavaScript files.</p>
<h3 id="heading-lets-launch-the-server-without-typescript-compilation">Let's launch the server without Typescript compilation</h3>
<p>Let's try using the new Node.js feature <a target="_blank" href="https://nodejs.org/docs/latest/api/cli.html#--experimental-strip-types"><strong>--experimental-strip-types</strong></a> to directly launch the server with the TypeScript source code without first converting the files to JavaScript.</p>
<p>We'll proceed with trial and error and fix any issues we encounter.</p>
<h3 id="heading-attempt-1-initial-state">Attempt 1: Initial State</h3>
<p>Let's start by just removing the compilation and launching the server directly with the TypeScript file and enjoy the explosion:</p>
<pre><code class="lang-json"><span class="hljs-string">"start"</span>: <span class="hljs-string">"fastify start -l info src/app.ts"</span>
</code></pre>
<pre><code class="lang-javascript">&gt; fastify-type-stripping@<span class="hljs-number">1.0</span><span class="hljs-number">.0</span> start
&gt; fastify start -l info src/app.ts

<span class="hljs-built_in">TypeError</span> [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension <span class="hljs-string">".ts"</span> <span class="hljs-keyword">for</span> /Users/manuelsalinardi/coding/blogs/fastify/fastify-type-stripping/src/app.ts
    at <span class="hljs-built_in">Object</span>.getFileProtocolModuleFormat [<span class="hljs-keyword">as</span> file:] (node:internal/modules/esm/get_format:<span class="hljs-number">217</span>:<span class="hljs-number">9</span>)
    at defaultGetFormat (node:internal/modules/esm/get_format:<span class="hljs-number">243</span>:<span class="hljs-number">36</span>)
    at defaultLoad (node:internal/modules/esm/load:<span class="hljs-number">123</span>:<span class="hljs-number">22</span>)
    at <span class="hljs-keyword">async</span> ModuleLoader.load (node:internal/modules/esm/loader:<span class="hljs-number">567</span>:<span class="hljs-number">7</span>)
    at <span class="hljs-keyword">async</span> ModuleLoader.moduleProvider (node:internal/modules/esm/loader:<span class="hljs-number">442</span>:<span class="hljs-number">45</span>)
    at <span class="hljs-keyword">async</span> ModuleJob._link (node:internal/modules/esm/module_job:<span class="hljs-number">106</span>:<span class="hljs-number">19</span>) {
  <span class="hljs-attr">code</span>: <span class="hljs-string">'ERR_UNKNOWN_FILE_EXTENSION'</span>
}
</code></pre>
<p>Boom!!!</p>
<p>We have an error telling us the .ts file is not supported, but we saw that we can add the new Node.js flag <a target="_blank" href="https://nodejs.org/docs/latest/api/cli.html#--experimental-strip-types"><strong>--experimental-strip-types</strong></a> for this.</p>
<p>But where?</p>
<h3 id="heading-attempt-2-passing-the-experimental-strip-types-flag">Attempt 2: Passing the <strong>--experimental-strip-types</strong> flag</h3>
<p>The <a target="_blank" href="https://nodejs.org/docs/latest/api/cli.html#--experimental-strip-types"><strong>--experimental-strip-types</strong></a> flag needs to be passed to the <strong>node</strong> executable, but we are launching the server with:<br /><strong>fastify start -l info src/app.ts.</strong> In this case, we can use the environment variable: <a target="_blank" href="https://nodejs.org/docs/v20.17.0/api/cli.html#node_optionsoptions"><strong>NODE_OPTIONS</strong></a> which allows us to pass Node.js <a target="_blank" href="https://nodejs.org/docs/latest-v22.x/api/cli.html">options</a> like this:</p>
<pre><code class="lang-json"><span class="hljs-string">"start"</span>: <span class="hljs-string">"NODE_OPTIONS='--experimental-strip-types' fastify start -l info src/app.ts"</span>
</code></pre>
<pre><code class="lang-javascript"> *  Executing task: source ~/.zshrc &amp;&amp; npm run start 


&gt; fastify-type-stripping@<span class="hljs-number">1.0</span><span class="hljs-number">.0</span> start
&gt; NODE_OPTIONS=<span class="hljs-string">'--experimental-strip-types'</span> fastify start -l info src/app.ts

(node:<span class="hljs-number">57588</span>) ExperimentalWarning: Type Stripping is an experimental feature and might change at any time
(Use <span class="hljs-string">`node --trace-warnings ...`</span> to show where the warning was created)
<span class="hljs-attr">file</span>:<span class="hljs-comment">///Users/manuelsalinardi/coding/blogs/fastify/fastify-type-stripping/src/app.ts:2</span>
<span class="hljs-keyword">import</span> AutoLoad, {AutoloadPluginOptions} <span class="hljs-keyword">from</span> <span class="hljs-string">'@fastify/autoload'</span>;
                  ^^^^^^^^^^^^^^^^^^^^^
<span class="hljs-built_in">SyntaxError</span>: Named <span class="hljs-keyword">export</span> <span class="hljs-string">'AutoloadPluginOptions'</span> not found. The requested <span class="hljs-built_in">module</span> <span class="hljs-string">'@fastify/autoload'</span> is a CommonJS <span class="hljs-built_in">module</span>, which m
ay not support all <span class="hljs-built_in">module</span>.exports <span class="hljs-keyword">as</span> named <span class="hljs-built_in">exports</span>.                                                                                CommonJS modules can always be imported via the <span class="hljs-keyword">default</span> <span class="hljs-keyword">export</span>, <span class="hljs-keyword">for</span> example using:

<span class="hljs-keyword">import</span> pkg <span class="hljs-keyword">from</span> <span class="hljs-string">'@fastify/autoload'</span>;
<span class="hljs-keyword">const</span> {AutoloadPluginOptions} = pkg;

    at ModuleJob._instantiate (node:internal/modules/esm/module_job:<span class="hljs-number">171</span>:<span class="hljs-number">21</span>)
    at <span class="hljs-keyword">async</span> ModuleJob.run (node:internal/modules/esm/module_job:<span class="hljs-number">254</span>:<span class="hljs-number">5</span>)
    at <span class="hljs-keyword">async</span> onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:<span class="hljs-number">482</span>:<span class="hljs-number">26</span>)
    at <span class="hljs-keyword">async</span> requireServerPluginFromPath (<span class="hljs-regexp">/Users/m</span>anuelsalinardi/coding/blogs/fastify/fastify-type-stripping/node_modules/fastify-c
li/util.js:<span class="hljs-number">83</span>:<span class="hljs-number">22</span>)                                                                                                                      at <span class="hljs-keyword">async</span> runFastify (<span class="hljs-regexp">/Users/m</span>anuelsalinardi/coding/blogs/fastify/fastify-type-stripping/node_modules/fastify-cli/start.js:<span class="hljs-number">115</span>:<span class="hljs-number">1</span>
<span class="hljs-number">2</span>)                                                                                                                                 
 *  The terminal process <span class="hljs-string">"/bin/zsh '-l', '-c', 'source ~/.zshrc &amp;&amp; npm run start'"</span> terminated <span class="hljs-keyword">with</span> exit code: <span class="hljs-number">1.</span>
</code></pre>
<p>Wow, the error has changed!</p>
<p>Now we see that the flag <a target="_blank" href="https://nodejs.org/docs/latest/api/cli.html#--experimental-strip-types"><strong>--experimental-strip-types</strong></a> was correctly recognized because we have this warning:</p>
<pre><code class="lang-javascript">(node:<span class="hljs-number">57588</span>) ExperimentalWarning: Type Stripping is an experimental feature and might change at any time
(Use <span class="hljs-string">`node --trace-warnings ...`</span> to show where the warning was created)
</code></pre>
<p>But there is an error with the plugin <a target="_blank" href="https://www.npmjs.com/package/@fastify/autoload">@fastify/autoload</a>:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">SyntaxError</span>: Named <span class="hljs-keyword">export</span> <span class="hljs-string">'AutoloadPluginOptions'</span> not found. The requested <span class="hljs-built_in">module</span> <span class="hljs-string">'@fastify/autoload'</span> is a CommonJS <span class="hljs-built_in">module</span>, which m
ay not support all <span class="hljs-built_in">module</span>.exports <span class="hljs-keyword">as</span> named <span class="hljs-built_in">exports</span>.
</code></pre>
<p>There is something wrong with an import in our src/app.ts file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> AutoLoad, {AutoloadPluginOptions} <span class="hljs-keyword">from</span> <span class="hljs-string">'@fastify/autoload'</span>;
</code></pre>
<p>This is due to the behavior of the type stripping flag <a target="_blank" href="https://nodejs.org/docs/latest/api/cli.html#--experimental-strip-types"><strong>--experimental-strip-types</strong></a>. If we import a TypeScript type without explicitly using the keyword “<a target="_blank" href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export"><strong>type</strong></a>,” Node.js will treat it as a regular value, causing a runtime error, as explained in more detail here: <a target="_blank" href="https://nodejs.org/docs/latest-v22.x/api/typescript.html#type-stripping">https://nodejs.org/docs/latest-v22.x/api/typescript.html#type-stripping</a>.</p>
<h3 id="heading-attempt-3-using-import-type-for-typescript-types">Attempt 3: Using “import type” for TypeScript types</h3>
<p>To ensure we correctly import TypeScript types with “import type” so that type stripping can properly remove them, we add a TypeScript compiler setting: <a target="_blank" href="https://www.typescriptlang.org/tsconfig/#verbatimModuleSyntax"><strong>verbatimModuleSyntax</strong></a> to our file:</p>
<p>tsconfig.json</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"extends"</span>: <span class="hljs-string">"fastify-tsconfig"</span>,
  <span class="hljs-attr">"compilerOptions"</span>: {
    <span class="hljs-attr">"outDir"</span>: <span class="hljs-string">"dist"</span>,
    <span class="hljs-attr">"sourceMap"</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">"moduleResolution"</span>: <span class="hljs-string">"NodeNext"</span>,
    <span class="hljs-attr">"module"</span>: <span class="hljs-string">"NodeNext"</span>,
    <span class="hljs-attr">"target"</span>: <span class="hljs-string">"ES2022"</span>,
    <span class="hljs-attr">"esModuleInterop"</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">"verbatimModuleSyntax"</span>: <span class="hljs-literal">true</span>
  },
  <span class="hljs-attr">"include"</span>: [<span class="hljs-string">"src/**/*.ts"</span>]
}
</code></pre>
<p>Now we will see the import errors directly from our editor:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727708383225/d91dcb87-0285-4b0e-a4b1-79d3e386f905.png" alt class="image--center mx-auto" /></p>
<p>So let's go fix all the errors:</p>
<p>src/app.ts</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> AutoLoad, { <span class="hljs-keyword">type</span> AutoloadPluginOptions } <span class="hljs-keyword">from</span> <span class="hljs-string">'@fastify/autoload'</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-keyword">type</span> FastifyPluginAsync } <span class="hljs-keyword">from</span> <span class="hljs-string">'fastify'</span>;
</code></pre>
<p>src/routes/root.ts</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { <span class="hljs-keyword">type</span> FastifyPluginAsync } <span class="hljs-keyword">from</span> <span class="hljs-string">'fastify'</span>
</code></pre>
<p>src/routes/example/index.ts</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { <span class="hljs-keyword">type</span> FastifyPluginAsync } <span class="hljs-keyword">from</span> <span class="hljs-string">'fastify'</span>
</code></pre>
<p>src/plugins/sensible.ts</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> sensible, { <span class="hljs-keyword">type</span> FastifySensibleOptions } <span class="hljs-keyword">from</span> <span class="hljs-string">'@fastify/sensible'</span>
</code></pre>
<p>Now that we have solved all the import problems let's try to launch the server and cross our fingers.</p>
<pre><code class="lang-typescript"> *  Executing task: source ~/.zshrc &amp;&amp; npm run start 


&gt; fastify-<span class="hljs-keyword">type</span>-stripping@<span class="hljs-number">1.0</span><span class="hljs-number">.0</span> start
&gt; NODE_OPTIONS=<span class="hljs-string">'--experimental-strip-types'</span> fastify start -l info src/app.ts

(node:<span class="hljs-number">24423</span>) ExperimentalWarning: Type Stripping is an experimental feature and might change at <span class="hljs-built_in">any</span> time
(Use <span class="hljs-string">`node --trace-warnings ...`</span> to show where the warning was created)
/Users/manuelsalinardi/coding/blogs/fastify/fastify-<span class="hljs-keyword">type</span>-stripping/node_modules/<span class="hljs-meta">@fastify</span>/autoload/lib/find-plugins.js:<span class="hljs-number">148</span>
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`@fastify/autoload cannot import <span class="hljs-subst">${isHook ? <span class="hljs-string">'hooks '</span> : <span class="hljs-string">''</span>}</span>plugin at '<span class="hljs-subst">${file}</span>'. To fix this error compile TypeScript to JavaScrip
t or use 'ts-node' to run your app.`</span>)                                                                                                                         ^

<span class="hljs-built_in">Error</span>: <span class="hljs-meta">@fastify</span>/autoload cannot <span class="hljs-keyword">import</span> plugin at <span class="hljs-string">'/Users/manuelsalinardi/coding/blogs/fastify/fastify-type-stripping/src/plugins/sensible.ts'</span>. To fi
x <span class="hljs-built_in">this</span> error compile TypeScript to JavaScript or use <span class="hljs-string">'ts-node'</span> to run your app.                                                                         at handleTypeScriptSupport (<span class="hljs-regexp">/Users/m</span>anuelsalinardi/coding/blogs/fastify/fastify-<span class="hljs-keyword">type</span>-stripping/node_modules/<span class="hljs-meta">@fastify</span>/autoload/lib/find-plugins.j
s:<span class="hljs-number">148</span>:<span class="hljs-number">11</span>)                                                                                                                                               at processFile (<span class="hljs-regexp">/Users/m</span>anuelsalinardi/coding/blogs/fastify/fastify-<span class="hljs-keyword">type</span>-stripping/node_modules/<span class="hljs-meta">@fastify</span>/autoload/lib/find-plugins.js:<span class="hljs-number">124</span>:<span class="hljs-number">3</span>)
    at processDirContents (<span class="hljs-regexp">/Users/m</span>anuelsalinardi/coding/blogs/fastify/fastify-<span class="hljs-keyword">type</span>-stripping/node_modules/<span class="hljs-meta">@fastify</span>/autoload/lib/find-plugins.js:<span class="hljs-number">101</span>
:<span class="hljs-number">7</span>)                                                                                                                                                     at buildTree (<span class="hljs-regexp">/Users/m</span>anuelsalinardi/coding/blogs/fastify/fastify-<span class="hljs-keyword">type</span>-stripping/node_modules/<span class="hljs-meta">@fastify</span>/autoload/lib/find-plugins.js:<span class="hljs-number">41</span>:<span class="hljs-number">9</span>)
    at <span class="hljs-keyword">async</span> findPlugins (<span class="hljs-regexp">/Users/m</span>anuelsalinardi/coding/blogs/fastify/fastify-<span class="hljs-keyword">type</span>-stripping/node_modules/<span class="hljs-meta">@fastify</span>/autoload/lib/find-plugins.js:<span class="hljs-number">14</span>:<span class="hljs-number">3</span>
)                                                                                                                                                       at <span class="hljs-keyword">async</span> autoload (<span class="hljs-regexp">/Users/m</span>anuelsalinardi/coding/blogs/fastify/fastify-<span class="hljs-keyword">type</span>-stripping/node_modules/<span class="hljs-meta">@fastify</span>/autoload/index.js:<span class="hljs-number">20</span>:<span class="hljs-number">22</span>)

Node.js v22<span class="hljs-number">.8</span><span class="hljs-number">.0</span>

 *  The terminal process <span class="hljs-string">"/bin/zsh '-l', '-c', 'source ~/.zshrc &amp;&amp; npm run start'"</span> terminated <span class="hljs-keyword">with</span> exit code: <span class="hljs-number">1.</span>
</code></pre>
<p>Boom! Oh no another error!</p>
<p>The error comes from the @fastify/autoload module and it tells us:<br />To fix this error, compile TypeScript to JavaScript or use 'ts-node' to run your app.</p>
<p>It is a check done by @fastify/autoload. To disable it, we need to start the server with the environment variable: <strong>FASTIFY_AUTOLOAD_TYPESCRIPT</strong></p>
<h3 id="heading-attempt-4-fastifyautoloadtypescript">Attempt 4: <strong>FASTIFY_AUTOLOAD_TYPESCRIPT</strong></h3>
<p>Let's also add the environment variable: <strong>FASTIFY_AUTOLOAD_TYPESCRIPT</strong> to the "start" script.</p>
<pre><code class="lang-json"><span class="hljs-string">"start"</span>: <span class="hljs-string">"NODE_OPTIONS='--experimental-strip-types' FASTIFY_AUTOLOAD_TYPESCRIPT=1 fastify start -l info src/app.ts"</span>
</code></pre>
<pre><code class="lang-json"> *  Executing task: source ~/.zshrc &amp;&amp; npm run start 


&gt; fastify-type-stripping@<span class="hljs-number">1.0</span><span class="hljs-number">.0</span> start
&gt; NODE_OPTIONS='--experimental-strip-types' FASTIFY_AUTOLOAD_TYPESCRIPT=<span class="hljs-number">1</span> fastify start -l info src/app.ts

(node:<span class="hljs-number">36950</span>) ExperimentalWarning: Type Stripping is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
{<span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,<span class="hljs-attr">"time"</span>:<span class="hljs-number">1727709779182</span>,<span class="hljs-attr">"pid"</span>:<span class="hljs-number">36950</span>,<span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,<span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Server listening at http://127.0.0.1:3000"</span>}
{<span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,<span class="hljs-attr">"time"</span>:<span class="hljs-number">1727709779183</span>,<span class="hljs-attr">"pid"</span>:<span class="hljs-number">36950</span>,<span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,<span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Server listening at http://[::1]:3000"</span>}
</code></pre>
<p>Wow, it finally works!</p>
<p>Now we can run our server directly from the TypeScript source code without needing to compile it anymore.</p>
<p>We can do the same for the "<strong>test</strong>" script in package.json and remove the "<strong>ts-node</strong>" library from "<strong>devDependencies</strong>" because we can do it natively in Node.js thanks to the new <a target="_blank" href="https://nodejs.org/docs/latest/api/cli.html#--experimental-strip-types"><strong>--experimental-strip-types</strong></a> flag.</p>
]]></content:encoded></item><item><title><![CDATA[How to Customize the Fastify Logger]]></title><description><![CDATA[read the article in italian language

Intro
Fastify uses pino as its logger, one of the most performant loggers for Node.js.
So generally, to customize the Fastify logger, you apply the same concepts to customize pino, with a few exceptions that we w...]]></description><link>https://blog.manuelsalinardi.dev/how-to-customize-logger-in-fastify</link><guid isPermaLink="true">https://blog.manuelsalinardi.dev/how-to-customize-logger-in-fastify</guid><category><![CDATA[fastify]]></category><category><![CDATA[pino]]></category><category><![CDATA[logging]]></category><category><![CDATA[server]]></category><dc:creator><![CDATA[Manuel Salinardi]]></dc:creator><pubDate>Fri, 02 Aug 2024 08:35:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1722585131585/d14fdc96-55e0-4f8e-9e9e-bfb8f09f845a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><a target="_blank" href="https://blog.manuelsalinardi.it/come-personalizzare-il-logger-in-fastify"><strong><em>read the article in italian language</em></strong></a></p>
</blockquote>
<h2 id="heading-intro">Intro</h2>
<p>Fastify uses <a target="_blank" href="https://github.com/pinojs/pino">pino</a> as its logger, one of the most performant loggers for Node.js.</p>
<p>So generally, to customize the Fastify logger, you apply the same concepts to customize pino, with a few exceptions that we will see in this article.</p>
<blockquote>
<p>For this article, Node.js v20.13.1 was used.</p>
</blockquote>
<h2 id="heading-enable-the-logger">Enable the logger</h2>
<p>By default, the Fastify logger is disabled. To enable it, simply set it to true when initializing Fastify.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fastify = Fastify({
  <span class="hljs-attr">logger</span>: <span class="hljs-literal">true</span>
})
</code></pre>
<h2 id="heading-lets-write-the-first-log">Let's write the first log</h2>
<p>To see the first log example, let's create a simple Fastify project, which we will use for all the other examples in this article.</p>
<h3 id="heading-lets-create-the-fastify-project">Let's create the Fastify project</h3>
<p>Let's create and enter the project folder</p>
<pre><code class="lang-bash">mkdir my-logger
<span class="hljs-built_in">cd</span> my-logger
</code></pre>
<p>Let's install Fastify in the project</p>
<pre><code class="lang-bash">npm install fastify
</code></pre>
<p>This is the content of the generated package.json file:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"dependencies"</span>: {
    <span class="hljs-attr">"fastify"</span>: <span class="hljs-string">"^4.28.1"</span>
  }
}
</code></pre>
<p>Let's create the index.js file</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// import Fastify</span>
<span class="hljs-keyword">const</span> Fastify = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fastify'</span>)

<span class="hljs-comment">// initialize Fastify</span>
<span class="hljs-keyword">const</span> fastify = Fastify({
  <span class="hljs-attr">logger</span>: <span class="hljs-literal">true</span> <span class="hljs-comment">// enable the logger (disabled by default)</span>
})

<span class="hljs-comment">// start logging</span>
fastify.log.info(<span class="hljs-string">'Hello Log!'</span>)
</code></pre>
<blockquote>
<p><em>We haven't started any server; we have only initialized Fastify, and this is enough to start logging.</em></p>
</blockquote>
<p>Run the file with the command:</p>
<pre><code class="lang-bash">node server
</code></pre>
<p>As output, we will get an object similar to this:</p>
<pre><code class="lang-json">{<span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,<span class="hljs-attr">"time"</span>:<span class="hljs-number">1721369918925</span>,<span class="hljs-attr">"pid"</span>:<span class="hljs-number">85758</span>,<span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,<span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Hello World!"</span>}
</code></pre>
<p>Let's format it better to analyze it:</p>
<pre><code class="lang-json">{
   <span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>, <span class="hljs-comment">// 30 represents the level of information due from: fastify.log.info</span>
   <span class="hljs-attr">"time"</span>:<span class="hljs-number">1721369918925</span>, <span class="hljs-comment">// Unix time in milliseconds ( epoch time )</span>
   <span class="hljs-attr">"pid"</span>:<span class="hljs-number">85758</span>, <span class="hljs-comment">// process id (equivalent to process.pid)</span>
   <span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>, <span class="hljs-comment">// the host name of the operating system. ( equivalent to require('os').hostname() ) </span>
   <span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Hello World!"</span> <span class="hljs-comment">// the string we logged</span>
}
</code></pre>
<p>We can see from our simple log call:</p>
<pre><code class="lang-javascript">fastify.log.info(<span class="hljs-string">'Hello Log!'</span>)
</code></pre>
<p>Only "msg" is actually what we wrote; all the other fields were added by Pino and will be included with every call to the logger.</p>
<h2 id="heading-customize-the-logger">Customize the Logger</h2>
<p>We have seen that by default, when we make a call to the logger, a JSON object is logged where our message is placed as the value of the "msg" field.</p>
<p>But Pino also adds the fields:</p>
<ul>
<li><p>"level"</p>
</li>
<li><p>"time"</p>
</li>
<li><p>"pid"</p>
</li>
<li><p>"hostname"</p>
</li>
</ul>
<p>In this section, we will see how to customize them one by one.</p>
<h3 id="heading-level">level</h3>
<p><strong>Before customizing the "level" field, let's see how it works.</strong></p>
<p>In Pino, there are different log levels:</p>
<p>"fatal" | "error" | "warn" | "info" | "debug" | "trace".</p>
<p>For each level, there is a corresponding method:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Fastify = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fastify'</span>)

<span class="hljs-keyword">const</span> fastify = Fastify({
  <span class="hljs-attr">logger</span>: <span class="hljs-literal">true</span>
})

fastify.log.fatal(<span class="hljs-string">'Hello fatal!'</span>)
fastify.log.error(<span class="hljs-string">'Hello error!'</span>)
fastify.log.warn(<span class="hljs-string">'Hello warn!'</span>)
fastify.log.info(<span class="hljs-string">'Hello info!'</span>)
fastify.log.debug(<span class="hljs-string">'Hello debug!'</span>)
fastify.log.trace(<span class="hljs-string">'Hello trace!'</span>)
</code></pre>
<p>The code above will generate the following output:</p>
<pre><code class="lang-json">{<span class="hljs-attr">"level"</span>:<span class="hljs-number">60</span>,<span class="hljs-attr">"time"</span>:<span class="hljs-number">1722405654790</span>,<span class="hljs-attr">"pid"</span>:<span class="hljs-number">57113</span>,<span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,<span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Hello fatal!"</span>}
{<span class="hljs-attr">"level"</span>:<span class="hljs-number">50</span>,<span class="hljs-attr">"time"</span>:<span class="hljs-number">1722405654790</span>,<span class="hljs-attr">"pid"</span>:<span class="hljs-number">57113</span>,<span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,<span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Hello error!"</span>}
{<span class="hljs-attr">"level"</span>:<span class="hljs-number">40</span>,<span class="hljs-attr">"time"</span>:<span class="hljs-number">1722405654790</span>,<span class="hljs-attr">"pid"</span>:<span class="hljs-number">57113</span>,<span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,<span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Hello warn!"</span>}
{<span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,<span class="hljs-attr">"time"</span>:<span class="hljs-number">1722405654790</span>,<span class="hljs-attr">"pid"</span>:<span class="hljs-number">57113</span>,<span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,<span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Hello info!"</span>}
</code></pre>
<p>But there's something strange, because from the code we called the logger 6 times, but only 4 were generated?</p>
<ul>
<li><p>"Hello fatal!"</p>
</li>
<li><p>"Hello error!"</p>
</li>
<li><p>"Hello warn!"</p>
</li>
<li><p>"Hello info!"</p>
</li>
</ul>
<p>Missing are:</p>
<ul>
<li><p>"Hello debug!"</p>
</li>
<li><p>"Hello trace!"</p>
</li>
</ul>
<p>Where did they go?</p>
<p>Pino associates a numeric value to each level:</p>
<ul>
<li><p>"fatal" = 60</p>
</li>
<li><p>"error" = 50</p>
</li>
<li><p>"warn" = 40</p>
</li>
<li><p>"info" = 30</p>
</li>
<li><p>"debug" = 20</p>
</li>
<li><p>"trace" = 10</p>
</li>
</ul>
<p>Which we can see in the "level" field of the generated logs.</p>
<p>By default, logs below level 30, or "info", are discarded.</p>
<p>To change this default and see logs of all levels, you need to set the logger level field like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fastify = Fastify({
  <span class="hljs-attr">logger</span>: {
    <span class="hljs-attr">level</span>: <span class="hljs-string">'trace'</span>
  }
})
</code></pre>
<p>Now we see that all 6 logs are there:</p>
<pre><code class="lang-json">{<span class="hljs-attr">"level"</span>:<span class="hljs-number">60</span>,<span class="hljs-attr">"time"</span>:<span class="hljs-number">1722406770355</span>,<span class="hljs-attr">"pid"</span>:<span class="hljs-number">57832</span>,<span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,<span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Hello fatal!"</span>}
{<span class="hljs-attr">"level"</span>:<span class="hljs-number">50</span>,<span class="hljs-attr">"time"</span>:<span class="hljs-number">1722406770355</span>,<span class="hljs-attr">"pid"</span>:<span class="hljs-number">57832</span>,<span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,<span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Hello error!"</span>}
{<span class="hljs-attr">"level"</span>:<span class="hljs-number">40</span>,<span class="hljs-attr">"time"</span>:<span class="hljs-number">1722406770355</span>,<span class="hljs-attr">"pid"</span>:<span class="hljs-number">57832</span>,<span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,<span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Hello warn!"</span>}
{<span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,<span class="hljs-attr">"time"</span>:<span class="hljs-number">1722406770355</span>,<span class="hljs-attr">"pid"</span>:<span class="hljs-number">57832</span>,<span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,<span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Hello info!"</span>}
{<span class="hljs-attr">"level"</span>:<span class="hljs-number">20</span>,<span class="hljs-attr">"time"</span>:<span class="hljs-number">1722406770355</span>,<span class="hljs-attr">"pid"</span>:<span class="hljs-number">57832</span>,<span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,<span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Hello debug!"</span>}
{<span class="hljs-attr">"level"</span>:<span class="hljs-number">10</span>,<span class="hljs-attr">"time"</span>:<span class="hljs-number">1722406770355</span>,<span class="hljs-attr">"pid"</span>:<span class="hljs-number">57832</span>,<span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,<span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Hello trace!"</span>}
</code></pre>
<p><strong>Now that we understand how the "level" field works, let's see how to customize it:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fastify = Fastify({
  <span class="hljs-attr">logger</span>: {
    <span class="hljs-attr">formatters</span>: {
      level (label, number) {
        <span class="hljs-comment">// these fields will be replaced by the default "level" field</span>
        <span class="hljs-keyword">return</span> {
          <span class="hljs-attr">myLevel</span>: <span class="hljs-string">`<span class="hljs-subst">${label}</span>-<span class="hljs-subst">${number}</span>`</span>,
          <span class="hljs-attr">levelName</span>: label,
          <span class="hljs-attr">levelNumber</span>: number 
        }
      }
    }
  }
})
</code></pre>
<p>Now the generated logs will be in this format:</p>
<pre><code class="lang-json">{<span class="hljs-attr">"myLevel"</span>:<span class="hljs-string">"fatal-60"</span>,<span class="hljs-attr">"levelName"</span>:<span class="hljs-string">"fatal"</span>,<span class="hljs-attr">"levelNumber"</span>:<span class="hljs-number">60</span>,<span class="hljs-attr">"time"</span>:<span class="hljs-number">1722576879835</span>,<span class="hljs-attr">"pid"</span>:<span class="hljs-number">90770</span>,<span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,<span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Hello fatal!"</span>}
{<span class="hljs-attr">"myLevel"</span>:<span class="hljs-string">"error-50"</span>,<span class="hljs-attr">"levelName"</span>:<span class="hljs-string">"error"</span>,<span class="hljs-attr">"levelNumber"</span>:<span class="hljs-number">50</span>,<span class="hljs-attr">"time"</span>:<span class="hljs-number">1722576879835</span>,<span class="hljs-attr">"pid"</span>:<span class="hljs-number">90770</span>,<span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,<span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Hello error!"</span>}
{<span class="hljs-attr">"myLevel"</span>:<span class="hljs-string">"warn-40"</span>,<span class="hljs-attr">"levelName"</span>:<span class="hljs-string">"warn"</span>,<span class="hljs-attr">"levelNumber"</span>:<span class="hljs-number">40</span>,<span class="hljs-attr">"time"</span>:<span class="hljs-number">1722576879835</span>,<span class="hljs-attr">"pid"</span>:<span class="hljs-number">90770</span>,<span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,<span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Hello warn!"</span>}
{<span class="hljs-attr">"myLevel"</span>:<span class="hljs-string">"info-30"</span>,<span class="hljs-attr">"levelName"</span>:<span class="hljs-string">"info"</span>,<span class="hljs-attr">"levelNumber"</span>:<span class="hljs-number">30</span>,<span class="hljs-attr">"time"</span>:<span class="hljs-number">1722576879835</span>,<span class="hljs-attr">"pid"</span>:<span class="hljs-number">90770</span>,<span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,<span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Hello info!"</span>}
</code></pre>
<p>As we can see from the logs, now instead of the "level" field we find 3 more:</p>
<ul>
<li><p>"myLevel"</p>
</li>
<li><p>"levelName"</p>
</li>
<li><p>"levelNumber</p>
</li>
</ul>
<h3 id="heading-time">time</h3>
<p>You can customize the time field by setting the "timestamp" field as follows:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Fastify = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fastify'</span>)
<span class="hljs-keyword">const</span> pino = <span class="hljs-built_in">require</span>(<span class="hljs-string">'pino'</span>)

<span class="hljs-keyword">const</span> fastify = Fastify({
  <span class="hljs-attr">logger</span>: {
    <span class="hljs-attr">timestamp</span>: pino.stdTimeFunctions.isoTime, <span class="hljs-comment">// convert from epoch time to ISO time</span>
  }
})

fastify.log.info(<span class="hljs-string">'Hello info!'</span>)
</code></pre>
<pre><code class="lang-json">{
   <span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,
   <span class="hljs-attr">"time"</span>:<span class="hljs-string">"2024-07-18T06:48:52.040Z"</span>, <span class="hljs-comment">// ISO Time</span>
   <span class="hljs-attr">"pid"</span>:<span class="hljs-number">19929</span>,
   <span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,
   <span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Hello info"</span>
}
</code></pre>
<p>Pino provides us with the following functions for formatting the "timestamp":</p>
<ul>
<li><p><code>pino.stdTimeFunctions.epochTime</code>: Milliseconds since Unix epoch (Default)</p>
</li>
<li><p><code>pino.stdTimeFunctions.unixTime</code>: Seconds since Unix epoch</p>
</li>
<li><p><code>pino.stdTimeFunctions.nullTime</code>: Clears timestamp property (Used when <code>timestamp: false</code>)</p>
</li>
<li><p><code>pino.stdTimeFunctions.isoTime</code>: ISO 8601-formatted time in UTC</p>
</li>
</ul>
<p>From the official documentation: <a target="_blank" href="https://github.com/pinojs/pino/blob/main/docs/api.md#pino-stdtimefunctions">Pino stdTimeFunctions</a></p>
<h3 id="heading-pid-e-hostname">pid e hostname</h3>
<p>To customize the "pid" and "hostname" fields you need to customize the bindings.</p>
<p>Bindings are additional data that can be associated with a logger to be included in all logs generated by that logger. This data is used to enrich the log information without having to manually specify this information each time a log call is made.</p>
<p>By default Pino logger adds in the bindings: "pid" and "hostname", so to remove them and add fields to our liking we have to modify the bindings in this way:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Fastify = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fastify'</span>)
<span class="hljs-keyword">const</span> os = <span class="hljs-built_in">require</span>(<span class="hljs-string">'os'</span>)

<span class="hljs-keyword">const</span> fastify = Fastify({
  <span class="hljs-attr">logger</span>: {
    <span class="hljs-attr">formatters</span>: {
      <span class="hljs-attr">bindings</span>: <span class="hljs-function">(<span class="hljs-params">bindings</span>) =&gt;</span> {
        <span class="hljs-keyword">return</span> { 
          <span class="hljs-attr">osMachine</span>: os.machine(),
          <span class="hljs-attr">osType</span>: os.type()
        };
      },
    },
  }
})

fastify.log.info(<span class="hljs-string">'Hello info!'</span>)
</code></pre>
<pre><code class="lang-json">{
   <span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,
   <span class="hljs-attr">"time"</span>:<span class="hljs-number">1721283756521</span>,
   <span class="hljs-attr">"osMachine"</span>:<span class="hljs-string">"arm64"</span>,
   <span class="hljs-attr">"osType"</span>:<span class="hljs-string">"Darwin"</span>,
   <span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Hello info!"</span>
}
</code></pre>
<p>We see that "pid" and "hostname" are gone, but in their place are "osMachine" and "osType".</p>
<p>Instead of replacing "pid" and "hostname" we can also keep them and add fields like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fastify = Fastify({
  <span class="hljs-attr">logger</span>: {
    <span class="hljs-attr">formatters</span>: {
      <span class="hljs-attr">bindings</span>: <span class="hljs-function">(<span class="hljs-params">bindings</span>) =&gt;</span> {
        <span class="hljs-keyword">return</span> { 
          <span class="hljs-attr">pid</span>: bindings.pid,
          <span class="hljs-attr">hostname</span>: bindings.hostname,
          <span class="hljs-attr">osMachine</span>: os.machine(),
          <span class="hljs-attr">osType</span>: os.type()
        };
      },
    },
  }
})

fastify.log.info(<span class="hljs-string">'Hello info!'</span>)
</code></pre>
<pre><code class="lang-json">{
   <span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,
   <span class="hljs-attr">"time"</span>:<span class="hljs-number">1722577623975</span>,
   <span class="hljs-attr">"pid"</span>:<span class="hljs-number">91371</span>,
   <span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,
   <span class="hljs-attr">"osMachine"</span>:<span class="hljs-string">"arm64"</span>,
   <span class="hljs-attr">"osType"</span>:<span class="hljs-string">"Darwin"</span>,
   <span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Hello info!"</span>
}
</code></pre>
<h2 id="heading-what-is-request-logger">What is Request Logger?</h2>
<p>Up until now we have used the Fastify logger but without ever starting a server. Fastify provides us with a very useful feature called "Request Logger". Now with some practical examples we will see how it works and how to customize it.</p>
<h3 id="heading-lets-create-the-server">Let's create the server</h3>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> Fastify = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fastify'</span>)

<span class="hljs-keyword">const</span> fastify = Fastify({
  <span class="hljs-attr">logger</span>: <span class="hljs-literal">true</span>
})

<span class="hljs-comment">// Declare the route GET /</span>
fastify.get(<span class="hljs-string">'/'</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span> (<span class="hljs-params">request, reply</span>) </span>{
  fastify.log.info(<span class="hljs-string">'Fastify logger!'</span>)
  <span class="hljs-comment">// note that request.log is used instead of fastify.log</span>
  <span class="hljs-comment">// unlike the previous examples</span>
  request.log.info(<span class="hljs-string">'Request logger!'</span>)
  <span class="hljs-keyword">return</span> { <span class="hljs-attr">hello</span>: <span class="hljs-string">'world'</span> }
})

<span class="hljs-comment">// Start the server on port 3000</span>
fastify.listen({ <span class="hljs-attr">port</span>: <span class="hljs-number">3000</span> }, <span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (err) {
    fastify.log.error(err)
    process.exit(<span class="hljs-number">1</span>)
  }
})
</code></pre>
<p>In this server we have defined only one GET route "/" which:</p>
<ul>
<li><p>log the string "Fastify logger!" (with fastify.log)</p>
</li>
<li><p>log the string "Request logger!" (with request.log)</p>
</li>
<li><p>returns the object as response: { hello: 'world' }</p>
</li>
</ul>
<p>Note that for the first log "fastify.log" is used for the second "request.log". Then we will see with an example what is the difference between the two.</p>
<p>Let's start the server with:</p>
<pre><code class="lang-bash">node server
</code></pre>
<p>When the server starts we will see some logs automatically generated by Fastify like this:</p>
<pre><code class="lang-json">{<span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,<span class="hljs-attr">"time"</span>:<span class="hljs-number">1720591420640</span>,<span class="hljs-attr">"pid"</span>:<span class="hljs-number">69286</span>,<span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,<span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Server listening at http://127.0.0.1:3000"</span>}
{<span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,<span class="hljs-attr">"time"</span>:<span class="hljs-number">1720591420643</span>,<span class="hljs-attr">"pid"</span>:<span class="hljs-number">69286</span>,<span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,<span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Server listening at http://[::1]:3000"</span>}
</code></pre>
<h3 id="heading-first-http-call">First HTTP call</h3>
<p>Now let's try to make an HTTP call, for example with Postman to our newly created single route.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720592120698/1d083e16-2e12-4631-a4e7-5e5646f05294.png" alt class="image--center mx-auto" /></p>
<p>This call generated 4 logs:</p>
<pre><code class="lang-json"><span class="hljs-comment">// auto generated by Fastify (when receiving an HTTP request)</span>
{
   <span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,
   <span class="hljs-attr">"time"</span>:<span class="hljs-number">1720678823876</span>,
   <span class="hljs-attr">"pid"</span>:<span class="hljs-number">2292</span>,
   <span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,
   <span class="hljs-attr">"reqId"</span>:<span class="hljs-string">"req-1"</span>,
   <span class="hljs-attr">"req"</span>:{
      <span class="hljs-attr">"method"</span>:<span class="hljs-string">"GET"</span>,
      <span class="hljs-attr">"url"</span>:<span class="hljs-string">"/"</span>,
      <span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"127.0.0.1:3000"</span>,
      <span class="hljs-attr">"remoteAddress"</span>:<span class="hljs-string">"127.0.0.1"</span>,
      <span class="hljs-attr">"remotePort"</span>:<span class="hljs-number">63548</span>
   },
   <span class="hljs-attr">"msg"</span>:<span class="hljs-string">"incoming request"</span>
}

<span class="hljs-comment">// generated by us with fastify.log.info('Fastify logger!')</span>
{
   <span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,
   <span class="hljs-attr">"time"</span>:<span class="hljs-number">1720678823877</span>,
   <span class="hljs-attr">"pid"</span>:<span class="hljs-number">2292</span>,
   <span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,
   <span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Fastify logger!"</span>
}

<span class="hljs-comment">// generated by us with request.log.info('Request logger!')</span>
{
   <span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,
   <span class="hljs-attr">"time"</span>:<span class="hljs-number">1720678823877</span>,
   <span class="hljs-attr">"pid"</span>:<span class="hljs-number">2292</span>,
   <span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,
   <span class="hljs-attr">"reqId"</span>:<span class="hljs-string">"req-1"</span>,
   <span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Request logger!"</span>
}

<span class="hljs-comment">// auto generated by Fastify (when sending an HTTP response)</span>
{
   <span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,
   <span class="hljs-attr">"time"</span>:<span class="hljs-number">1720678823880</span>,
   <span class="hljs-attr">"pid"</span>:<span class="hljs-number">2292</span>,
   <span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,
   <span class="hljs-attr">"reqId"</span>:<span class="hljs-string">"req-1"</span>,
   <span class="hljs-attr">"res"</span>:{
      <span class="hljs-attr">"statusCode"</span>:<span class="hljs-number">200</span>
   },
   <span class="hljs-attr">"responseTime"</span>:<span class="hljs-number">3.9882499873638153</span>,
   <span class="hljs-attr">"msg"</span>:<span class="hljs-string">"request completed"</span>
}
</code></pre>
<p>There is an intruder among the four logs, can you see it?</p>
<p>The intruder is the second one: "Fastify logger!"</p>
<p>In fact we can see that it is the only one that does not have the "reqId". It does not have the "reqId" because it is the only one that was not generated by the request logger.</p>
<p>For each request Fastify generates a "reqId" useful to connect all the logs to that specific request, in our case:</p>
<ul>
<li><p>"incoming request" was generated by Fastify upon receiving the request, and a unique id "reqId":"req-1" was created for this request.</p>
</li>
<li><p>"Fastify logger!" was generated by us with fastify.log.info('Fastify logger!'), but since we used fastify.log, this log will not be part of the request context, so "reqId":"req-1" will not be logged.</p>
</li>
<li><p>"Request logger!" was generated by us with request.log.info('Request logger!'), in this case since we used request.log, this log will be part of the request context so "reqId":"req-1" will be logged.</p>
</li>
<li><p>"request completed" was generated by Fastify when the request was completed and the response was sent.</p>
</li>
</ul>
<h3 id="heading-disable-the-request-logger">Disable the request logger</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> app = Fastify({
  <span class="hljs-attr">disableRequestLogging</span>: <span class="hljs-literal">true</span>, <span class="hljs-comment">// disable the request logger</span>
  <span class="hljs-attr">logger</span>: <span class="hljs-literal">true</span>
})
</code></pre>
<p>Simply set disableRequestLogging to true to prevent Fastify from automatically generating logs when receiving the request and sending the response.</p>
<p>Let's see the previous example with the request logger disabled:</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> Fastify = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fastify'</span>)

<span class="hljs-keyword">const</span> fastify = Fastify({
  <span class="hljs-attr">disableRequestLogging</span>: <span class="hljs-literal">true</span>, <span class="hljs-comment">// disable the request logger</span>
  <span class="hljs-attr">logger</span>: <span class="hljs-literal">true</span>
})

<span class="hljs-comment">// declare the route GET /</span>
fastify.get(<span class="hljs-string">'/'</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span> (<span class="hljs-params">request, reply</span>) </span>{
  fastify.log.info(<span class="hljs-string">'Fastify logger!'</span>) <span class="hljs-comment">// logged</span>
  request.log.info(<span class="hljs-string">'Request logger!'</span>) <span class="hljs-comment">// it is still logged</span>
  <span class="hljs-keyword">return</span> { <span class="hljs-attr">hello</span>: <span class="hljs-string">'world'</span> }
})

<span class="hljs-comment">// start the server on the port 3000</span>
fastify.listen({ <span class="hljs-attr">port</span>: <span class="hljs-number">3000</span> }, <span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (err) {
    fastify.log.error(err)
    process.exit(<span class="hljs-number">1</span>)
  }
})
</code></pre>
<p>Let's start the server:</p>
<pre><code class="lang-bash">node server
</code></pre>
<pre><code class="lang-json">{<span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,<span class="hljs-attr">"time"</span>:<span class="hljs-number">1722320649945</span>,<span class="hljs-attr">"pid"</span>:<span class="hljs-number">20123</span>,<span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,<span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Server listening at http://[::1]:3000"</span>}
{<span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,<span class="hljs-attr">"time"</span>:<span class="hljs-number">1722320649947</span>,<span class="hljs-attr">"pid"</span>:<span class="hljs-number">20123</span>,<span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,<span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Server listening at http://127.0.0.1:3000"</span>}
</code></pre>
<p>Automatic logs at server startup are still generated.</p>
<p>Let's make the HTTP call again with Postman:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720592120698/1d083e16-2e12-4631-a4e7-5e5646f05294.png" alt class="image--center mx-auto" /></p>
<pre><code class="lang-json">{<span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,<span class="hljs-attr">"time"</span>:<span class="hljs-number">1722320840449</span>,<span class="hljs-attr">"pid"</span>:<span class="hljs-number">20123</span>,<span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,<span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Fastify logger!"</span>}
{<span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,<span class="hljs-attr">"time"</span>:<span class="hljs-number">1722320840449</span>,<span class="hljs-attr">"pid"</span>:<span class="hljs-number">20123</span>,<span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,<span class="hljs-attr">"reqId"</span>:<span class="hljs-string">"req-1"</span>,<span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Request logger!"</span>}
</code></pre>
<p>We see that now there are only 2 logs, the ones automatically generated by Fastify are missing:</p>
<ul>
<li><p>"incoming request"</p>
</li>
<li><p>"request completed"</p>
</li>
</ul>
<p>But the request logger we invoked manually with:</p>
<pre><code class="lang-javascript">request.log.info(<span class="hljs-string">'Request logger!'</span>)
</code></pre>
<p>It is still logged.</p>
<h2 id="heading-customize-the-request-logger">Customize the Request Logger</h2>
<p>The Request Logger is used in the following cases:</p>
<ul>
<li><p>explicitly called with method: "request.log"</p>
</li>
<li><p>automatically called by Fastify on every new HTTP request received</p>
</li>
<li><p>automatically called by Fastify on every HTTP response sent</p>
</li>
<li><p>automatically called by Fastify for every exception thrown inside a route (we haven't seen it yet but we'll see it later)</p>
</li>
</ul>
<p>Let's review them one by one:</p>
<pre><code class="lang-json"><span class="hljs-comment">// called explicitly with the method: "request.log"</span>
{
   <span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,
   <span class="hljs-attr">"time"</span>:<span class="hljs-number">1720678823877</span>,
   <span class="hljs-attr">"pid"</span>:<span class="hljs-number">2292</span>,
   <span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,
   <span class="hljs-attr">"reqId"</span>:<span class="hljs-string">"req-1"</span>,
   <span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Request logger!"</span>
}

<span class="hljs-comment">// automatically called by Fastify with each new HTTP request received</span>
{
   <span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,
   <span class="hljs-attr">"time"</span>:<span class="hljs-number">1720678823876</span>,
   <span class="hljs-attr">"pid"</span>:<span class="hljs-number">2292</span>,
   <span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,
   <span class="hljs-attr">"reqId"</span>:<span class="hljs-string">"req-1"</span>,
   <span class="hljs-attr">"req"</span>:{
      <span class="hljs-attr">"method"</span>:<span class="hljs-string">"GET"</span>,
      <span class="hljs-attr">"url"</span>:<span class="hljs-string">"/"</span>,
      <span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"127.0.0.1:3000"</span>,
      <span class="hljs-attr">"remoteAddress"</span>:<span class="hljs-string">"127.0.0.1"</span>,
      <span class="hljs-attr">"remotePort"</span>:<span class="hljs-number">63548</span>
   },
   <span class="hljs-attr">"msg"</span>:<span class="hljs-string">"incoming request"</span>
}

<span class="hljs-comment">// automatically called by Fastify with each HTTP response sent</span>
{
   <span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,
   <span class="hljs-attr">"time"</span>:<span class="hljs-number">1720678823880</span>,
   <span class="hljs-attr">"pid"</span>:<span class="hljs-number">2292</span>,
   <span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,
   <span class="hljs-attr">"reqId"</span>:<span class="hljs-string">"req-1"</span>,
   <span class="hljs-attr">"res"</span>:{
      <span class="hljs-attr">"statusCode"</span>:<span class="hljs-number">200</span>
   },
   <span class="hljs-attr">"responseTime"</span>:<span class="hljs-number">3.9882499873638153</span>,
   <span class="hljs-attr">"msg"</span>:<span class="hljs-string">"request completed"</span>
}

<span class="hljs-comment">// automatically called by Fastify on every exception thrown within a route </span>
{
   <span class="hljs-attr">"level"</span>:<span class="hljs-number">50</span>,
   <span class="hljs-attr">"time"</span>:<span class="hljs-number">1720766398542</span>,
   <span class="hljs-attr">"pid"</span>:<span class="hljs-number">40069</span>,
   <span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,
   <span class="hljs-attr">"reqId"</span>:<span class="hljs-string">"req-1"</span>,
   <span class="hljs-attr">"req"</span>:{
      <span class="hljs-attr">"method"</span>:<span class="hljs-string">"GET"</span>,
      <span class="hljs-attr">"url"</span>:<span class="hljs-string">"/"</span>,
      <span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"127.0.0.1:3000"</span>,
      <span class="hljs-attr">"remoteAddress"</span>:<span class="hljs-string">"127.0.0.1"</span>,
      <span class="hljs-attr">"remotePort"</span>:<span class="hljs-number">54858</span>
   },
   <span class="hljs-attr">"res"</span>:{
      <span class="hljs-attr">"statusCode"</span>:<span class="hljs-number">500</span>
   },
   <span class="hljs-attr">"err"</span>:{
      <span class="hljs-attr">"type"</span>:<span class="hljs-string">"Error"</span>,
      <span class="hljs-attr">"message"</span>:<span class="hljs-string">"Boom!"</span>,
      <span class="hljs-attr">"stack"</span>:<span class="hljs-string">"Error: Boom!\n    at Object..."</span>
   },
   <span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Boom!"</span>
}
</code></pre>
<p>So we can see that the following fields are added from the Request Logger:</p>
<ul>
<li><p>"reqId"</p>
</li>
<li><p>"req"</p>
</li>
<li><p>"res"</p>
</li>
<li><p>"err"</p>
</li>
</ul>
<p>In this section we will see how to customize them one by one.</p>
<h3 id="heading-reqid">reqId</h3>
<p>The first thing we can customize about the request logger is the "reqId", with the method: genReqId</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> currentId = <span class="hljs-number">1</span>

<span class="hljs-keyword">const</span> fastify = Fastify({
  <span class="hljs-attr">logger</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">genReqId</span>: <span class="hljs-function">(<span class="hljs-params">req</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">`my-custom-id-<span class="hljs-subst">${currentId++}</span>`</span>
  }
})
</code></pre>
<pre><code class="lang-json">{
   <span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,
   <span class="hljs-attr">"time"</span>:<span class="hljs-number">1722580879611</span>,
   <span class="hljs-attr">"pid"</span>:<span class="hljs-number">93284</span>,
   <span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,
   <span class="hljs-attr">"reqId"</span>:<span class="hljs-string">"my-custom-id-1"</span>, <span class="hljs-comment">// generated by our genReqId</span>
   <span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Request logger!"</span>
}
</code></pre>
<h3 id="heading-req-e-res">req e res</h3>
<p>How do we customize the "req" and "res" objects that are logged? For example, add or remove fields?</p>
<p>You use the serializers object for this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fastify = Fastify({
  <span class="hljs-attr">logger</span>: {
    <span class="hljs-attr">serializers</span>: {
      req (request) { <span class="hljs-comment">// in req we only want: method and url</span>
        <span class="hljs-keyword">return</span> {
          <span class="hljs-attr">method</span>: request.method,
          <span class="hljs-attr">url</span>: request.url,
        };
      },
      res (reply) { <span class="hljs-comment">// in res we want: method, url and statusCode</span>
        <span class="hljs-keyword">return</span> {
          <span class="hljs-attr">method</span>: reply.request.method,
          <span class="hljs-attr">url</span>: reply.request.url,
          <span class="hljs-attr">statusCode</span>: reply.statusCode
        }
      },
    }
  }
})
</code></pre>
<pre><code class="lang-json"><span class="hljs-comment">// req now contains only method and url</span>
<span class="hljs-comment">// instead of the default: method, url, hostname, remoteAddress, remotePort</span>
{
   <span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,
   <span class="hljs-attr">"time"</span>:<span class="hljs-number">1720765071638</span>,
   <span class="hljs-attr">"pid"</span>:<span class="hljs-number">38418</span>,
   <span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,
   <span class="hljs-attr">"reqId"</span>:<span class="hljs-string">"req-1"</span>,
   <span class="hljs-attr">"req"</span>:{
      <span class="hljs-attr">"method"</span>:<span class="hljs-string">"GET"</span>,
      <span class="hljs-attr">"url"</span>:<span class="hljs-string">"/"</span>
   },
   <span class="hljs-attr">"msg"</span>:<span class="hljs-string">"incoming request"</span>
}

<span class="hljs-comment">// this log is not affected by serializers because it contains neither req nor res</span>
{
   <span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,
   <span class="hljs-attr">"time"</span>:<span class="hljs-number">1720765071638</span>,
   <span class="hljs-attr">"pid"</span>:<span class="hljs-number">38418</span>,
   <span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,
   <span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Fastify logger!"</span>
}

<span class="hljs-comment">// This log is also not affected by the serializers because it contains neither req nor res</span>
{
   <span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,
   <span class="hljs-attr">"time"</span>:<span class="hljs-number">1720765071638</span>,
   <span class="hljs-attr">"pid"</span>:<span class="hljs-number">38418</span>,
   <span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,
   <span class="hljs-attr">"reqId"</span>:<span class="hljs-string">"req-1"</span>,
   <span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Request logger!"</span>
}

<span class="hljs-comment">// now res contains: method, url, statusCode</span>
<span class="hljs-comment">// instead of the default: statusCode</span>
{
   <span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,
   <span class="hljs-attr">"time"</span>:<span class="hljs-number">1720765071640</span>,
   <span class="hljs-attr">"pid"</span>:<span class="hljs-number">38418</span>,
   <span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,
   <span class="hljs-attr">"reqId"</span>:<span class="hljs-string">"req-1"</span>,
   <span class="hljs-attr">"res"</span>:{
      <span class="hljs-attr">"method"</span>:<span class="hljs-string">"GET"</span>,
      <span class="hljs-attr">"url"</span>:<span class="hljs-string">"/"</span>,
      <span class="hljs-attr">"statusCode"</span>:<span class="hljs-number">200</span>
   },
   <span class="hljs-attr">"responseTime"</span>:<span class="hljs-number">2.362499952316284</span>,
   <span class="hljs-attr">"msg"</span>:<span class="hljs-string">"request completed"</span>
}
</code></pre>
<h3 id="heading-err">err</h3>
<p>If an exception is generated inside a route, Fastify handles it and logs it for us automatically, let's see an example.</p>
<p>Let's throw an exception in our route:</p>
<pre><code class="lang-javascript">fastify.get(<span class="hljs-string">'/'</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span> (<span class="hljs-params">request, reply</span>) </span>{
  <span class="hljs-keyword">throw</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Boom!'</span>) <span class="hljs-comment">// this will generate the error</span>
  fastify.log.info(<span class="hljs-string">'Fastify logger!'</span>)
  request.log.info(<span class="hljs-string">'Request logger!'</span>)
  <span class="hljs-keyword">return</span> { <span class="hljs-attr">hello</span>: <span class="hljs-string">'world'</span> }
})
</code></pre>
<p>If we try to make the HTTP call to GET "/" we will see this log generated:</p>
<pre><code class="lang-json">{
   <span class="hljs-attr">"level"</span>:<span class="hljs-number">50</span>,
   <span class="hljs-attr">"time"</span>:<span class="hljs-number">1720766398542</span>,
   <span class="hljs-attr">"pid"</span>:<span class="hljs-number">40069</span>,
   <span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,
   <span class="hljs-attr">"reqId"</span>:<span class="hljs-string">"req-1"</span>,
   <span class="hljs-attr">"req"</span>:{
      <span class="hljs-attr">"method"</span>:<span class="hljs-string">"GET"</span>,
      <span class="hljs-attr">"url"</span>:<span class="hljs-string">"/"</span>,
      <span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"127.0.0.1:3000"</span>,
      <span class="hljs-attr">"remoteAddress"</span>:<span class="hljs-string">"127.0.0.1"</span>,
      <span class="hljs-attr">"remotePort"</span>:<span class="hljs-number">54858</span>
   },
   <span class="hljs-attr">"res"</span>:{
      <span class="hljs-attr">"statusCode"</span>:<span class="hljs-number">500</span>
   },
   <span class="hljs-comment">// fastify by default logs an err object, with inside: type, message and stack</span>
   <span class="hljs-attr">"err"</span>:{
      <span class="hljs-attr">"type"</span>:<span class="hljs-string">"Error"</span>,
      <span class="hljs-attr">"message"</span>:<span class="hljs-string">"Boom!"</span>,
      <span class="hljs-attr">"stack"</span>:<span class="hljs-string">"Error: Boom!\n    at Object.handler (/Users/manuelsalinardi/..."</span>
   },
   <span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Boom!"</span>
}
</code></pre>
<p>We see that for the error, Fastify generates a log with the object "err" inside.</p>
<p>What if we don't want to log the stack for security reasons?</p>
<p>Again, we can customize the "err" object as we did with the "req" and "res" objects, using the serializers object:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fastify = Fastify({
  <span class="hljs-attr">logger</span>: {
    <span class="hljs-attr">serializers</span>: {
      req (request) {
        <span class="hljs-keyword">return</span> {
          <span class="hljs-attr">method</span>: request.method,
          <span class="hljs-attr">url</span>: request.url,
        };
      },
      res (reply) {
        <span class="hljs-keyword">return</span> {
          <span class="hljs-attr">method</span>: reply.request.method,
          <span class="hljs-attr">url</span>: reply.request.url,
          <span class="hljs-attr">statusCode</span>: reply.statusCode
        }
      },
      <span class="hljs-comment">// here we customize the err object</span>
      err (error) {
        <span class="hljs-keyword">return</span> {
          <span class="hljs-attr">type</span>: error.name,
          <span class="hljs-attr">message</span>: error.message,
        }
      }
    }
  }
})
</code></pre>
<p>This is the log generator:</p>
<pre><code class="lang-json">{
   <span class="hljs-attr">"level"</span>:<span class="hljs-number">50</span>,
   <span class="hljs-attr">"time"</span>:<span class="hljs-number">1720767139181</span>,
   <span class="hljs-attr">"pid"</span>:<span class="hljs-number">40774</span>,
   <span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,
   <span class="hljs-attr">"reqId"</span>:<span class="hljs-string">"req-1"</span>,
   <span class="hljs-attr">"req"</span>:{
      <span class="hljs-attr">"method"</span>:<span class="hljs-string">"GET"</span>,
      <span class="hljs-attr">"url"</span>:<span class="hljs-string">"/"</span>
   },
   <span class="hljs-attr">"res"</span>:{
      <span class="hljs-attr">"method"</span>:<span class="hljs-string">"GET"</span>,
      <span class="hljs-attr">"url"</span>:<span class="hljs-string">"/"</span>,
      <span class="hljs-attr">"statusCode"</span>:<span class="hljs-number">500</span>
   },
   <span class="hljs-comment">// now stack is no longer present</span>
   <span class="hljs-attr">"err"</span>:{
      <span class="hljs-attr">"type"</span>:<span class="hljs-string">"Error"</span>,
      <span class="hljs-attr">"message"</span>:<span class="hljs-string">"Boom!"</span>
   },
   <span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Boom!"</span>
}
</code></pre>
<h2 id="heading-how-to-add-new-fields-to-the-request-logger">How to add new fields to the Request Logger</h2>
<p>Fastify helps us to correlate all the logs of a specific request with each other via the "reqId" field.</p>
<p>We have seen that we can also customize "reqId", but how do we add another field similar to "reqId", but chosen to our liking?</p>
<p>For example, we want to add the "user" field to the request logger, which is passed to us as a parameter in the URL by the person making the HTTP call.</p>
<p>To do this you need to call the Fastify method <a target="_blank" href="https://fastify.dev/docs/latest/Reference/Server/#setchildloggerfactory">setChildLoggerFactory</a>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Fastify = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fastify'</span>)

<span class="hljs-keyword">const</span> fastify = Fastify({
  <span class="hljs-attr">logger</span>: <span class="hljs-literal">true</span>,
})

<span class="hljs-comment">// adds fields to the Request Logger</span>
fastify.setChildLoggerFactory(<span class="hljs-function">(<span class="hljs-params">logger, bindings, opts, rawReq</span>) =&gt;</span> {

  <span class="hljs-comment">// retrieve user from URL</span>
  <span class="hljs-keyword">const</span> urlString = rawReq.url || <span class="hljs-string">''</span>
  <span class="hljs-keyword">const</span> queryString = urlString.split(<span class="hljs-string">'?'</span>)[<span class="hljs-number">1</span>]
  <span class="hljs-keyword">const</span> searchParams = <span class="hljs-keyword">new</span> URLSearchParams(queryString)
  <span class="hljs-keyword">const</span> user = searchParams.get(<span class="hljs-string">'user'</span>)

  <span class="hljs-comment">// adds user to bindings</span>
  bindings.user = user

  <span class="hljs-keyword">return</span> logger.child(bindings, opts)
})

<span class="hljs-comment">// declare the route</span>
fastify.get(<span class="hljs-string">'/'</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span> (<span class="hljs-params">request, reply</span>) </span>{
  request.log.info(<span class="hljs-string">'Request logger!'</span>)
  <span class="hljs-keyword">return</span> { <span class="hljs-attr">hello</span>: <span class="hljs-string">'world'</span> }
})

<span class="hljs-comment">// start the server</span>
fastify.listen({ <span class="hljs-attr">port</span>: <span class="hljs-number">3000</span> }, <span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (err) {
    fastify.log.error(err)
    process.exit(<span class="hljs-number">1</span>)
  }
})
</code></pre>
<p>Now let's make an HTTP call with the user query URL parameter:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722584394555/d3ba4b2a-eaeb-437d-9ec5-004fbf32e637.png" alt class="image--center mx-auto" /></p>
<p>We will see logs like this:</p>
<pre><code class="lang-json">{
   <span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,
   <span class="hljs-attr">"time"</span>:<span class="hljs-number">1722583839646</span>,
   <span class="hljs-attr">"pid"</span>:<span class="hljs-number">95780</span>,
   <span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,
   <span class="hljs-attr">"reqId"</span>:<span class="hljs-string">"req-2"</span>,
   <span class="hljs-attr">"user"</span>:<span class="hljs-string">"manuel"</span>, <span class="hljs-comment">// new field: user</span>
   <span class="hljs-attr">"req"</span>:{
      <span class="hljs-attr">"method"</span>:<span class="hljs-string">"GET"</span>,
      <span class="hljs-attr">"url"</span>:<span class="hljs-string">"/?user=manuel"</span>,
      <span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"127.0.0.1:3000"</span>,
      <span class="hljs-attr">"remoteAddress"</span>:<span class="hljs-string">"127.0.0.1"</span>,
      <span class="hljs-attr">"remotePort"</span>:<span class="hljs-number">52098</span>
   },
   <span class="hljs-attr">"msg"</span>:<span class="hljs-string">"incoming request"</span>
}{
   <span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,
   <span class="hljs-attr">"time"</span>:<span class="hljs-number">1722583839646</span>,
   <span class="hljs-attr">"pid"</span>:<span class="hljs-number">95780</span>,
   <span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,
   <span class="hljs-attr">"reqId"</span>:<span class="hljs-string">"req-2"</span>,
   <span class="hljs-attr">"user"</span>:<span class="hljs-string">"manuel"</span>, <span class="hljs-comment">// new field: user</span>
   <span class="hljs-attr">"msg"</span>:<span class="hljs-string">"Request logger!"</span>
}{
   <span class="hljs-attr">"level"</span>:<span class="hljs-number">30</span>,
   <span class="hljs-attr">"time"</span>:<span class="hljs-number">1722583839648</span>,
   <span class="hljs-attr">"pid"</span>:<span class="hljs-number">95780</span>,
   <span class="hljs-attr">"hostname"</span>:<span class="hljs-string">"Manuels-MacBook-Pro.local"</span>,
   <span class="hljs-attr">"reqId"</span>:<span class="hljs-string">"req-2"</span>,
   <span class="hljs-attr">"user"</span>:<span class="hljs-string">"manuel"</span>, <span class="hljs-comment">// new field: user</span>
   <span class="hljs-attr">"res"</span>:{
      <span class="hljs-attr">"statusCode"</span>:<span class="hljs-number">200</span>
   },
   <span class="hljs-attr">"responseTime"</span>:<span class="hljs-number">1.4203753471374512</span>,
   <span class="hljs-attr">"msg"</span>:<span class="hljs-string">"request completed"</span>
}
</code></pre>
<p>Now the Request Logger will have the new field "user" in addition to the "reqId".</p>
<blockquote>
<p>Manuel Salinardi</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Fastify: Type safe with Type-Providers]]></title><description><![CDATA[In this article we will see how to automatically type Fastify routes via the JSON schema, using the Type-Provider: TypeBox.

click here to read the article in italian language

Pre-requirements
Node.js v20.13.1
What are Type-Providers?
Documentation:...]]></description><link>https://blog.manuelsalinardi.dev/fastify-type-safe-with-type-providers</link><guid isPermaLink="true">https://blog.manuelsalinardi.dev/fastify-type-safe-with-type-providers</guid><category><![CDATA[fastify]]></category><category><![CDATA[Typebox]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[REST API]]></category><category><![CDATA[APIs]]></category><category><![CDATA[server]]></category><dc:creator><![CDATA[Manuel Salinardi]]></dc:creator><pubDate>Fri, 28 Jun 2024 14:51:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1719586124053/14ea8741-b412-499c-b200-0c58028b1bf4.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this article we will see how to automatically type Fastify routes via the JSON schema, using the Type-Provider: TypeBox.</p>
<blockquote>
<p><a target="_blank" href="https://blog.manuelsalinardi.it/fastify-type-safe-con-i-type-providers">click here to read the article in italian language</a></p>
</blockquote>
<h2 id="heading-pre-requirements">Pre-requirements</h2>
<p>Node.js v20.13.1</p>
<h2 id="heading-what-are-type-providers">What are Type-Providers?</h2>
<p><a target="_blank" href="https://fastify.dev/docs/latest/Reference/Type-Providers/">Documentation: Type-Providers</a></p>
<p>Type-Providers are a feature only for Fastify projects that use Typescript as a language.</p>
<p>There are different types of Type-Providers, for this article, we will use: <a target="_blank" href="https://github.com/sinclairzx81/typebox#validation">TypeBox</a>.</p>
<h2 id="heading-lets-create-the-fastify-project-with-typescript">Let's create the Fastify project with Typescript</h2>
<p>We open the terminal and type this command:</p>
<pre><code class="lang-bash">npx fastify-cli generate my-app --lang=ts
</code></pre>
<p>This command will generate a Fastify project with Typescript, using the utility <a target="_blank" href="https://github.com/fastify/fastify-cli">fastify-cli</a>.</p>
<h2 id="heading-project-structure">Project structure</h2>
<p>At this point, we have a project with the following structure:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718260761874/d8a079fb-480d-4cbc-9311-0b00c4270c9f.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-contents-of-the-packagejson-generated">Contents of the package.json generated</h2>
<pre><code class="lang-json">{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"my-app"</span>,
  <span class="hljs-attr">"version"</span>: <span class="hljs-string">"1.0.0"</span>,
  <span class="hljs-attr">"description"</span>: <span class="hljs-string">"This project was bootstrapped with Fastify-CLI."</span>,
  <span class="hljs-attr">"main"</span>: <span class="hljs-string">"app.ts"</span>,
  <span class="hljs-attr">"directories"</span>: {
    <span class="hljs-attr">"test"</span>: <span class="hljs-string">"test"</span>
  },
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"test"</span>: <span class="hljs-string">"npm run build:ts &amp;&amp; tsc -p test/tsconfig.json &amp;&amp; c8 node --test -r ts-node/register \"test/**/*.ts\""</span>,
    <span class="hljs-attr">"start"</span>: <span class="hljs-string">"npm run build:ts &amp;&amp; fastify start -l info dist/app.js"</span>,
    <span class="hljs-attr">"build:ts"</span>: <span class="hljs-string">"tsc"</span>,
    <span class="hljs-attr">"watch:ts"</span>: <span class="hljs-string">"tsc -w"</span>,
    <span class="hljs-attr">"dev"</span>: <span class="hljs-string">"npm run build:ts &amp;&amp; concurrently -k -p \"[{name}]\" -n \"TypeScript,App\" -c \"yellow.bold,cyan.bold\" \"npm:watch:ts\" \"npm:dev:start\""</span>,
    <span class="hljs-attr">"dev:start"</span>: <span class="hljs-string">"fastify start --ignore-watch=.ts$ -w -l info -P dist/app.js"</span>
  },
  <span class="hljs-attr">"keywords"</span>: [],
  <span class="hljs-attr">"author"</span>: <span class="hljs-string">""</span>,
  <span class="hljs-attr">"license"</span>: <span class="hljs-string">"ISC"</span>,
  <span class="hljs-attr">"dependencies"</span>: {
    <span class="hljs-attr">"@fastify/autoload"</span>: <span class="hljs-string">"^5.0.0"</span>,
    <span class="hljs-attr">"@fastify/sensible"</span>: <span class="hljs-string">"^5.0.0"</span>,
    <span class="hljs-attr">"@fastify/type-provider-typebox"</span>: <span class="hljs-string">"^4.0.0"</span>,
    <span class="hljs-attr">"fastify"</span>: <span class="hljs-string">"^4.26.1"</span>,
    <span class="hljs-attr">"fastify-cli"</span>: <span class="hljs-string">"^6.2.1"</span>,
    <span class="hljs-attr">"fastify-plugin"</span>: <span class="hljs-string">"^4.0.0"</span>
  },
  <span class="hljs-attr">"devDependencies"</span>: {
    <span class="hljs-attr">"@types/node"</span>: <span class="hljs-string">"^20.4.4"</span>,
    <span class="hljs-attr">"c8"</span>: <span class="hljs-string">"^9.0.0"</span>,
    <span class="hljs-attr">"concurrently"</span>: <span class="hljs-string">"^8.2.2"</span>,
    <span class="hljs-attr">"fastify-tsconfig"</span>: <span class="hljs-string">"^2.0.0"</span>,
    <span class="hljs-attr">"ts-node"</span>: <span class="hljs-string">"^10.4.0"</span>,
    <span class="hljs-attr">"typescript"</span>: <span class="hljs-string">"^5.2.2"</span>
  }
}
</code></pre>
<h2 id="heading-lets-install-the-packagejson-dependencies">Let's install the package.json dependencies</h2>
<p>Enter the folder of the newly created "my-app" project and install all the dependencies of the package.json with this command:</p>
<pre><code class="lang-bash">npm install
</code></pre>
<h2 id="heading-default-route-root">Default route root</h2>
<p>fastify-cli has already created 2 routes for us, we can find them inside the files:</p>
<ol>
<li><p>src/routes/root.ts</p>
</li>
<li><p>src/routes/example/index.ts</p>
</li>
</ol>
<p>Let's see the generated code for the root route:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { FastifyPluginAsync } <span class="hljs-keyword">from</span> <span class="hljs-string">"fastify"</span>

<span class="hljs-keyword">const</span> example: FastifyPluginAsync = <span class="hljs-keyword">async</span> (fastify, opts): <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">void</span>&gt; =&gt; {
  fastify.get(<span class="hljs-string">'/'</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">request, reply</span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">'this is an example'</span>
  })
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> example;
</code></pre>
<p>This route defines an HTTP GET call that returns a response string: 'this is an example'.</p>
<h2 id="heading-lets-add-our-route">Let's add our route</h2>
<p>To make an example as simple as possible, let's add a route that takes text as input and returns the text in uppercase as a response.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { FastifyPluginAsync } <span class="hljs-keyword">from</span> <span class="hljs-string">"fastify"</span>

<span class="hljs-keyword">const</span> example: FastifyPluginAsync = <span class="hljs-keyword">async</span> (fastify, opts): <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">void</span>&gt; =&gt; {

  fastify.get(<span class="hljs-string">'/'</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">request, reply</span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">'this is an example'</span>
  })

  fastify.post(<span class="hljs-string">'/uppercase'</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">request, reply</span>) </span>{
    <span class="hljs-keyword">const</span> body = request.body
    <span class="hljs-keyword">const</span> text = body.text
    <span class="hljs-keyword">return</span> { textResult: text.toUpperCase()} 
  })

}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> example;
</code></pre>
<p>We have added a POST type route, the route expects a single 'text' property in the body and returns an object with a single 'textResult' property.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718347595519/7d91eea8-1871-489b-a628-44312d5915b7.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-typescript-error">Typescript error</h2>
<p>At this point Typescript will generate an error because initially, the body object is of type unknown, so we need to type the body object.</p>
<p>We could type the body object directly with a Typescript interface. Still, since we will be using a schema to validate the route, we will let Typescript generate the types directly from our schema, to have a single source of truth.</p>
<h2 id="heading-lets-install-the-type-provider-typebox-library">Let's install the type-provider-typebox library</h2>
<pre><code class="lang-bash">npm i @fastify/type-provider-typebox
</code></pre>
<h2 id="heading-lets-create-the-schema-with-typebox">Let's create the schema with Typebox</h2>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Type } <span class="hljs-keyword">from</span> <span class="hljs-string">'@fastify/type-provider-typebox'</span>
<span class="hljs-keyword">import</span> { FastifyPluginAsync } <span class="hljs-keyword">from</span> <span class="hljs-string">"fastify"</span>

<span class="hljs-keyword">const</span> example: FastifyPluginAsync = <span class="hljs-keyword">async</span> (fastify, opts): <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">void</span>&gt; =&gt; {

  fastify.get(<span class="hljs-string">'/'</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">request, reply</span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">'this is an example'</span>
  })

  fastify.post(<span class="hljs-string">'/uppercase'</span>, {
    schema: {
      body: Type.Object({
        text: Type.String(),
      }),
      response: {
        <span class="hljs-number">200</span>: Type.Object({ 
          textResult: Type.String() 
        }),
      }
    }
  }, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">request, reply</span>) </span>{
    <span class="hljs-keyword">const</span> body = request.body
    <span class="hljs-keyword">const</span> text = body.text
    <span class="hljs-keyword">return</span> { textResult: text.toUpperCase()} 
  })

}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> example;
</code></pre>
<p>Now we have created a schema that defines that:</p>
<ul>
<li><p>If the customer does not pass exactly one object with a string-type 'text' property in the body, he will receive a 404 error</p>
</li>
<li><p>If the server does not return exactly one object with the string-type 'textResult' property inside, the client will receive a 500 error</p>
</li>
</ul>
<p>But there is still a problem, the schema is right but Typescript still doesn't compile because request.body is still of type unknown.</p>
<h2 id="heading-lets-use-the-schema-to-generate-the-types-for-the-route">Let's use the schema to generate the types for the route</h2>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Type, FastifyPluginAsyncTypebox } <span class="hljs-keyword">from</span> <span class="hljs-string">'@fastify/type-provider-typebox'</span>

<span class="hljs-keyword">const</span> example: FastifyPluginAsyncTypebox = <span class="hljs-keyword">async</span> (fastify, opts): <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">void</span>&gt; =&gt; {

  fastify.get(<span class="hljs-string">'/'</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">request, reply</span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">'this is an example'</span>
  })

  fastify.post(<span class="hljs-string">'/uppercase'</span>, {
    schema: {
      body: Type.Object({
        text: Type.String(),
      }),
      response: {
        <span class="hljs-number">200</span>: Type.Object({ 
          textResult: Type.String() 
        }),
      }
    }
  }, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">request, reply</span>) </span>{
    <span class="hljs-keyword">const</span> body = request.body
    <span class="hljs-keyword">const</span> text = body.text
    <span class="hljs-keyword">return</span> { textResult: text.toUpperCase()} 
  })

}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> example;
</code></pre>
<p>We just replaced the type:</p>
<ul>
<li>FastifyPluginAsync (type for plugin imported directly from 'fastify')</li>
</ul>
<p>With the type:</p>
<ul>
<li>FastifyPluginAsyncTypebox (type for plugin imported from '@fastify/type-provider-typebox')</li>
</ul>
<h2 id="heading-refactoring">Refactoring</h2>
<p>Now everything works, but personally, for better readability, I prefer to separate the function of the route and the schema from the declaration of the route itself.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Type, FastifyPluginAsyncTypebox } <span class="hljs-keyword">from</span> <span class="hljs-string">'@fastify/type-provider-typebox'</span>
<span class="hljs-keyword">import</span> { FastifyReply, FastifyRequest } <span class="hljs-keyword">from</span> <span class="hljs-string">'fastify'</span>

<span class="hljs-keyword">const</span> example: FastifyPluginAsyncTypebox = <span class="hljs-keyword">async</span> (fastify, opts): <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">void</span>&gt; =&gt; {

  fastify.get(<span class="hljs-string">'/'</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">request, reply</span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">'this is an example'</span>
  })

  <span class="hljs-keyword">const</span> schemaPostUppercase = {
    body: Type.Object({
      text: Type.String(),
    }),
    response: {
      <span class="hljs-number">200</span>: Type.Object({ 
        textResult: Type.String() 
      }),
    }
  }

  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">postUppercase</span>(<span class="hljs-params">request: FastifyRequest, reply: FastifyReply</span>) </span>{
    <span class="hljs-keyword">const</span> body = request.body
    <span class="hljs-keyword">const</span> text = body.text
    <span class="hljs-keyword">return</span> { textResult: text.toUpperCase()} 
  }

  fastify.post(<span class="hljs-string">'/uppercase'</span>, { schema: schemaPostUppercase }, postUppercase)

}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> example;
</code></pre>
<p>This way we separated the schema into the variable: schemaPostUppercase and the route handler into the function: postUppercase.</p>
<p>But now Typescript is no longer able to type the body and return of the function and generates the error:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719326501941/721ef45d-6663-49c1-b093-c668a6284e52.png" alt class="image--center mx-auto" /></p>
<p>And also note that the return is no longer typed. Typescript allows us to do this:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">return</span> { hello: text.toUpperCase()}
</code></pre>
<p>Returning the 'hello' property should generate a Typescript compilation error because it does not respect the schema which instead defines that only the 'textResult' property is present in the response.</p>
<p>This is because the route no longer takes types from the schema.</p>
<h2 id="heading-route-handler-type">Route handler type</h2>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Type, FastifyPluginAsyncTypebox, TypeBoxTypeProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">'@fastify/type-provider-typebox'</span>
<span class="hljs-keyword">import</span> { ContextConfigDefault, FastifyBaseLogger, FastifyInstance, FastifyReply, FastifyRequest, FastifySchema, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerDefault, RouteGenericInterface } <span class="hljs-keyword">from</span> <span class="hljs-string">'fastify'</span>
<span class="hljs-keyword">import</span> { ResolveFastifyReplyReturnType } <span class="hljs-keyword">from</span> <span class="hljs-string">'fastify/types/type-provider'</span>

<span class="hljs-keyword">type</span> FastifyInstanceTypebox = FastifyInstance&lt;
  RawServerDefault,
  RawRequestDefaultExpression&lt;RawServerDefault&gt;,
  RawReplyDefaultExpression,
  FastifyBaseLogger,
  TypeBoxTypeProvider
&gt;

<span class="hljs-keyword">type</span> FastifyRequestTypebox&lt;TSchema <span class="hljs-keyword">extends</span> FastifySchema&gt; = FastifyRequest&lt;
  RouteGenericInterface,
  RawServerDefault,
  RawRequestDefaultExpression&lt;RawServerDefault&gt;,
  TSchema,
  TypeBoxTypeProvider
&gt;

<span class="hljs-keyword">type</span> FastifyReplyTypebox&lt;TSchema <span class="hljs-keyword">extends</span> FastifySchema&gt; = FastifyReply&lt;
  RawServerDefault,
  RawRequestDefaultExpression,
  RawReplyDefaultExpression,
  RouteGenericInterface,
  ContextConfigDefault,
  TSchema,
  TypeBoxTypeProvider
&gt;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> RouteHandlerTypebox&lt;TSchema <span class="hljs-keyword">extends</span> FastifySchema&gt; = <span class="hljs-function">(<span class="hljs-params">
  <span class="hljs-built_in">this</span>: FastifyInstanceTypebox,
  request: FastifyRequestTypebox&lt;TSchema&gt;,
  reply: FastifyReplyTypebox&lt;TSchema&gt;
</span>) =&gt;</span> ResolveFastifyReplyReturnType&lt;TypeBoxTypeProvider, TSchema, RouteGenericInterface&gt;

<span class="hljs-keyword">const</span> example: FastifyPluginAsyncTypebox = <span class="hljs-keyword">async</span> (fastify, opts): <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">void</span>&gt; =&gt; {

  fastify.get(<span class="hljs-string">'/'</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">request, reply</span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">'this is an example'</span>
  })

  <span class="hljs-keyword">const</span> schemaPostUppercase = {
    body: Type.Object({
      text: Type.String(),
    }),
    response: {
      <span class="hljs-number">200</span>: Type.Object({ 
        textResult: Type.String() 
      }),
    }
  }

  <span class="hljs-keyword">const</span> postUppercase: RouteHandlerTypebox&lt;<span class="hljs-keyword">typeof</span> schemaPostUppercase&gt; = <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">request, reply</span>) </span>{
    <span class="hljs-keyword">const</span> body = request.body
    <span class="hljs-keyword">const</span> text = body.text
    <span class="hljs-keyword">return</span> { textResult: text.toUpperCase()} 
  }

  fastify.post(<span class="hljs-string">'/uppercase'</span>, { schema: schemaPostUppercase }, postUppercase)

}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> example;
</code></pre>
<p>Unfortunately, in order to separate the declaration of the 'postUppercase' function from the route definition, we have to create its type manually.</p>
<p>For simplicity, I have defined all the types within the same file, but in a real project, you generally define the types in a separate file and import them into the files in which they are used.</p>
<p>Let's see this process step by step:</p>
<ul>
<li>We transformed the postUppercase function from this:</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">postUppercase</span>(<span class="hljs-params">request: FastifyRequest, reply: FastifyReply</span>) </span>{
    <span class="hljs-keyword">const</span> body = request.body
    <span class="hljs-keyword">const</span> text = body.text
    <span class="hljs-keyword">return</span> { textResult: text.toUpperCase()} 
}
</code></pre>
<ul>
<li>To this:</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> postUppercase: RouteHandlerTypebox&lt;<span class="hljs-keyword">typeof</span> schemaPostUppercase&gt; = <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">request, reply</span>) </span>{
    <span class="hljs-keyword">const</span> body = request.body
    <span class="hljs-keyword">const</span> text = body.text
    <span class="hljs-keyword">return</span> { textResult: text.toUpperCase()} 
}
</code></pre>
<p>postUppercase becomes from a function to a variable that contains an anonymous function, this syntax allows us to define the types for the parameters, the return, and the context (this) of the function with a single type:</p>
<pre><code class="lang-typescript">RouteHandlerTypebox&lt;<span class="hljs-keyword">typeof</span> schemaPostUppercase&gt;
</code></pre>
<p>Let's see its definition:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> RouteHandlerTypebox&lt;TSchema <span class="hljs-keyword">extends</span> FastifySchema&gt; = <span class="hljs-function">(<span class="hljs-params">
  <span class="hljs-built_in">this</span>: FastifyInstanceTypebox,
  request: FastifyRequestTypebox&lt;TSchema&gt;,
  reply: FastifyReplyTypebox&lt;TSchema&gt;
</span>) =&gt;</span> ResolveFastifyReplyReturnType&lt;TypeBoxTypeProvider, TSchema, RouteGenericInterface&gt;
</code></pre>
<p>In the RouteHandlerTypebox type, we are going to define types for:</p>
<ul>
<li><p>this: the context of the function i.e. when you want to access the 'fastify' object via 'this'</p>
</li>
<li><p>request: the first parameter of the function</p>
</li>
<li><p>reply: the second parameter of the function</p>
</li>
<li><p>function return: ResolveFastifyReplyReturnType</p>
</li>
</ul>
<p>Manually typing with the schema: request, reply, and the return of the function, which takes the generic type: TSchema.</p>
<blockquote>
<p>Manuel Salinardi</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Dev Retro 2022: My journey as a freelance developer]]></title><description><![CDATA[Hello devs! 👋
I am a freelance full stack developer and I have been collaborating full time for years for an Italian company: Icona, of which I am part of the development team of one of their products: Acty, an amazing app for remote technical assis...]]></description><link>https://blog.manuelsalinardi.dev/dev-retro-2022-my-journey-as-a-freelance-developer</link><guid isPermaLink="true">https://blog.manuelsalinardi.dev/dev-retro-2022-my-journey-as-a-freelance-developer</guid><category><![CDATA[#DevRetro2022]]></category><category><![CDATA[journey]]></category><category><![CDATA[Freelancing]]></category><dc:creator><![CDATA[Manuel Salinardi]]></dc:creator><pubDate>Thu, 22 Dec 2022 03:07:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1671513176791/AA7EpJaL8.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello devs! 👋</p>
<p>I am a freelance full stack developer and I have been collaborating full time for years for an Italian company: <a target="_blank" href="https://www.icona.it">Icona</a>, of which I am part of the development team of one of their products: <a target="_blank" href="https://www.acty.com">Acty</a>, an amazing app for remote technical assistance.</p>
<p>Luckily <a target="_blank" href="https://www.acty.com">Acty</a> is an innovative product and during my working days it allows me to work with exciting technologies such as:</p>
<ol>
<li><p>Javascript</p>
</li>
<li><p>Typescript</p>
</li>
<li><p>React</p>
</li>
<li><p>WebRTC</p>
</li>
<li><p>WebSocket with Socket.io</p>
</li>
<li><p>Webdriver.io</p>
</li>
<li><p>Node.js</p>
</li>
<li><p>Express</p>
</li>
<li><p>Fastify</p>
</li>
<li><p>Swagger</p>
</li>
<li><p>MongoDB</p>
</li>
<li><p>Redis</p>
</li>
<li><p>Augmented reality</p>
</li>
<li><p>and more...</p>
</li>
</ol>
<p>In this article I won't talk about what I've accomplished in this working year 2022 for <a target="_blank" href="https://www.icona.it">Icona</a>, also because I would need a whole book, but about my activities outside the working day.</p>
<h2 id="heading-web-30">♦️ Web 3.0</h2>
<p><a target="_blank" href="https://ethereum.org/en/"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671516710154/WZQ0j1KT-.png" alt /></a></p>
<p>My year 2022 began by studying and deepening everything related to the so-called Web 3.0, in particular, I studied:</p>
<ul>
<li><p>Blockchain</p>
</li>
<li><p>Ethereum ecosystem</p>
</li>
<li><p>Smart contracts</p>
</li>
<li><p>Solidity</p>
</li>
<li><p>NFT</p>
</li>
</ul>
<p>I started by taking these 2 courses on Udemy:</p>
<ul>
<li><p><a target="_blank" href="https://www.udemy.com/share/101wx43@Dh-eFqgv5BF2jFToLLEKAov6uWUqIWJlc0GIBRYBt2KxFpclEArZ8EmIW-GJyxUC/">Ethereum Blockchain Developer Bootcamp With Solidity (2022)</a></p>
</li>
<li><p><a target="_blank" href="https://www.udemy.com/share/101WhE3@Q4fdqShvj8ZEzCq7M0ThUvwEuNvo4UFE5V7ipFlrT_Q5n2UdppzdECQ91CENM39F/">Blockchain A-Z™: Learn How To Build Your First Blockchain</a></p>
</li>
</ul>
<p>Then read this book: <a target="_blank" href="https://www.amazon.it/Mastering-Ethereum-Building-Smart-Contracts/dp/1491971940/ref=sr_1_5?__mk_it_IT=%C3%85M%C3%85%C5%BD%C3%95%C3%91&amp;crid=1O6DZRGZ0ORB3&amp;keywords=ethereum&amp;qid=1671152054&amp;sprefix=ethereum%2Caps%2C366&amp;sr=8-5">Mastering Ethereum: Building Smart Contracts and Dapps</a>.</p>
<p>Both the courses and the book have been excellent resources, many times it is not easy to find good material, but this time I was lucky.</p>
<h3 id="heading-nft">NFT</h3>
<p>After that I felt the need to put into practice the concepts learned on a real project, fate has it that a childhood friend called me and told me that he had to create an NFT project on behalf of one of his clients.</p>
<p>I took the opportunity and created the project, with interesting features such as:</p>
<ul>
<li><p>Smart contract upgradable</p>
</li>
<li><p>Metadata revealing</p>
</li>
<li><p>Addresses in the white list with different price</p>
</li>
<li><p>Minting web app</p>
</li>
<li><p>Max 4 NFT per wallet</p>
</li>
<li><p>Block public mint</p>
</li>
<li><p>Drops NFT</p>
</li>
</ul>
<p>The project was deployed on the Ethereum main net and the collection is visible on the major Marketplaces such as Opensea: <a target="_blank" href="https://opensea.io/collection/cryptomadonne">CryptoMadonne</a>, for information about the project: <a target="_blank" href="https://cryptomadonne.com">https://cryptomadonne.com</a></p>
<h2 id="heading-toptal">♦️ TopTal</h2>
<p><a target="_blank" href="https://www.toptal.com/"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671516515997/3cQdSfVKD.png" alt /></a></p>
<p>To look for some extra projects I started exploring the various platforms for freelancers such as:</p>
<ul>
<li><p><a target="_blank" href="https://www.toptal.com">TopTal</a></p>
</li>
<li><p><a target="_blank" href="https://www.freelancer.com">Freelancer</a></p>
</li>
<li><p><a target="_blank" href="https://www.upwork.com">Upwork</a></p>
</li>
</ul>
<p>Doing some research, I concluded that the best for me was TopTal. The difference between TopTal and the other platforms is that TopTal has a high barrier to entry, i.e. to join TopTal you must pass a 4-step Screening Process, but then to continue being part of it you must continue to excel. They claim that only 3% of applicants make it through all steps, more info here: <a target="_blank" href="https://www.toptal.com/top-3-percent">https://www.toptal.com/top-3-percent</a></p>
<p>This could discourage many, but for me, it is a great advantage because, in the other platforms where everyone can enter even without skills, you would find yourself competing with people with little or no experience who obviously can afford to make much lower prices than yours.</p>
<p>So I applied, went through all stages and I passed 🎉</p>
<p>I can confirm that the standards are very high.</p>
<p>The final step was a project to be done in a week. Afterward, during a call with a TopTal expert, the project is evaluated and he makes sure that the project has all the requested features, but also that the code is secure and scalable and that all edge cases are managed correctly.</p>
<p>Now I'm working on my first project with TopTal and for now, I'm really satisfied!</p>
<p>This is my TopTal profile: <a target="_blank" href="https://www.toptal.com/resume/manuel-salinardi">https://www.toptal.com/resume/manuel-salinardi</a></p>
<h2 id="heading-nodejs-certification">♦️ Node.js Certification</h2>
<p><a target="_blank" href="https://www.credly.com/badges/5c42903c-0ac0-491d-a1fb-ebb30bff6c68"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671517203924/tJUTJ4VSm.png" alt /></a></p>
<p>I feel that a great way to study a programming language, or framework/library is by getting its official certification, because many times during normal use of it, for example within a project, all its potential is not explored.</p>
<p>Node.js has 2 official certifications:</p>
<ol>
<li><p><a target="_blank" href="https://training.linuxfoundation.org/certification/jsnad">OpenJS Node.js Application Developer (JSNAD)</a></p>
</li>
<li><p><a target="_blank" href="https://training.linuxfoundation.org/certification/jsnsd">OpenJS Node.js Services Developer (JSNSD)</a></p>
</li>
</ol>
<p>The first is with a focus on knowledge of Node.js core APIs, which I had taken in 2021.</p>
<p>In 2022 I took the second 🎉 with a focus on knowledge of RESTful Node.js Servers and Services.</p>
<p>In this link, there is my Credly profile with the certifications I have obtained: <a target="_blank" href="https://www.credly.com/users/manuel-salinardi/badges">https://www.credly.com/users/manuel-salinardi/badges</a></p>
<h2 id="heading-blogging">♦️ Blogging</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671517343339/sVpk42N0m.png" alt /></p>
<p>And we have reached the end of this 2022 and the desire to write coding tutorials are starting to grow in me, for various reasons, for example:</p>
<ul>
<li><p>Improving my writing</p>
</li>
<li><p>Improving my communication</p>
</li>
<li><p>Learn to write programs with graphs and charts</p>
</li>
<li><p>Learning by teaching and explaining concepts</p>
</li>
<li><p>Start building an online presence</p>
</li>
</ul>
<p>For my new adventure, I have to thank <a target="_blank" href="https://hashnode.com/">Hashnode</a>, which allows me to start writing articles like this one, only focuses on writing, without dealing with technical stuff, and also encourages me to do it with initiatives like <a target="_blank" href="https://townhall.hashnode.com/announcing-dev-retro-2022?source=hashnode_countdown">#DevRetro2022</a></p>
<p>This new blogging challenge bet will be the hardest because I have never written articles or books, and I'm better at coding than I am at English 🤓.</p>
<p>I've always been a big content customer. Content creation is definitely more complex, I hope I can make it and don't give up! 👊</p>
<h2 id="heading-goals-for-2023">♦️ Goals for 2023</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671517399638/IyWpjxNps.png" alt /></p>
<ul>
<li><p>Blogging</p>
</li>
<li><p>The 2 official MongoDB certifications</p>
</li>
<li><p>Study PostgreSQL</p>
</li>
<li><p>Study Web Audio API</p>
</li>
<li><p>Study WebGL</p>
</li>
<li><p>Study WebXR with a focus on AR</p>
</li>
</ul>
]]></content:encoded></item></channel></rss>