<?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[Imad Atyat-Allah's Hashnode Blog]]></title><description><![CDATA[Self-taught Full Stack JavaScript/TypeScript developer with passion for Front-End.]]></description><link>https://hashnode.imadatyat.me</link><generator>RSS for Node</generator><lastBuildDate>Sun, 17 May 2026 13:37:12 GMT</lastBuildDate><atom:link href="https://hashnode.imadatyat.me/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Schema Validation with Zod and Express.js]]></title><description><![CDATA[This guide was originally published on my personal portfolio

What is Zod?
Zod is a TypeScript-first schema declaration and validation library, Created by Colin McDonnell. Unlike Yup, Zod is TypeScript-first which means it has a lot of features for T...]]></description><link>https://hashnode.imadatyat.me/schema-validation-with-zod-and-expressjs</link><guid isPermaLink="true">https://hashnode.imadatyat.me/schema-validation-with-zod-and-expressjs</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Validation]]></category><category><![CDATA[Express]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Imad Atyat-Allah]]></dc:creator><pubDate>Mon, 20 Dec 2021 12:06:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1645185842010/-fIm4cAvC.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p>This guide was originally published on <a target="_blank" href="https://imadatyatalah.vercel.app/guides/schema-validation-with-zod-and-expressjs">my personal portfolio</a></p>
</blockquote>
<h2 id="heading-what-is-zod">What is Zod?</h2>
<p><a target="_blank" href="https://github.com/colinhacks/zod">Zod</a> is a TypeScript-first schema declaration and validation library, Created by <a target="_blank" href="https://twitter.com/colinhacks">Colin McDonnell</a>. Unlike <a target="_blank" href="https://github.com/jquense/yup">Yup</a>, Zod is TypeScript-first which means it has a lot of features for TypeScript developers.</p>
<p>Zod comes with some really great features like:</p>
<ul>
<li>Works in Node.js and browsers (including IE 11)</li>
<li>Zero dependencies</li>
<li>Works with JavaScript too</li>
</ul>
<h2 id="heading-why-do-you-need-to-validate-your-api-calls">Why do you need to validate your API Calls?</h2>
<p>Validating your API Calls helps you get the right data that you want, For example, you want your users to have a strong password(e.g. at least 6 characters), You can use something like Zod or Yup and prevent users from entering a short password(less than 6 characters). Also, doing validation on the server makes your server much more secure, Because no one can open the developer tools, go through your code, and figure out how to beat your validation.</p>
<h2 id="heading-lets-start-coding">Let's start coding</h2>
<p>First, Create an empty directory and navigate into it:</p>
<pre><code class="lang-bash">mkdir schema-validation-with-zod-and-expressjs
<span class="hljs-built_in">cd</span> schema-validation-with-zod-and-expressjs
</code></pre>
<p>Then, Initialize a Node.js project and add the necessary dependencies:</p>
<pre><code class="lang-bash">npm init -y
npm install express zod
</code></pre>
<p>Next, add the following script to our <code>package.json</code> file.</p>
<pre><code class="lang-json">{
  <span class="hljs-comment">// ...</span>
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"dev"</span>: <span class="hljs-string">"node index.js"</span>
  }
  <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>Now let's start an Express.js server.
Create a file called <code>index.js</code> at the root of the project:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);

<span class="hljs-keyword">const</span> app = express();

app.use(express.json());

app.listen(<span class="hljs-number">1337</span>, <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`&gt; Ready on http://localhost:<span class="hljs-subst">${<span class="hljs-number">1337</span>}</span>`</span>));
</code></pre>
<p>Then run the Express.js server(You can access it at <a target="_blank" href="http://localhost:1337"><code>http://localhost:1337</code></a>).</p>
<pre><code class="lang-bash">npm run dev
</code></pre>
<p>Next, we can start working with Zod,
Let's first import <code>z</code> from <code>zod</code> and add a simple login schema.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);
<span class="hljs-keyword">const</span> { z } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"zod"</span>);

<span class="hljs-keyword">const</span> app = express();

app.use(express.json());

<span class="hljs-keyword">const</span> LoginSchema = z.object({
  <span class="hljs-comment">// In this example we will only validate the request body.</span>
  <span class="hljs-attr">body</span>: z.object({
    <span class="hljs-comment">// email should be valid and non-empty</span>
    <span class="hljs-attr">email</span>: z.string().email(),
    <span class="hljs-comment">// password should be at least 6 characters</span>
    <span class="hljs-attr">password</span>: z.string().min(<span class="hljs-number">6</span>),
  }),
});

<span class="hljs-comment">// ...</span>
</code></pre>
<p>Now we are going to create our middleware for Zod validation.</p>
<pre><code class="lang-js"><span class="hljs-comment">// ...</span>

<span class="hljs-keyword">const</span> validate = <span class="hljs-function">(<span class="hljs-params">schema</span>) =&gt;</span> <span class="hljs-function">(<span class="hljs-params">req, res, next</span>) =&gt;</span> {
  <span class="hljs-keyword">try</span> {
    schema.parse({
      <span class="hljs-attr">body</span>: req.body,
      <span class="hljs-attr">query</span>: req.query,
      <span class="hljs-attr">params</span>: req.params,
    });

    next();
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).send(err.errors);
  }
};

<span class="hljs-comment">// ...</span>
</code></pre>
<p>Finally, we are going to create a route(<code>/login</code>) for <code>POST</code> requests,
which we will use our middleware(<code>validate</code>) to perform the validation of the request body.</p>
<pre><code class="lang-js"><span class="hljs-comment">// ...</span>

<span class="hljs-comment">// pass LoginSchema to validate middleware</span>
app.post(<span class="hljs-string">"/login"</span>, validate(LoginSchema), <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> res.json({ ...req.body });
});

<span class="hljs-comment">// ...</span>
</code></pre>
<p>The final code would be as follows:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);
<span class="hljs-keyword">const</span> { z } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"zod"</span>);

<span class="hljs-keyword">const</span> app = express();

app.use(express.json());

<span class="hljs-keyword">const</span> LoginSchema = z.object({
  <span class="hljs-comment">// In this example we will only validate the request body.</span>
  <span class="hljs-attr">body</span>: z.object({
    <span class="hljs-comment">// email should be valid and non-empty</span>
    <span class="hljs-attr">email</span>: z.string().email(),
    <span class="hljs-comment">// password should be at least 6 characters</span>
    <span class="hljs-attr">password</span>: z.string().min(<span class="hljs-number">6</span>),
  }),
});

<span class="hljs-keyword">const</span> validate = <span class="hljs-function">(<span class="hljs-params">schema</span>) =&gt;</span> <span class="hljs-function">(<span class="hljs-params">req, res, next</span>) =&gt;</span> {
  <span class="hljs-keyword">try</span> {
    schema.parse({
      <span class="hljs-attr">body</span>: req.body,
      <span class="hljs-attr">query</span>: req.query,
      <span class="hljs-attr">params</span>: req.params,
    });

    next();
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).send(err.errors);
  }
};

app.post(<span class="hljs-string">"/login"</span>, validate(LoginSchema), <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> res.json({ ...req.body });
});

app.listen(<span class="hljs-number">1337</span>, <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`&gt; Ready on http://localhost:<span class="hljs-subst">${<span class="hljs-number">1337</span>}</span>`</span>));
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this guide, We learned how to validate our Express.js REST API Calls using Zod, You can find the code on <a target="_blank" href="https://github.com/imadatyatalah/schema-validation-with-zod-and-expressjs-guide">GitHub</a>.</p>
<p>Make sure to <a target="_blank" href="https://twitter.com/ImadAtyat">contact me</a> if you have any questions.</p>
]]></content:encoded></item><item><title><![CDATA[How to setup Contentlayer in your Next.js app?]]></title><description><![CDATA[Note: Contentlayer is still in development and some APIs might change!

What is Contentlayer?
Contentlayer turns your content into data - making it super easy to import MD(X) and CMS content in your app.
Automatic Setup
The easiest way to create a ne...]]></description><link>https://hashnode.imadatyat.me/how-to-setup-contentlayer-in-your-nextjs-app</link><guid isPermaLink="true">https://hashnode.imadatyat.me/how-to-setup-contentlayer-in-your-nextjs-app</guid><category><![CDATA[Next.js]]></category><category><![CDATA[markdown]]></category><category><![CDATA[guide]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Imad Atyat-Allah]]></dc:creator><pubDate>Tue, 19 Oct 2021 09:50:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1636106155801/PcwpJ6pD3.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p>Note: Contentlayer is still in development and some APIs might change!</p>
</blockquote>
<h2 id="heading-what-is-contentlayer">What is Contentlayer?</h2>
<p><a target="_blank" href="https://www.contentlayer.dev">Contentlayer</a> turns your content into data - making it super easy to import MD(X) and CMS content in your app.</p>
<h2 id="heading-automatic-setup">Automatic Setup</h2>
<p>The easiest way to create a new Next.js app with Contentlayer is by using <a target="_blank" href="https://github.com/vercel/next.js/tree/canary/examples/with-contentlayer">official Next.js example</a>,
which sets up everything automatically for you. To create a project, run:</p>
<pre><code class="lang-bash">npx create-next-app --example with-contentlayer with-contentlayer-app
<span class="hljs-comment"># or</span>
yarn create next-app --example with-contentlayer with-contentlayer-app
</code></pre>
<p>After the installation is complete:</p>
<ul>
<li>Run <code>npm run dev</code> or <code>yarn dev</code> to start the development server on <code>http://localhost:3000</code>.</li>
<li>Visit <code>http://localhost:3000</code> to view your application</li>
</ul>
<h2 id="heading-manual-setup">Manual Setup</h2>
<h3 id="heading-install-contentlayer-in-your-nextjs-app">Install Contentlayer in your Next.js app</h3>
<pre><code class="lang-shell">npm install contentlayer next-contentlayer
# or
yarn add contentlayer next-contentlayer
</code></pre>
<h3 id="heading-add-your-contentlayer-config">Add your Contentlayer config</h3>
<p>Create <code>contentlayer.config.js</code> file at the root of the project with the following code.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { defineDocumentType, makeSource } <span class="hljs-keyword">from</span> <span class="hljs-string">"contentlayer/source-files"</span>;

<span class="hljs-keyword">const</span> Post = defineDocumentType(<span class="hljs-function">() =&gt;</span> ({
  <span class="hljs-attr">name</span>: <span class="hljs-string">"Post"</span>,
  <span class="hljs-attr">filePathPattern</span>: <span class="hljs-string">`**/*.md`</span>,
  <span class="hljs-attr">contentType</span>: <span class="hljs-string">"markdown"</span>,
  <span class="hljs-attr">fields</span>: {
    <span class="hljs-attr">title</span>: { <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>, <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span> },
    <span class="hljs-attr">date</span>: { <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>, <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span> },
  },
  <span class="hljs-attr">computedFields</span>: {
    <span class="hljs-attr">slug</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
      <span class="hljs-attr">resolve</span>: <span class="hljs-function">(<span class="hljs-params">doc</span>) =&gt;</span> doc._raw.sourceFileName.replace(<span class="hljs-regexp">/\.md/</span>, <span class="hljs-string">""</span>),
    },
  },
}));

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> makeSource({
  <span class="hljs-attr">contentDirPath</span>: <span class="hljs-string">"posts"</span>,
  <span class="hljs-attr">documentTypes</span>: [Post],
});
</code></pre>
<h3 id="heading-set-up-nextjs-plugin-in-nextconfigjs-optional-enables-live-reload-and-build-setup">Set up Next.js plugin in <code>next.config.js</code> (optional: enables live-reload and build setup)</h3>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> { withContentlayer } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"next-contentlayer"</span>);

<span class="hljs-built_in">module</span>.exports = withContentlayer({
  <span class="hljs-comment">// Your Next.js config...</span>
});
</code></pre>
<h3 id="heading-add-a-jsconfigjson-file">Add a <code>jsconfig.json</code> file</h3>
<pre><code class="lang-json">{
  <span class="hljs-attr">"compilerOptions"</span>: {
    <span class="hljs-attr">"baseUrl"</span>: <span class="hljs-string">"."</span>,
    <span class="hljs-attr">"paths"</span>: {
      <span class="hljs-attr">"contentlayer/generated"</span>: [<span class="hljs-string">"./.contentlayer/generated"</span>]
    }
  },
  <span class="hljs-attr">"include"</span>: [<span class="hljs-string">".contentlayer/generated"</span>]
}
</code></pre>
<p>In case you are using TypeScript in your project you already have a <code>tsconfig.json</code> to which you will add these lines of code to.</p>
<pre><code class="lang-diff">{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
       // These option allow you to configure module aliases.
       // So you will import contentlayer generated content from "contentlayer/generated" instead of "./.contentlayer/generated"
<span class="hljs-addition">+      "contentlayer/generated": ["./.contentlayer/generated"]</span>
    }
  },
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx",
<span class="hljs-addition">+    ".contentlayer/generated"</span>
  ],
}
</code></pre>
<h3 id="heading-add-some-posts">Add some posts</h3>
<ol>
<li>Add <code>posts</code> folder at the root of your app(Where your content will live).</li>
<li>Add <code>.md</code> files(e.g. <code>pre-rendering.md</code>).</li>
<li>Add your content(You can write anything you want, This is just an example).</li>
</ol>
<pre><code class="lang-md">---
title: "Two Forms of Pre-rendering"
<span class="hljs-section">date: "2020-01-01"
---</span>

Next.js has two forms of pre-rendering: <span class="hljs-strong">**Static Generation**</span> and <span class="hljs-strong">**Server-side Rendering**</span>. The difference is in <span class="hljs-strong">**when**</span> it generates the HTML for a page.

<span class="hljs-bullet">-</span> <span class="hljs-strong">**Static Generation**</span> is the pre-rendering method that generates the HTML at <span class="hljs-strong">**build time**</span>. The pre-rendered HTML is then <span class="hljs-emphasis">_reused_</span> on each request.
<span class="hljs-bullet">-</span> <span class="hljs-strong">**Server-side Rendering**</span> is the pre-rendering method that generates the HTML on <span class="hljs-strong">**each request**</span>.

Importantly, Next.js lets you <span class="hljs-strong">**choose**</span> which pre-rendering form to use for each page. You can create a "hybrid" Next.js app by using Static Generation for most pages and using Server-side Rendering for others.
</code></pre>
<h3 id="heading-fetch-and-display-your-posts">Fetch and display your posts</h3>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> Link <span class="hljs-keyword">from</span> <span class="hljs-string">"next/link"</span>;
<span class="hljs-keyword">import</span> { allPosts } <span class="hljs-keyword">from</span> <span class="hljs-string">"contentlayer/generated"</span>;
<span class="hljs-keyword">import</span> { pick } <span class="hljs-keyword">from</span> <span class="hljs-string">"@contentlayer/client"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params">{ posts }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">section</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
        {posts.map(({ slug, date, title }) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{slug}</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">{</span>`/<span class="hljs-attr">posts</span>/${<span class="hljs-attr">slug</span>}`}&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">a</span>&gt;</span>{title}<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">small</span>&gt;</span>{date}<span class="hljs-tag">&lt;/<span class="hljs-name">small</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        ))}
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// Statically fetch all posts</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticProps</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> posts = allPosts.map(<span class="hljs-function">(<span class="hljs-params">post</span>) =&gt;</span> pick(post, [<span class="hljs-string">"title"</span>, <span class="hljs-string">"date"</span>, <span class="hljs-string">"slug"</span>]));

  <span class="hljs-keyword">return</span> { <span class="hljs-attr">props</span>: { posts } };
}
</code></pre>
<h3 id="heading-create-dynamic-routes-for-each-post">Create dynamic routes for each post</h3>
<p>In this section, you should know how <a target="_blank" href="https://nextjs.org/docs/routing/dynamic-routes">dynamic routes</a> works in Next.js,</p>
<p>Add <code>posts/[slug].js</code> inside <code>pages</code> folder.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { allPosts } <span class="hljs-keyword">from</span> <span class="hljs-string">'contentlayer/generated'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Post</span>(<span class="hljs-params">{ post }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">article</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{post.title}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{post.date}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">dangerouslySetInnerHTML</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">__html:</span> <span class="hljs-attr">post.body.html</span> }} /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">article</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticPaths</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">paths</span>: allPosts.map(<span class="hljs-function">(<span class="hljs-params">p</span>) =&gt;</span> ({ <span class="hljs-attr">params</span>: { <span class="hljs-attr">slug</span>: p.slug } })),
    <span class="hljs-attr">fallback</span>: <span class="hljs-literal">false</span>,
  }
}

<span class="hljs-comment">// Statically fetch post by slug</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticProps</span>(<span class="hljs-params">{ params }</span>) </span>{
  <span class="hljs-keyword">const</span> post = allPosts.find(<span class="hljs-function">(<span class="hljs-params">post</span>) =&gt;</span> post.slug === params?.slug)

  <span class="hljs-keyword">return</span> { <span class="hljs-attr">props</span>: { post } }
}
</code></pre>
<p>Now we are done 🎉, Check <a target="_blank" href="http://localhost:3000">http://localhost:3000</a> to see the results!</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this guide, We learned about how we can integrate Next.js with Contentlayer,
As well as how we can display all posts and post by slug.</p>
<p>An online demo of the application that we built is hosted on <a target="_blank" href="https://nextjs-contentlayer-guide.vercel.app">Vercel</a>
and the code is available on <a target="_blank" href="https://github.com/imadatyatalah/nextjs-contentlayer-guide">GitHub</a> for TypeScript version check out this <a target="_blank" href="https://github.com/imadatyatalah/nextjs-contentlayer-guide/tree/typescript">GitHub branch</a>.</p>
<p>Thanks to <a target="_blank" href="https://twitter.com/schickling">Johannes Schickling</a> for providing this really great tool!
Make sure to <a target="_blank" href="https://twitter.com/ImadAtyat">contact me</a> if you have any questions.</p>
]]></content:encoded></item></channel></rss>