<?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[Jamin's notes]]></title><description><![CDATA[Jamin's notes]]></description><link>https://blog.jamin.sh</link><generator>RSS for Node</generator><lastBuildDate>Mon, 20 Apr 2026 13:19:01 GMT</lastBuildDate><atom:link href="https://blog.jamin.sh/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How to Deploy Directus to Render.com]]></title><description><![CDATA[Directus is an open-source backend-as-a-service platform that offers a user-friendly interface that simplifies building fully functional backend services, APIs, and graphQL endpoints. This ease of use extends to Render, a fully managed cloud platform...]]></description><link>https://blog.jamin.sh/how-to-deploy-directus-to-rendercom</link><guid isPermaLink="true">https://blog.jamin.sh/how-to-deploy-directus-to-rendercom</guid><category><![CDATA[directus]]></category><category><![CDATA[deployment]]></category><category><![CDATA[render.com]]></category><category><![CDATA[PostgreSQL]]></category><category><![CDATA[Databases]]></category><category><![CDATA[Docker]]></category><dc:creator><![CDATA[Trust Jamin]]></dc:creator><pubDate>Wed, 03 Apr 2024 01:54:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1712107558595/5a334ff2-bed3-44aa-a288-317b22de80cf.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a target="_blank" href="https://directus.io/">Directus</a> is an open-source backend-as-a-service platform that offers a user-friendly interface that simplifies building fully functional backend services, APIs, and graphQL endpoints. This ease of use extends to <a target="_blank" href="https://render.com/">Render</a>, a fully managed cloud platform where you can effortlessly host static sites, backend APIs, databases, and all other components for your web application. In this article, you’ll learn how to deploy a self-hosted instance of Directus to Render and connect it to a PostgreSQL database.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before you begin this tutorial, you will need a <a target="_blank" href="https://render.com/">Render</a> account; the free plan is good enough to follow along with this tutorial.</p>
<h2 id="heading-step-1-set-up-a-postgresql-database">Step 1: Set Up a PostgreSQL Database</h2>
<p>On your <a target="_blank" href="http://Render.com">Render</a> account<a target="_blank" href="http://render.com/">,</a> click on the “New +” button and Click on PostgreSQL to create a new PostgreSQL database.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712107775927/02e0fb4b-cbb1-4817-a9d6-1e1637a4a4da.png" alt class="image--center mx-auto" /></p>
<p>On the database creation page, add a name for your PostgreSQL instance, a database name, a user, and the region from which you want the PostgreSQL instance to run. Also, select “For hobby projects” as the instance type for a free tier.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712107844697/6164ddc7-284d-41a0-9f29-3ec79a65a4a6.png" alt class="image--center mx-auto" /></p>
<p>Next, click on the Create Database button to create your PostgreSQL database.</p>
<p>You should be redirected to the created database page.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712107909079/20902436-077c-4277-abb5-6bfcce65645d.png" alt class="image--center mx-auto" /></p>
<p>You can scroll down to the <strong>Connections</strong> tab to find the credentials needed to communicate with the database you created.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712107994973/6d1ea596-0eb2-40d6-b063-6a1a51e87a7a.png" alt class="image--center mx-auto" /></p>
<p>Copy the <code>hostname</code>, <code>port</code>, <code>database</code>, <code>username</code>, and <code>password</code> and save them, as you’ll need them when creating an instance of Directus later in the next step of this tutorial:</p>
<h2 id="heading-step-2-deploy-an-instance-of-directus-from-docker-hub">Step 2: Deploy an Instance of Directus from Docker Hub</h2>
<p>On your <a target="_blank" href="http://Render.com">Render.com</a> account<a target="_blank" href="http://render.com/">,</a> click on the “New +” button and Click on “Web Service” to create a new web service</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712108252611/38d2e2ad-651d-4852-a568-f733cbd9af99.png" alt class="image--center mx-auto" /></p>
<p>Select the second option on the “How would you like to deploy your web service?” page, then click next.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712108313905/df6366c0-3749-461e-bbb0-a9da1e901ca4.png" alt class="image--center mx-auto" /></p>
<p>The next page will ask you for the image URL you want to deploy. Paste the official Directus URL from the Docker hub below into the input field, and click on next:</p>
<pre><code class="lang-bash">https://hub.docker.com/r/directus/directus
</code></pre>
<p>On the web service creation page, you can add your preferred name for your web service and the region where you want the web service to run; also, select the <strong>For Hobby Projects</strong> as the <strong>Instance Type</strong> plan.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712108548578/3b95136e-701c-432d-9045-aa33334a3945.png" alt class="image--center mx-auto" /></p>
<p>On the <strong>Environment Variables</strong> tab, add the following variables to set up the Directus instance:</p>
<pre><code class="lang-yaml"><span class="hljs-string">ADMIN_EMAIL</span> <span class="hljs-string">=</span> <span class="hljs-string">admin@example.com</span>
<span class="hljs-string">ADMIN_PASSWORD</span> <span class="hljs-string">=</span> <span class="hljs-string">d1r3ctu5</span>
<span class="hljs-string">DB_CLIENT</span> <span class="hljs-string">=</span> <span class="hljs-string">postgres</span>
<span class="hljs-string">DB_DATABASE</span> <span class="hljs-string">=</span> <span class="hljs-string">YOUR_DB_NAME_FROM_STEP_1</span>
<span class="hljs-string">DB_HOST</span> <span class="hljs-string">=</span> <span class="hljs-string">YOUR_DB_HOSTNAME_FROM_STEP_1</span>
<span class="hljs-string">DB_PASSWORD</span> <span class="hljs-string">=</span> <span class="hljs-string">YOUR_DB_PASSWORD_FROM_STEP_1</span>
<span class="hljs-string">DB_PORT</span> <span class="hljs-string">=</span> <span class="hljs-number">5432</span>
<span class="hljs-string">DB_USER</span> <span class="hljs-string">=</span> <span class="hljs-string">YOUR_DB_USER_FROM_STEP_1</span>
<span class="hljs-string">KEY</span> <span class="hljs-string">=</span> <span class="hljs-string">YOUR_RANDOM_KEY</span>
<span class="hljs-string">SECRET</span> <span class="hljs-string">=</span> <span class="hljs-string">YOUR_RANDOM_SECRET</span>
<span class="hljs-string">WEBSOCKETS_ENABLED</span> <span class="hljs-string">=</span> <span class="hljs-literal">true</span>
</code></pre>
<p>Click on the “Create Web Service” button, and this will deploy a new instance of Directus as a web service for you.</p>
<p>After deployment, you will be redirected to the web service page with all the details about your web service. Click on the live URL of your web service, and it should open Directus in a new tab.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712108788150/ac0bc16e-0062-416e-bce6-2d0e67c9d243.png" alt class="image--center mx-auto" /></p>
<p>Congratulations! 🥳 you’ve just deployed an instance of Directus on <a target="_blank" href="http://Render.com">Render</a> and connected it to a PostgreSQL database.</p>
<h2 id="heading-summary">Summary</h2>
<p>In this article, you successfully created a PostgreSQL instance and deployed Directus to <a target="_blank" href="http://Render.com">Render.com</a>; some possible next steps you can take to improve your deployment might include setting up autoscaling to handle large incoming requests on your Directus application and enabling cron jobs to run backups for your application. (This involves upgrading to a paid account on <a target="_blank" href="http://Render.com">Render</a> 😉).</p>
<p>Directus also has a <a target="_blank" href="https://directus.io/cloud">Directus Cloud</a> version that offers constant backups, rolling updates, round-the-clock monitoring, and the ability to restart automatically in the event of a crash.</p>
<p>I hope this article is helpful to you.</p>
<p>Happy coding!🍻</p>
<p>I'd love to connect with you on <a target="_blank" href="https://twitter.com/codejagaban"><strong>Twitter</strong></a> | <a target="_blank" href="https://www.linkedin.com/in/codejagaban/"><strong>LinkedIn</strong></a> | <a target="_blank" href="https://github.com/codejagaban/"><strong>GitHub</strong></a></p>
]]></content:encoded></item><item><title><![CDATA[What is cross-browser compatibility, and why should you care?]]></title><description><![CDATA[Picture this scenario: You worked hard to build your company's website or app, and it worked. It seems to be functioning. A few days later, the product team informed you that people reported that the website looked terrible on the Edge browser in Win...]]></description><link>https://blog.jamin.sh/what-is-cross-browser-compatibility-and-why-should-you-care</link><guid isPermaLink="true">https://blog.jamin.sh/what-is-cross-browser-compatibility-and-why-should-you-care</guid><category><![CDATA[Testing]]></category><category><![CDATA[cross browser testing]]></category><category><![CDATA[Developer]]></category><category><![CDATA[CSS]]></category><dc:creator><![CDATA[Trust Jamin]]></dc:creator><pubDate>Fri, 29 Mar 2024 10:44:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1711709001925/66080512-c940-40e8-854d-7d26dd3631e4.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Picture this scenario: You worked hard to build your company's website or app, and it worked. It seems to be functioning. A few days later, the product team informed you that people reported that the website looked terrible on the Edge browser in Windows, and several functionalities are not working.</p>
<p>“But everything works fine on my machine,” you might say. The machine referred to might be a 2021 M1 MacBook Pro, yet the user complaining may be using a 2015 Windows 10 laptop or something else. How do you tackle this issue? How do you ensure your websites and web apps are compatible with all other browsers and devices, not just the one you used for developing? This article will discuss cross-browser compatibility and its significance, methods to ensure compatibility, and practical tips for ensuring cross-browser compatibility in your websites.</p>
<h1 id="heading-what-is-cross-browser-compatibility">What is Cross-Browser Compatibility?</h1>
<p>Cross-browser compatibility is the ability of your website or web application to function consistently and correctly across various devices and web browsers. It ensures that browsers like Google Chrome, Mozilla Firefox, Apple Safari, Microsoft Edge, and others interpret and render your website uniformly.</p>
<h2 id="heading-common-causes-of-cross-browser-compatibility-issues">Common Causes of Cross-Browser Compatibility Issues</h2>
<ol>
<li><strong>Different Browser Rendering Engines:</strong></li>
</ol>
<p>Each browser employs its rendering engine (e.g., Blink for Chrome, WebKit for Safari, Gecko for Firefox). These engines may interpret and display website code differently.</p>
<ol start="2">
<li><strong>Different Devices:</strong></li>
</ol>
<p>Different devices, such as Laptops, Tablets, and smartphones, display your website differently to their user.</p>
<h2 id="heading-why-cross-browser-compatibility-matters">Why Cross-Browser Compatibility Matters</h2>
<p>As a developer, understanding the importance of cross-browser compatibility is essential for several reasons:</p>
<ol>
<li><p><strong>User Experience:</strong> A seamless experience across different browsers contributes to positive user experiences, which in turn impact user satisfaction and business success. If a user visits your website and notices things are not displayed correctly, it might give them a bad experience and deter them from revisiting it.</p>
</li>
<li><p><strong>Reach Diverse Users:</strong> The internet's diversity means users access content via various browsers and devices. Compatibility ensures your website reaches a broader audience.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711707174601/9ec715a1-7b02-401a-822d-a6fb8901d9ce.png" alt="Statistic of browsers used to access the internet. Source: StatCounter" class="image--center mx-auto" /></p>
</li>
<li><p><strong>Better SEO:</strong> Search engines favor websites with consistent positive experiences across browsers. Neglecting compatibility can adversely affect search rankings.</p>
</li>
<li><p><strong>Future-Proofing Your Code:</strong> Evolving browsers introduce new features. Cross-browser compatibility ensures your application remains functional amid these changes.</p>
</li>
</ol>
<h2 id="heading-tips-for-ensuring-cross-browser-compatibility">Tips for Ensuring Cross-Browser Compatibility</h2>
<ol>
<li><p><strong>Use Modern Web Standards</strong></p>
<p> Your HTML, CSS, and JavaScript code and website accessibility should follow the standard web practices, reducing the likelihood of compatibility issues with browsers. The <a target="_blank" href="https://www.w3.org/standards/">World Wide Web Consortium (W3C) develops open standards to ensure the long-term growth an</a>d accessibility of the World Wide Web. Following these standards will help ensure your website is compatible with the standard web browser.</p>
</li>
<li><p><strong>Practice Responsive Design</strong></p>
<p> Implementing fluid layouts, flexible images, and CSS media queries to provide a consistent user experience across various devices. These will help to make your website responsive to different devices that your users will visit from</p>
</li>
<li><p><strong>Validate Your Code</strong></p>
<p> Include tools like <a target="_blank" href="https://validator.w3.org/">W3C code validation service</a> <a target="_blank" href="https://validator.w3.org/">and CSS validator</a> <a target="_blank" href="https://www.cssportal.com/css-validator/">to</a> <a target="_blank" href="https://validator.w3.org/">ensure your code</a> <a target="_blank" href="https://www.cssportal.com/css-validator/">meets web sta</a>ndards.</p>
</li>
<li><p><strong>Test Early, Test Often</strong></p>
<p> Begin cross-browser Testing in the early stages of development to identify and address these issues. Frequent Testing can help you catch issues before they turn into significant problems.</p>
</li>
</ol>
<p><strong>Consider Using CSS Resets</strong></p>
<p>Use CSS resets to establish a baseline layout across browsers and minimize inconsistencies. Each browser has predefined padding, margin, and line height styles by default. Etc. Applying CSS resets before adding custom styling to your webpage helps you predict how elements render comfortably across different browsers.</p>
<pre><code class="lang-css"><span class="hljs-comment">/*

1. Use a box-sizing model.
*/</span>
*, *<span class="hljs-selector-pseudo">::before</span>, *<span class="hljs-selector-pseudo">::after</span> {
    <span class="hljs-attribute">box-sizing</span>: border-box;
}
<span class="hljs-comment">/*
2. Removes the default margin and padding on the browsers
*/</span>
 {
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
}
</code></pre>
<p>You can also consider using stylesheets like <a target="_blank" href="https://necolas.github.io/normalize.css/">Normalize.css</a>,  <a target="_blank" href="https://necolas.github.io/normalize.css/">Eric Mayer's</a> <a target="_blank" href="https://meyerweb.com/eric/tools/css/reset/">CSS reset rules</a> <a target="_blank" href="https://meyerweb.com/eric/tools/css/reset/"></a>to establish a baseline layout across browsers.</p>
<h2 id="heading-ia"> </h2>
<p>How to Test for Cross-Browser Compatibility  </p>
<ol>
<li><p><strong>Create a Plan:</strong> Based on audience research, determine target browsers and establish what your website should look like, what devices they would be using, and what browsers are primarily used in the region where your intended users will be. Having a plan will help you decide which browsers to test.</p>
</li>
<li><p><strong>Development:</strong> Strive for uniform functionality across all target browsers. Or use <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/Polyfill">polyfills</a> as needed. Some Browsers interpret your code differently on some styling features, so you should try styling them using browser-specific code; you can do this using prefixes. Some general prefixes used when targeting specific browsers are:</p>
<ul>
<li><p>Safari and Chrome <em>(-WebKit)</em></p>
</li>
<li><p>Internet Explorer <em>(-ms)</em></p>
</li>
<li><p>Opera (-o)</p>
</li>
<li><p>Mozilla Firefox <em>(-moz)</em></p>
</li>
</ul>
</li>
<li><p><strong>Testing:</strong> There are two types of Testing you should consider when performing cross-browser compatibility tests</p>
<ul>
<li><p><strong>Manuel Testing: This involves using live devices and browsers to test for functionality and consistency of your website. Consider using tools like</strong> <a target="_blank" href="https://www.browserstack.com/live">BrowserStack</a> and <a target="_blank" href="https://www.lambdatest.com/">Lambdatest</a>, which provide different device stimulations and browsers to identify inconsistency and performance issues on your website. And automated Testing using tools like <a target="_blank" href="https://www.browserstack.com/selenium">Selenium</a></p>
</li>
<li><p><strong>Automated Testing:</strong> This involves using automated scripts and tools to execute test cases and verify the functionality of your website on different browsers and devices. Some automated tools you can consider when performing cross-browser compatibility tests are <a target="_blank" href="https://playwright.dev/">Playwright</a> and <a target="_blank" href="https://www.browserstack.com/selenium">Selenium</a></p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-pitfalls-to-avoid-in-cross-browser-compatibility">Pitfalls to Avoid in Cross-Browser Compatibility</h2>
<p>There are a couple of pitfalls to avoid when ensuring your websites and web applications are cross-browser compatible; because cross-browser compatibility can be tedious, it's easy to fall into these pitfalls</p>
<ol>
<li><p><strong>Over-Engineering:</strong> Focus more on the core functionality of your website and the user experience it provides for your users rather than pursuing pixel-perfect consistency across all browsers. This will help you avoid over-engineering your product to target specific browsers.</p>
</li>
<li><p><strong>Ignoring Older Browsers:</strong> Balance dropping support for outdated browsers with considering your target audience's browser usage. For example, Microsoft retired the Internet Explorer browser in favor of its new Edge browser, so it wouldn't be wise to spend time making your website compatible with browsers like Internet Explorer that are no longer supported.</p>
</li>
<li><p><strong>Misusing Polyfills:</strong> While using <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/Polyfill">polyfills</a> can help you to implement features that are not present in a browser and flatten the browser API landscape, you should only use it judiciously for critical missing features to avoid unnecessary code bloat that might hurt your website performance.</p>
</li>
</ol>
<p><strong>Testing in Isolation:</strong> To better understand how your website will function in different environments. Test not only on individual browsers but also various combinations of devices and screen sizes.</p>
<h2 id="heading-best-practices-for-cross-browser-compatibility">Best Practices for Cross-Browser Compatibility</h2>
<ul>
<li><strong>Research Your Audience:</strong> Perform market research to understand your target audience's browser preferences based on their region. Do not test randomly with browsers, as this might not be adequate for your users.</li>
</ul>
<ul>
<li><p><strong>Prepare a Browser List To Test on:</strong> Limit development and test coverage efforts to a specific set of browsers relevant to your audience. A list of browsers will help you focus on pertinent issues for your target audience and reduce exposure to cross-browser bugs.</p>
</li>
<li><p><strong>Choose the Right Automation Tool:</strong> Since cross-browser compatibility testing is a tedious task and requires a lot of time and effort, consider selecting tools that are easy to use and allow Testing across a maximum number of browsers for maximum efficiency.</p>
</li>
<li><p><strong>Test on Real Device Browsers:</strong> Automated Testing should differ from manual Testing. Testing on actual device browsers will help you identify bugs that may arise on actual devices that your end-users will use, offering a more realistic testing environment.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Cross-browser compatibility is not just a checkbox; it's a journey of continuous improvement. By understanding its significance and following best practices, you can navigate this complex landscape, creating websites and software that provide a seamless experience for users across different browsers and devices.</p>
<p>Happy coding!</p>
<p>I'd love to connect with you on <a target="_blank" href="https://twitter.com/codejagaban"><strong>Twitter</strong></a> | <a target="_blank" href="https://www.linkedin.com/in/codejagaban/"><strong>LinkedIn</strong></a> | <a target="_blank" href="https://github.com/codejagaban/"><strong>GitHub</strong></a></p>
]]></content:encoded></item><item><title><![CDATA[A Beginner's Guide to Using Resend]]></title><description><![CDATA[As developers, we often include transactional email capabilities in your application to send emails to your users based on actions triggered in your applications, such as account creation/welcome emails, order confirmations, shipping notifications, p...]]></description><link>https://blog.jamin.sh/a-beginners-guide-to-using-resend</link><guid isPermaLink="true">https://blog.jamin.sh/a-beginners-guide-to-using-resend</guid><category><![CDATA[Developer]]></category><category><![CDATA[Go Language]]></category><category><![CDATA[resend]]></category><category><![CDATA[email]]></category><category><![CDATA[guide]]></category><dc:creator><![CDATA[Trust Jamin]]></dc:creator><pubDate>Wed, 24 Jan 2024 11:31:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1706095784320/c58dde25-7f87-4d43-8bb8-d705004c43f5.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As developers, we often include transactional email capabilities in your application to send emails to your users based on actions triggered in your applications, such as account creation/welcome emails, order confirmations, shipping notifications, password reset emails, booking confirmations, receipts and invoices, etc.</p>
<p>Resend is a developer-friendly API you can utilize for sending transactional emails from your application, and due to its ease of integration, it</p>
<p>In this article, we'll explain what resend is, some of its features, and why you should use it as your email provider for your applications.</p>
<h2 id="heading-introduction"><strong>Introduction</strong></h2>
<p><strong>What is Resend?</strong></p>
<p><a target="_blank" href="http://Resend.com">Resend.com</a> is an email API for developers. It's designed to help developers build, test, and send transactional emails at scale. Resend offers a simple, elegant interface that makes it easy to get started, and it integrates with popular programming languages like JavaScript, PHP, Java, Python, Go, and Ruby.</p>
<p>Resend can be used to send a variety of email types, including welcome emails, password reset emails, and order confirmation emails. It also offers a variety of features to help developers ensure that their emails are delivered successfully, such as email tracking and spam prevention.</p>
<h2 id="heading-features-of-resend"><strong>Features of Resend</strong></h2>
<p>Resend comes with a variety of features that make it stand out from other transactional email services. Let's consider some of them.</p>
<h3 id="heading-integration-with-popular-tools-and-languages">Integration with popular tools and languages</h3>
<p>Using Resend, you can create email functionalities and send emails using your favorite tools and technologies. At the moment, you can send emails using Resend with popular programming languages and frameworks such as TypeScript, Node.js, PHP, the Laravel framework, Go programming languages, Python, Ruby, and the Rails framework, as well as serverless functions. A few months ago, they added integration and support for sending emails with SMTP, You can read about it here.<br />They also continually add new integrations for new tools and technologies; most recently, they released a Java SDK, you can read about it <a target="_blank" href="https://resend.com/changelog/announcing-the-java-sdk">here</a>.</p>
<h3 id="heading-better-debugging-and-developer-experience">Better Debugging and Developer Experience</h3>
<p>Resend One cool thing I like about resend is that you can easily test your email functionality in different environments, and the results will remain the same.<br />Its error handling feature makes it easy for you to handle different scenarios during development when your emails are not going through</p>
<p>With its analytic dashboard, you can easily tell when your emails are getting bounced or throwing errors during production</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691814838502/1b9b60bf-b64a-451b-b1a7-05daf6a7c114.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-email-tracking-spam-prevention">Email Tracking, Spam Prevention</h3>
<p>When creating transactional emails to send from your application, you most times will want to be able to do the following:</p>
<ul>
<li>Track emails to see if they were delivered, opened, or clicked.</li>
</ul>
<h3 id="heading-hooks-functionality">Hooks functionality</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691815026326/216d8b07-1ac9-465f-8d9b-d68178be0484.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-webhooks">W<strong>ebhooks</strong></h3>
<ul>
<li><p>Features to help ensure email delivery, such as email tracking and spam prevention</p>
</li>
<li><p>Affordable</p>
</li>
<li><p>Once you configure a webhook, you'll be able to receive real-time updates about email events. <strong>Add webhook</strong></p>
</li>
</ul>
<h2 id="heading-examples">Examples</h2>
<h3 id="heading-nextjs">NextJs</h3>
<p>Install the</p>
<pre><code class="lang-bash">npm install resend
</code></pre>
<p>as an API</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { NextApiRequest, NextApiResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">'next'</span>;
<span class="hljs-keyword">import</span> { EmailTemplate } <span class="hljs-keyword">from</span> <span class="hljs-string">'../../components/EmailTemplate'</span>;
<span class="hljs-keyword">import</span> { Resend } <span class="hljs-keyword">from</span> <span class="hljs-string">'resend'</span>;

<span class="hljs-keyword">const</span> resend = <span class="hljs-keyword">new</span> Resend(process.env.RESEND_API_KEY);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> (req: NextApiRequest, res: NextApiResponse) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> resend.emails.send({
      <span class="hljs-keyword">from</span>: <span class="hljs-string">'Acme &lt;onboarding@resend.dev&gt;'</span>,
      to: [<span class="hljs-string">'delivered@resend.dev'</span>],
      subject: <span class="hljs-string">'Hello world'</span>,
      react: EmailTemplate({ firstName: <span class="hljs-string">'John'</span> }),
    });

    res.status(<span class="hljs-number">200</span>).json(data);
  } <span class="hljs-keyword">catch</span> (error) {
    res.status(<span class="hljs-number">400</span>).json(error);
  }
};
</code></pre>
<h3 id="heading-go">Go</h3>
<p>install the Resend SDK for Go</p>
<pre><code class="lang-typescript">go get github.com/resendlabs/resend-go
</code></pre>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"github.com/resendlabs/resend-go"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    apiKey = <span class="hljs-string">"re_123"</span>

    client := resend.NewClient(apiKey)

    params := &amp;resend.SendEmailRequest{
        From:    <span class="hljs-string">"Acme &lt;onboarding@resend.dev&gt;"</span>,
        To:      []<span class="hljs-keyword">string</span>{<span class="hljs-string">"@test.com"</span>},
        Html:    <span class="hljs-string">"&lt;strong&gt;hello world&lt;/strong&gt;"</span>,
        Subject: <span class="hljs-string">"Hello from Golang"</span>,
        Cc:      []<span class="hljs-keyword">string</span>{<span class="hljs-string">"cc@example.com"</span>},
        Bcc:     []<span class="hljs-keyword">string</span>{<span class="hljs-string">"bcc@example.com"</span>},
        ReplyTo: <span class="hljs-string">"replyto@example.com"</span>,
    }

    sent, err := client.Emails.Send(params)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        fmt.Println(err.Error())
        <span class="hljs-keyword">return</span>
    }
    fmt.Println(sent.Id)
}
</code></pre>
<p>You can find some other examples on the official Resend <a target="_blank" href="https://resend.com/docs/introduction">documentation</a></p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<ul>
<li><p>Resend is a great email API for developers who need to send transactional emails.</p>
</li>
<li><p>It's easy to use, reliable, and affordable.</p>
</li>
<li><p>If you're looking for an email API to help you send transactional emails, Resend is a great option</p>
</li>
</ul>
<p><a target="_blank" href="https://resend.com">https://resend.com</a></p>
<p><a target="_blank" href="https://resend.com/docs/introduction">https://resend.com/docs/introduction</a></p>
<p><a target="_blank" href="https://react.email">https://react.email</a></p>
]]></content:encoded></item><item><title><![CDATA[What is Developer Relations (DevRel)?]]></title><description><![CDATA[Introduction
In this article, we'll go over developer relations, what it is, what the team does, and their importance.
Developer Relations by Definition
Developer Relations (DevRel), as the name implies, means building relationships with developers b...]]></description><link>https://blog.jamin.sh/what-is-developer-relations-devrel</link><guid isPermaLink="true">https://blog.jamin.sh/what-is-developer-relations-devrel</guid><category><![CDATA[Developer]]></category><category><![CDATA[community]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[developer-advocacy]]></category><dc:creator><![CDATA[Trust Jamin]]></dc:creator><pubDate>Wed, 17 Jan 2024 12:54:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1705496139720/4e45ce8e-7999-48b9-8e6b-22146743a861.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>In this article, we'll go over developer relations, what it is, what the team does, and their importance.</p>
<h2 id="heading-developer-relations-by-definition">Developer Relations by Definition</h2>
<p>Developer Relations (DevRel), as the name implies, means building relationships with developers between a product and the developers that use the product.</p>
<p>DevRel is a multifaceted field comprising various activities designed to bridge the gap between a company and its developer community. At its core, DevRel focuses on creating a positive and supportive environment for developers, ensuring they have the resources, tools, and information needed to succeed in building their product.</p>
<p>As Ewan Dennis said:</p>
<p><em>To the community, I represent the company. To the company, I represent the community. I must have both of their interests in mind at all times.- Ewan Dennis</em>, quoted in <a target="_blank" href="https://www.persea-consulting.com/book?ref=tessakriesel.com"><em>The Business Value of Developer Relations</em></a></p>
<h2 id="heading-what-does-the-team-do">What does the team do?</h2>
<p>There are a couple of activities the DevRel team does to ensure that this includes:</p>
<ol>
<li><p><strong>Communication and Advocacy:</strong></p>
<ul>
<li><p>The DevRel team act as liaisons between developers and the company, advocating for the needs and interests of the developer community.</p>
</li>
<li><p>Effective communication is crucial, and DevRel often involves creating content, blog posts, tutorials, and documentation to help developers understand and utilize a company's products or services.</p>
</li>
</ul>
</li>
<li><p><strong>Community Building:</strong></p>
<ul>
<li><p>Online forums, discussion groups, and social media platforms are common channels to facilitate community interaction and collaboration.</p>
</li>
<li><p>DevRel teams work to cultivate and nurture communities around a company's products or technologies. This involves organizing events, meetups, and webinars and engaging in social media to foster a sense of belonging among developers.</p>
</li>
</ul>
</li>
<li><p><strong>Feedback Loop:</strong></p>
<ul>
<li><p>The DevRel team serves as a feedback channel between developers and the company's product and engineering teams. They do this by collecting iterative feedback loops that help enhance products, address issues, and tailor offerings to better meet developer needs.</p>
</li>
<li><p>They also collect insights on pain points, feature requests, and general sentiments to help improve and refine the developer experience.</p>
</li>
</ul>
</li>
<li><p><strong>Education and Training:</strong></p>
<ul>
<li><p>Providing educational resources is a key aspect of DevRel. This can include webinars, workshops, tutorials, and documentation that empower developers to master a company's technologies.</p>
</li>
<li><p>DevRel teams often collaborate with educational institutions, ensuring a pipeline of skilled developers and fostering the growth of the overall developer ecosystem.</p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-what-values-does-the-devrel-team-provide-to-the-company">What values does the DevRel Team provide to the company?</h2>
<ol>
<li><p><strong>Developer Empowerment:</strong></p>
<ul>
<li>DevRel is instrumental in empowering developers by providing them with the knowledge and tools needed to succeed in their projects. This, in turn, builds loyalty and trust within the developer community.</li>
</ul>
</li>
<li><p><strong>Product Improvement:</strong></p>
<ul>
<li>The constant feedback loop between developers and the company helps refine and improve products. Developers become valuable contributors to the evolution of a company's offerings, making them more aligned with user needs.</li>
</ul>
</li>
<li><p><strong>Brand Advocacy:</strong></p>
<ul>
<li>Through effective communication and community building, DevRel turns developers into brand advocates. These advocates are crucial in promoting a company's products within their networks.</li>
</ul>
</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, we covered what DevRel is, what the team does, and the important work it does in fostering collaboration, communication, and community building. As companies continue to recognize the importance of developer ecosystems, the role of DevRel is likely to evolve and expand, contributing to the growth and success of both developers and the organizations they support.</p>
]]></content:encoded></item><item><title><![CDATA[Improving Your Workflow as a Developer with Bash Aliases]]></title><description><![CDATA[As a developer, you most likely spend a significant amount of time working with the command-line interface (CLI). The command line is a powerful tool that allows you to interact with your operating system and execute various tasks efficiently. Howeve...]]></description><link>https://blog.jamin.sh/improving-your-workflow-as-a-developer-with-bash-aliases</link><guid isPermaLink="true">https://blog.jamin.sh/improving-your-workflow-as-a-developer-with-bash-aliases</guid><category><![CDATA[Bash]]></category><category><![CDATA[terminal]]></category><category><![CDATA[Git]]></category><category><![CDATA[Productivity]]></category><category><![CDATA[Developer]]></category><dc:creator><![CDATA[Trust Jamin]]></dc:creator><pubDate>Sat, 05 Aug 2023 07:47:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1691099307387/f3ee52ef-5acc-4faa-ad9c-6207ab132ac8.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As a developer, you most likely spend a significant amount of time working with the command-line interface (CLI). The command line is a powerful tool that allows you to interact with your operating system and execute various tasks efficiently. However, typing long and repetitive commands can become tedious and time-consuming. Fortunately, bash aliases can help you streamline your workflow and boost productivity. This article will explore what bash aliases are and how you can use them to enhance your development process.</p>
<h2 id="heading-prerequisite">Prerequisite</h2>
<p>Before you begin, this article requires basic knowledge of the terminal/CLI and bash commands.</p>
<h2 id="heading-what-is-a-bash-alias">What is a Bash Alias?</h2>
<p>A bash alias is a user-defined shortcut for frequently used commands. When you create an alias, you assign a custom name to a command or a series of commands. Once defined, you can use the alias instead of typing the entire command. Aliases are specific to your user profile and can be stored in your shell's configuration file, such as <code>.bashrc</code> or <code>.bash_profile</code>.</p>
<p>For example, the following alias command creates a shortcut for the <code>ls -al</code> command:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">alias</span> ls=<span class="hljs-string">"ls -al"</span>
</code></pre>
<p>This shortcut can then be used to list all of the files and directories in a directory. So, instead of writing the longer command <code>ls -al</code> every time you need to list the files in a directory, you can now type <code>ls</code>.</p>
<h2 id="heading-benefits-of-using-bash-aliases">Benefits of Using Bash Aliases</h2>
<p>There are several benefits to using bash aliases:</p>
<ol>
<li><p><strong>Increased productivity</strong>: By reducing the time spent typing repetitive commands, you can focus more on coding and development tasks.</p>
</li>
<li><p><strong>Customization</strong>: Bash aliases are entirely customizable, tailored to your specific needs and preferences.</p>
</li>
<li><p><strong>Error prevention</strong>: Since aliases can be designed to avoid complex or risky commands, you can reduce the chances of making mistakes when running important commands.</p>
</li>
</ol>
<h2 id="heading-creating-a-bash-alias">Creating a Bash Alias</h2>
<p>To create a bash alias, follow these steps:</p>
<ol>
<li><p>Open your terminal.</p>
</li>
<li><p>Navigate to your home directory (<code>cd ~</code>) if you're not already there.</p>
</li>
<li><p>Edit your shell configuration file using a text editor like Nano or VSCode. For example, to edit <code>.bashrc</code>, use <code>nano ~/.bashrc</code> or <code>code ~/.bashrc</code>.</p>
</li>
<li><p>Add your alias definitions to the file. The syntax for creating an alias is: <code>alias shortcut='command'</code>. Replace <code>shortcut</code> with the name of your desired alias and <code>command</code> with the actual command or commands you want to associate with the alias.</p>
</li>
<li><p>Save the file and exit the text editor.</p>
</li>
<li><p>To make your changes take effect, restart your terminal or run the command <code>source ~/.bashrc</code>.</p>
</li>
</ol>
<h2 id="heading-aliases-with-multiple-commands">Aliases with Multiple Commands</h2>
<p>Using logical operators such as the AND (<code>&amp;&amp;</code>) and OR (<code>||</code>) operators, you can create aliases with multiple commands.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">alias</span> shortcut=<span class="hljs-string">'command1 &amp;&amp; command2'</span>
</code></pre>
<h3 id="heading-using-the-and-ampamp-operator">Using the AND (<code>&amp;&amp;</code>) Operator</h3>
<p>The double ampersand is a logical AND operator used to execute the second command only if the first command succeeds (i.e., returns an exit status of 0). However, if <code>command1</code> fails (returns a non-zero exit status), <code>command2</code> will not be executed. Here's an example alias in bash:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">alias</span> npmsetup=<span class="hljs-string">'npm install &amp;&amp; npm run dev'</span>
</code></pre>
<p>In this example, you've created an alias called <code>npmsetup</code>. When you execute <code>npmsetup</code>, it will first install all the packages in the project using the command <code>npm install</code>. If the installation is successful, it will then run the development server using the <code>npm run dev</code> command.</p>
<h3 id="heading-using-semicolon">Using Semicolon (<code>;</code>)</h3>
<p>In bash, the semicolon is a simple command separator. When you use it to separate commands, bash will execute each command sequentially, regardless of whether the previous command succeeded or failed. This means that all commands separated by semicolons will be executed, even if some of them produce errors.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">alias</span> shortcut=<span class="hljs-string">'command1 ; command2 ; command3'</span>
</code></pre>
<p>In this case, <code>command1</code> will be executed first, followed by <code>command2</code>, and then <code>command3</code>, irrespective of whether any of them fail or succeed.</p>
<h3 id="heading-using-the-or-operator">Using the OR (<code>||</code>) Operator.</h3>
<p>The double pipe is a logical OR operator used to execute a second command when the first command fails: When you use <code>command1 || command2</code>, it will execute <code>command1</code> first. If <code>command1</code> fails (returns a non-zero exit status), then bash will proceed to execute <code>command2</code>. However, if <code>command1</code> succeeds (returns an exit status of 0), <code>command2</code> will not be executed. let’s have a look at an example of using the <code>||</code> operator:</p>
<p>Imagine you want to create an alias command <code>dev</code> that turns on the development server in a JavaScript/Typescript project, using the <code>||</code> operator you can create the alias as follows:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">alias</span> dev=<span class="hljs-string">'npm run dev || npm run develop'</span>
</code></pre>
<p>In this example, you've created an alias called <code>dev</code>. When you execute <code>dev</code>, it will first try to run the development server using the command <code>npm run dev</code>. If that command is not found or fails, it will then try the second command <code>npm run develop</code>.</p>
<h2 id="heading-bash-alias-examples">Bash Alias Examples</h2>
<p>Let’s consider some practical examples of bash alias commands that can help improve your development workflow.</p>
<p>I use the following alias commands to run common git and development commands with just a few keystrokes without having to type the whole command:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">alias</span> gm=<span class="hljs-string">'git commit -m'</span>
<span class="hljs-built_in">alias</span> pull=<span class="hljs-string">'git pull'</span>
<span class="hljs-built_in">alias</span> push=<span class="hljs-string">'git push'</span>
<span class="hljs-built_in">alias</span> gs=<span class="hljs-string">'git status -sb'</span>
<span class="hljs-built_in">alias</span> gc=<span class="hljs-string">'git checkout'</span>
<span class="hljs-built_in">alias</span> gb=<span class="hljs-string">'git branch'</span>
<span class="hljs-built_in">alias</span> gline=<span class="hljs-string">'git log --oneline'</span>
<span class="hljs-built_in">alias</span> gcp=<span class="hljs-string">'git cherry-pick'</span>
<span class="hljs-built_in">alias</span> add=<span class="hljs-string">'git add'</span>
<span class="hljs-built_in">alias</span> addall=<span class="hljs-string">'git add .'</span>
<span class="hljs-built_in">alias</span> dps=<span class="hljs-string">'docker ps'</span>
<span class="hljs-built_in">alias</span> dcu=<span class="hljs-string">'docker-compose up'</span>
<span class="hljs-built_in">alias</span> cf=<span class="hljs-string">'STAGE_BACKEND=true yarn start'</span>
<span class="hljs-built_in">alias</span> dev=<span class="hljs-string">'npm run dev || npm run develop'</span>
<span class="hljs-built_in">alias</span> clean=<span class="hljs-string">'npm run clean'</span>
</code></pre>
<p>What aliases do you use to speed up your workflow? Please share in the comments section; I'll be waiting :)</p>
<h2 id="heading-reference">Reference</h2>
<ul>
<li><p><a target="_blank" href="https://www.freecodecamp.org/news/bash-scripting-tutorial-linux-shell-script-and-command-line-for-beginners/">Bash scripting for beginners</a></p>
</li>
<li><p><a target="_blank" href="https://tldp.org/LDP/abs/html/aliases.html">Advanced Bash-Scripting Guide</a></p>
</li>
<li><p><a target="_blank" href="https://itsfoss.com/install-bash-on-windows/">Install Bash on Windows</a></p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Bash aliases can help you optimize your workflow as a developer. By creating shortcuts for common commands, you can save time, improve productivity, and make your development experience more enjoyable. So, don't hesitate to start creating your custom aliases today to improve your productivity on your daily development tasks.</p>
<p>Happy coding!</p>
<p>I'd love to connect with you on <a target="_blank" href="https://twitter.com/codejagaban"><strong>Twitter</strong></a> | <a target="_blank" href="https://www.linkedin.com/in/codejagaban"><strong>LinkedIn</strong></a> | <a target="_blank" href="https://github.com/codejagaban/"><strong>GitHub</strong></a></p>
]]></content:encoded></item><item><title><![CDATA[Mastering Generics in Typescript]]></title><description><![CDATA[Generics are one of the superpowers of TypeScript, and while they might look scary if one has little or no knowledge about them, they can be life-saving when understood and used correctly. Mastering generics in TypeScript can significantly enhance on...]]></description><link>https://blog.jamin.sh/mastering-generics-in-typescript</link><guid isPermaLink="true">https://blog.jamin.sh/mastering-generics-in-typescript</guid><category><![CDATA[TypeScript]]></category><category><![CDATA[TypeScript Generics]]></category><category><![CDATA[Interfaces]]></category><category><![CDATA[functions]]></category><category><![CDATA[scalability]]></category><dc:creator><![CDATA[Trust Jamin]]></dc:creator><pubDate>Fri, 14 Jul 2023 16:10:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1689165494198/85f4459e-b365-45d0-897d-07286049b547.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Generics are one of the superpowers of TypeScript, and while they might look scary if one has little or no knowledge about them, they can be life-saving when understood and used correctly. Mastering generics in TypeScript can significantly enhance one's ability to write clean, robust, and scalable code. In this article, we will explore the fundamentals of generics, delve into some of its concepts, and provide practical examples to help individuals become better users of generics in TypeScript.</p>
<h2 id="heading-what-are-generics-in-typescript">What are Generics in Typescript?</h2>
<p>Generics enable us to create reusable components that work with different data types while maintaining type safety. They provide a way to define placeholders for types that are determined when the code is used. This enables us to write more generic and flexible code.</p>
<p>Consider this example of this function below:</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">echo</span>(<span class="hljs-params">value</span>) </span>{
  <span class="hljs-keyword">return</span> value;
}

<span class="hljs-comment">//Call the function</span>
echo(<span class="hljs-string">"Hello World"</span>)
</code></pre>
<p>The <code>echo</code> function receives a value and returns that value without any modification. At the moment, TypeScript frowns at our function parameter and complains that “parameter 'value' implicitly has an 'any' type.“ meaning that since there’s no type explicitly specified, TypeScript has inferred a type of <code>any</code> to the parameter of the function. This doesn’t help us check the data of the parameter of our function, so how do we check that the right type is passed when our function is called and that our function also returns the correct data?</p>
<p>One way we could do this is by explicitly setting the type of parameter <code>value</code> passed and returned.</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">echo</span>(<span class="hljs-params">value:<span class="hljs-built_in">string</span></span>):<span class="hljs-title">string</span> </span>{
  <span class="hljs-keyword">return</span> value;
}
echo(<span class="hljs-string">"Hello World"</span>)
</code></pre>
<p>This example works perfectly as we know the type of data being passed as a parameter and the data our function returns, but there is a tiny bit of an issue. What if we want to make the <code>echo</code> function reusable and call it somewhere else with a different data type? Typescript will complain that we’re passing the wrong data type to the <code>echo</code> function.</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">echo</span>(<span class="hljs-params">value:<span class="hljs-built_in">string</span></span>): <span class="hljs-title">string</span> </span>{
  <span class="hljs-keyword">return</span> value;
}
<span class="hljs-comment">//Argument of type 'number' is not assignable to parameter of type 'string'</span>
echo(<span class="hljs-number">3.14159</span>)
</code></pre>
<p>So how do we fix this? How do we create a reusable function that accepts and returns the types we pass to it? Generics!</p>
<h2 id="heading-basic-generics">Basic Generics</h2>
<p>Starting with the basics, using the <code>echo</code> function as an example, let’s spice it up and update the function with generics to be reusable.</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">echo</span>&lt;<span class="hljs-title">T</span>&gt; (<span class="hljs-params">value: T</span>): <span class="hljs-title">T</span> </span>{
  <span class="hljs-keyword">return</span> value;
}

 <span class="hljs-comment">//calls the function with no errors from typescript</span>
echo(<span class="hljs-string">"Hello World"</span>)
echo(<span class="hljs-number">3.14159</span>);
echo(<span class="hljs-literal">false</span>);
echo([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>])
echo({id: <span class="hljs-number">1</span>, fullName: <span class="hljs-string">"John Doe"</span>})
</code></pre>
<p>In this example, The echo function is a generic function that takes an argument <code>value</code> of type <code>T</code> and returns the exact value of type <code>T</code> without any modification. The generic type parameter <code>&lt;T&gt;</code> we passed to the function allows it to work with different types, thus allowing us to reuse the same function with different data.</p>
<p>Generally, you can write a generic type with any alphabet you like, <code>&lt;X&gt;,&lt;Y&gt;</code>, but <code>T</code> is for <code>type</code>, and it's just a tradition of naming generics, and there is nothing to prevent you from using other names or alphabets.</p>
<h2 id="heading-generics-on-type-declarations">Generics on Type Declarations</h2>
<p>Generics don’t only work with <code>functions</code>; we can also use generics to make types more robust, reusable, and flexible when declared. For example, let's say we are building an e-commerce application and have a Repository interface defining common CRUD operations for working with different entities in our system. Instead of creating separate interfaces for each entity (e.g., <code>UserRepository</code>, <code>ProductRepository</code>, etc.), we can use generics to create a single, generic <code>Repository</code> interface that can handle various entity types.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> Repository&lt;T&gt; {
  getById(id: <span class="hljs-built_in">string</span>): T | <span class="hljs-literal">undefined</span>;
  getAll(): T[];
  create(item: T): <span class="hljs-built_in">void</span>;
  update(item: T): <span class="hljs-built_in">void</span>;
  <span class="hljs-keyword">delete</span>(id: <span class="hljs-built_in">string</span>): <span class="hljs-built_in">void</span>;
}
<span class="hljs-keyword">class</span> UserRepository <span class="hljs-keyword">implements</span> Repository&lt;User&gt; {
  <span class="hljs-comment">// Implementation specific to User entity</span>
}

<span class="hljs-keyword">class</span> ProductRepository <span class="hljs-keyword">implements</span> Repository&lt;Product&gt; {
  <span class="hljs-comment">// Implementation specific to Products operation</span>
}

<span class="hljs-comment">// Usage</span>
<span class="hljs-keyword">const</span> userRepository: Repository&lt;User&gt; = <span class="hljs-keyword">new</span> UserRepository();
<span class="hljs-keyword">const</span> user = userRepository.getById(<span class="hljs-string">'123'</span>);
userRepository.create(newUser);

<span class="hljs-keyword">const</span> productRepository: Repository&lt;Product&gt; = <span class="hljs-keyword">new</span> ProductRepository();
<span class="hljs-keyword">const</span> products = productRepository.getAll();
productRepository.update(updatedProduct);
</code></pre>
<p>In this example, the <code>Repository</code> interface is defined with a generic type parameter <code>T</code> representing the entity type. It provides common methods like <code>getById</code>, <code>getAll</code>, <code>create</code>, <code>update</code>, and <code>delete</code> that can be used with any entity.</p>
<p>By implementing the <code>Repository</code> interface with specific entity types like <code>User</code> and <code>Product</code>, we can create specialized repositories that handle operations particular to those entities. The generic nature of the interface allows for code reuse and flexibility when working with different types of entities.</p>
<p>This approach makes the code more modular, maintainable, and extensible, as we can easily add new entity-specific repositories without duplicating the same set of methods for each entity type.</p>
<h2 id="heading-generics-in-functions-with-type-constraints">Generics in Functions with Type Constraints</h2>
<p>As we’ve seen from our first generics example in this article, we can use generics with functions and combine them with some other features of TypeScript to produce more exciting results. Let’s say we want a function called <code>printLength</code> that accepts only items with lengths and prints the length of any items we pass on it. Using the <code>extend</code> keyword in Typescript, we can create a function that constrains the data passed to the function.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> Lengthy {
  length: <span class="hljs-built_in">number</span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">printLength</span>&lt;<span class="hljs-title">T</span> <span class="hljs-title">extends</span> <span class="hljs-title">Lengthy</span>&gt;(<span class="hljs-params">item: T</span>): <span class="hljs-title">void</span> </span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Length: <span class="hljs-subst">${item.length}</span>`</span>);
}

<span class="hljs-keyword">const</span> stringItem = <span class="hljs-string">"Hello, World!"</span>;
printLength(stringItem); <span class="hljs-comment">// Output: Length: 13</span>

<span class="hljs-keyword">const</span> arrayItem = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>];
printLength(arrayItem); <span class="hljs-comment">// Output: Length: 5</span>

<span class="hljs-keyword">const</span> numberItem = <span class="hljs-number">42</span>; <span class="hljs-comment">// Error: Type 'number' does not have a property 'length'</span>
printLength(numberItem);
</code></pre>
<p>In this example, The <code>printLength</code> function takes a generic type parameter <code>T</code> that extends the <code>Lengthy</code> interface using the <code>extends</code> keyword. This means the type <code>T</code> must have the <code>length</code> property of the type <code>number</code>.</p>
<p>Within the <code>printLength</code> function, we can safely access the <code>length</code> property of the <code>item</code> argument without causing type errors because the generic type <code>T</code> is guaranteed to have a <code>length</code> property.</p>
<p>Using the <code>printLength</code> function with items(<code>stringItem</code> and <code>arrayItem</code> ) that satisfy the <code>Lengthy</code> requirements, we got no errors from TypeScript. However, when we try to pass a number (<code>numberItem</code>), which doesn't have a <code>length</code> property, TypeScript raises an error.</p>
<p>Let’s consider another example that combines generics with some more inbuilt features of TypeScript. The function below accepts an array of objects, finds an object by the <code>id</code> key property of the object, and returns the <code>key</code> value we specified as a parameter when calling the function.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> Person {
  id: <span class="hljs-built_in">number</span>;
  name: <span class="hljs-built_in">string</span>;
  age: <span class="hljs-built_in">number</span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getObjectValue</span>&lt;<span class="hljs-title">T</span> <span class="hljs-title">extends</span> </span>{ id: <span class="hljs-built_in">number</span> }, K <span class="hljs-keyword">extends</span> keyof T&gt;
  (arr: T[], key: K, id: <span class="hljs-built_in">number</span>): T[K] | <span class="hljs-literal">undefined</span> {
  <span class="hljs-keyword">const</span> foundObject = arr.find(<span class="hljs-function">(<span class="hljs-params">obj</span>) =&gt;</span> obj.id === id);
  <span class="hljs-keyword">return</span> foundObject ? foundObject[key] : <span class="hljs-literal">undefined</span>;
}

<span class="hljs-keyword">const</span> people: Person[] = [
  { id: <span class="hljs-number">1</span>, name: <span class="hljs-string">"John"</span>, age: <span class="hljs-number">25</span> },
  { id: <span class="hljs-number">2</span>, name: <span class="hljs-string">"Jane"</span>, age: <span class="hljs-number">30</span> },
  { id: <span class="hljs-number">3</span>, name: <span class="hljs-string">"Bob"</span>, age: <span class="hljs-number">40</span> },
];

<span class="hljs-keyword">const</span> nameValue = getObjectValue(people, <span class="hljs-string">"name"</span>, <span class="hljs-number">2</span>);
<span class="hljs-built_in">console</span>.log(nameValue); <span class="hljs-comment">// Output: Jane</span>
</code></pre>
<p>Whoops! That looks like a complex function with lots of types flying everywhere. Let’s break it down bit by bit.</p>
<ol>
<li><p>The first line of the function contains two generic types <code>&lt;T, K&gt;</code> where <code>T</code> is an object and has a constraint that it must have an object property of <code>{id: number }</code> and <code>K</code> is a key property of the object <code>T</code> (using the <code>keyof</code> operator) and has a constraint that it must only contain properties from <code>T</code> object (using the <code>extend</code> keyword).</p>
</li>
<li><p>The second line contains the parameters the function receives and what the function returns.</p>
<ul>
<li><p><code>arr</code>: is an array of our object <code>T</code>.</p>
</li>
<li><p><code>key</code>: is a key property of object <code>T</code>.</p>
</li>
<li><p><code>id</code>: is a number unique to every object <code>T</code> in the array.</p>
</li>
<li><p>The function <code>getObjectValue</code> then returns the value of the object key property found, <code>T[K],</code> or <code>undefined</code> if the value is not found.</p>
</li>
</ul>
</li>
<li><p>The third line checks through the array using the <code>id</code> as a criterion, finding the object with the same <code>id.</code></p>
</li>
<li><p>The fourth line checks if the object <code>foundObject</code> we just searched for actually exists and if it does, we extract a value from it using its key <code>foundObject[key]</code> and return it, or return <code>undefined</code> if it’s not found.</p>
</li>
</ol>
<p>That’s it. We just broke down the <code>getObjectValue</code> function into small chunks to better understand the generic type definitions it has.</p>
<h2 id="heading-generics-can-have-default-values">Generics can have default values.</h2>
<p>We can also use generics with default values when working with functions. On our previous <code>getObjectValue</code> function, imagine we’d like to add a default parameter for our <code>id</code> parameter as the default value our function filters by. We could rewrite the function like this:</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getObjectValue</span>&lt;<span class="hljs-title">T</span> <span class="hljs-title">extends</span> </span>{ id: <span class="hljs-built_in">number</span> }, K <span class="hljs-keyword">extends</span> keyof T&gt;
  (arr: T[], key:K, id:<span class="hljs-built_in">number</span> = <span class="hljs-number">2</span>): T[K] | <span class="hljs-literal">undefined</span> {
  <span class="hljs-keyword">const</span> foundObject = arr.find(<span class="hljs-function">(<span class="hljs-params">obj</span>) =&gt;</span> obj.id === id);
  <span class="hljs-keyword">return</span> foundObject ? foundObject[key] : <span class="hljs-literal">undefined</span>;
}
</code></pre>
<p>By updating the <code>id: number</code> to be <code>id: number = 2,</code> we set the default value to be <code>2</code> whenever our function runs.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, we covered generics in TypeScript, how they make our code reusable, and how they help to add flexibility to our code using some examples of type declarations and functions.</p>
<p>Generics is one of the features of TypeScript that might look overwhelming at first, but once you get to know it better, you’ll appreciate how it makes your code more strictly typed.</p>
<p>I hope this article helps you better understand generics.</p>
<p>Thanks for reading. Cheers.</p>
<h2 id="heading-references">References</h2>
<ul>
<li><a target="_blank" href="https://www.typescriptlang.org/docs/handbook/2/generics.html">Official TypeScript documentation on generics</a></li>
</ul>
<p>I'd love to connect with you on <a target="_blank" href="https://twitter.com/codejagaban"><strong>Twitter</strong></a> | <a target="_blank" href="https://www.linkedin.com/in/codejagaban"><strong>LinkedIn</strong></a> | <a target="_blank" href="https://github.com/codejagaban/"><strong>GitHub</strong></a></p>
]]></content:encoded></item><item><title><![CDATA[The Differences Between Type and Interface in Typescript]]></title><description><![CDATA[Typescript is a superset of JavaScript that incorporates static typing, making detecting errors simpler and producing more maintainable code.
Types and interfaces in Typescript represent two distinct methods for defining the structure and shape of va...]]></description><link>https://blog.jamin.sh/the-differences-between-type-and-interface-in-typescript</link><guid isPermaLink="true">https://blog.jamin.sh/the-differences-between-type-and-interface-in-typescript</guid><category><![CDATA[TypeScript]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Programming Tips]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[classes]]></category><dc:creator><![CDATA[Trust Jamin]]></dc:creator><pubDate>Tue, 13 Jun 2023 21:34:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1686690992508/ae0dcc2f-a12f-4cd7-9fcb-2c17d2c7d6d3.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Typescript is a superset of JavaScript that incorporates static typing, making detecting errors simpler and producing more maintainable code.</p>
<p>Types and interfaces in Typescript represent two distinct methods for defining the structure and shape of values or objects. They help ensure that variables, objects, arrays, parameters, and function return values match the structure and type set by the developer. This article emphasizes the distinctions between types and interfaces and their appropriate use cases.</p>
<h2 id="heading-types">Types</h2>
<p>Types describe a value type such as string, boolean, number, etc. It enables you to explicitly specify the data type of variables, objects, function parameters, and function return values of functions, for example:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">//types in variables</span>
<span class="hljs-keyword">const</span> age: <span class="hljs-built_in">number</span> = <span class="hljs-number">24</span>;


<span class="hljs-comment">//types in functions</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addNumbers</span>(<span class="hljs-params">a: <span class="hljs-built_in">number</span>, b: <span class="hljs-built_in">number</span></span>): <span class="hljs-title">number</span> </span>{
  <span class="hljs-keyword">return</span> a + b;
}
</code></pre>
<p>You can also use types to describe an object's structure or shape.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">//type alias</span>
<span class="hljs-keyword">type</span> User = {
  id: <span class="hljs-built_in">string</span>;
  firstName: <span class="hljs-built_in">string</span>;
  lastName: <span class="hljs-built_in">string</span>;
  isAdmin: <span class="hljs-built_in">boolean</span>;
  age: <span class="hljs-built_in">number</span>;
};
</code></pre>
<h2 id="heading-interfaces">Interfaces</h2>
<p>Interfaces allow you to specify the shape of an object by declaring the properties it should have, along with their types and optionally their accessibility modifiers.</p>
<h2 id="heading-the-differences">The Differences</h2>
<p>Below are some key differences between an <code>interface</code> and a <code>type</code> in typescript:</p>
<h3 id="heading-types-can-be-used-to-describe-primitive-types">Types can be used to describe primitive types</h3>
<p>One key distinction between interfaces and types is that only types can describe primitive types.</p>
<p>In the following code, the <code>type</code> declarations are suitable for describing the shape of data that isn't an object, but they are not valid for interface declarations.</p>
<pre><code class="lang-typescript">
<span class="hljs-comment">// Types</span>
<span class="hljs-comment">// works fine with types</span>
<span class="hljs-keyword">type</span> Status = <span class="hljs-string">"pending"</span> | <span class="hljs-string">"success"</span> | <span class="hljs-string">"error"</span>;
<span class="hljs-keyword">type</span> FamousQuotes = <span class="hljs-built_in">string</span>[] | <span class="hljs-literal">undefined</span>;


 <span class="hljs-comment">//Interface</span>
 <span class="hljs-comment">//Error! parsing error "{" expected</span>
<span class="hljs-keyword">interface</span> IStatus = "pending" | "success"
</code></pre>
<h3 id="heading-interfaces-for-declaration-merging">Interfaces for declaration merging</h3>
<p>One advantage <code>interface</code> has over <code>type</code> is that you can always reopen them to add more properties. this is not possible when using <code>type</code>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> Person {
  name: <span class="hljs-built_in">string</span>;
  age: <span class="hljs-built_in">number</span>;
}

<span class="hljs-comment">// Reopen the Person interface and add a new property</span>
<span class="hljs-keyword">interface</span> Person {
  gender: <span class="hljs-built_in">string</span>;
}

<span class="hljs-keyword">const</span> person: Person = {
  name: <span class="hljs-string">"John"</span>,
  age: <span class="hljs-number">25</span>,
  gender: <span class="hljs-string">"Male"</span>,
};

<span class="hljs-built_in">console</span>.log(person.name); <span class="hljs-comment">// Output: John</span>
<span class="hljs-built_in">console</span>.log(person.age); <span class="hljs-comment">// Output: 25</span>
<span class="hljs-built_in">console</span>.log(person.gender); <span class="hljs-comment">// Output: Male</span>
</code></pre>
<p>When using <code>type</code> this would throw an error:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> Person = {
  name: <span class="hljs-built_in">string</span>;
  age: <span class="hljs-built_in">number</span>;
}

<span class="hljs-comment">// Error: "Duplicate identifier 'Person'"</span>
<span class="hljs-keyword">type</span> Person = {
  gender: <span class="hljs-built_in">string</span>;
}
<span class="hljs-comment">// Error: Object literal may only specify known properties, and 'gender' does not exist in type 'Person'</span>
<span class="hljs-keyword">const</span> person: Person = {
  name: <span class="hljs-string">"John"</span>,
  age: <span class="hljs-number">25</span>,
  gender: <span class="hljs-string">"Male"</span>,
};
</code></pre>
<h3 id="heading-interface-extension-and-type-union">Interface extension and type union</h3>
<p>When working with objects and classes, interfaces offer a more seamless experience, allowing you to extend other interfaces to inherit their properties and methods.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> Animal {
  name: <span class="hljs-built_in">string</span>;
  age: <span class="hljs-built_in">number</span>;
  eat(): <span class="hljs-built_in">void</span>;
}

<span class="hljs-keyword">interface</span> Dog <span class="hljs-keyword">extends</span> Animal {
  breed: <span class="hljs-built_in">string</span>;
  bark(): <span class="hljs-built_in">void</span>;
}

<span class="hljs-keyword">const</span> myDog: Dog = {
  name: <span class="hljs-string">"Max"</span>,
  age: <span class="hljs-number">3</span>,
  breed: <span class="hljs-string">"Chihuahua"</span>,
  eat() {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Eating..."</span>);
  },
  bark() {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Woof!"</span>);
  },
};

<span class="hljs-built_in">console</span>.log(myDog.name); <span class="hljs-comment">// Output: Max</span>
<span class="hljs-built_in">console</span>.log(myDog.age); <span class="hljs-comment">// Output: 3</span>
myDog.eat(); <span class="hljs-comment">// Output: Eating...</span>
myDog.bark(); <span class="hljs-comment">// Output: Woof!</span>
</code></pre>
<p>However, we can perform something known as "intersection types" with types. Intersection types allow you to combine multiple types into a single type with all the properties and methods of each type. This is achieved by using the <code>&amp;</code> symbol between the different types.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// type</span>

<span class="hljs-keyword">type</span> Animal = {
  name: <span class="hljs-built_in">string</span>;
  age: <span class="hljs-built_in">number</span>;
  eat(): <span class="hljs-built_in">void</span>;
}

<span class="hljs-keyword">type</span> Dog = Animal &amp; {
  breed: <span class="hljs-built_in">string</span>;
  bark(): <span class="hljs-built_in">void</span>;
}
</code></pre>
<h3 id="heading-vs-code-intellisense-performs-better-with-types">VS Code IntelliSense performs better with types.</h3>
<p>When using types, you can hover over the type declaration, and IntelliSense in VS Code displays the internal properties of that type. However, interfaces only show the name of the declared interface. A related issue can be found on <a target="_blank" href="https://github.com/microsoft/TypeScript/issues/38040">GitHub</a>, as this is a significant factor for some people to prefer using types over interfaces.</p>
<p>Intellisense on VS Code when using <code>interface</code>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686616625719/ac52429e-8f40-4f33-8428-e836da652545.png" alt class="image--center mx-auto" /></p>
<p>Intellisense on VS Code when using <code>type</code>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686617042795/a0f46387-024b-4685-9240-b68f752896ed.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-comparison-table">Comparison Table</h2>
<p>The table below compares types and interfaces in TypeScript:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td></td><td>Type</td><td>Interface</td></tr>
</thead>
<tbody>
<tr>
<td>Syntax</td><td><code>type TypeName = ...</code></td><td><code>interface InterfaceName { ... }</code></td></tr>
<tr>
<td>Declaration</td><td>Can be named or anonymous</td><td>Must be named</td></tr>
<tr>
<td>Merging</td><td>Can be extended using intersection (<code>&amp;</code>)</td><td>Can be extended using the <code>extends</code> keyword</td></tr>
<tr>
<td>Implementation</td><td>Cannot be implemented directly</td><td>Can be implemented by classes and objects</td></tr>
<tr>
<td>Extendable</td><td>Cannot extend or be extended</td><td>Can extend other interfaces</td></tr>
<tr>
<td>Intersection</td><td>Can be used in intersection types</td><td>Cannot be used in intersection types</td></tr>
<tr>
<td>Union</td><td>Can be used in union types</td><td>Cannot be used in union types</td></tr>
<tr>
<td>Declaration merging</td><td>Cannot merge declarations of the same name</td><td>Can merge declarations of the same name</td></tr>
<tr>
<td>Discriminated union</td><td>Cannot be used in discriminated unions</td><td>Can be used in discriminatory unions</td></tr>
<tr>
<td>Function-like</td><td>Can define callable and constructible types</td><td>Cannot define callable or constructible types</td></tr>
</tbody>
</table>
</div><h2 id="heading-which-should-i-use-for-a-typescript-project">Which should I use for a typescript project?</h2>
<p>Often, as someone starting with TypeScript, you might ask yourself, "When should I use 'type' over 'interface' and vice versa?" The comparison above shows that both have different approaches to describing the shape of values and objects in your TypeScript project.</p>
<p>A short, opinionated answer is to use interfaces until you encounter areas where you need to explicitly use types, as interfaces represent how Javascript behaves in a real-world scenario. However, it boils down to a matter of personal preference. This Stackoverflow <a target="_blank" href="https://stackoverflow.com/questions/37233735/interfaces-vs-types-in-typescript/52682220#52682220">discussion</a> also highlights different developers' choices and reasons for picking interfaces over types and vice versa.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, we explored some of the differences between types and interfaces in typescript and the best occasions to use one over the other. Ultimately, the decision of whether to use type or interface in a TypeScript project depends on your personal preference and the specific needs of your project. Both have their own strengths and weaknesses, and it's up to you to weigh them and make an informed decision. It's also worth noting that as you gain more experience with TypeScript, your preferences, and needs may change, so don't be afraid to experiment and try different approaches.</p>
<h2 id="heading-reference">Reference</h2>
<ul>
<li><p><a target="_blank" href="https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#differences-between-type-aliases-and-interfaces">Official typescript documentation on Type alias vs interface</a></p>
</li>
<li><p><a target="_blank" href="https://stackoverflow.com/questions/37233735/interfaces-vs-types-in-typescript/52682220#52682220">Stackoverflow discussion</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/microsoft/TypeScript/issues/38040">VSCode Intellisense issue with interfaces on GitHub</a></p>
</li>
</ul>
<p>I'd love to connect with you on <a target="_blank" href="https://twitter.com/codejagaban"><strong>Twitter</strong></a> | <a target="_blank" href="https://www.linkedin.com/in/codejagaban/"><strong>LinkedIn</strong></a> | <a target="_blank" href="https://github.com/codejagaban/"><strong>GitHub</strong></a></p>
<p>Thanks for reading; I hope you find this article helpful. Cheers</p>
]]></content:encoded></item><item><title><![CDATA[How to Send Custom Emails from Netlify: A Step-by-Step Guide]]></title><description><![CDATA[This article explains how to send custom emails from shared hosting while your site is hosted on Netlify.
Imagine this scenario: you have a website hosted on Netlify and want to send custom emails using your domain name, e.g., yourname@domain.com, so...]]></description><link>https://blog.jamin.sh/how-to-send-custom-emails-from-netlify-a-step-by-step-guide</link><guid isPermaLink="true">https://blog.jamin.sh/how-to-send-custom-emails-from-netlify-a-step-by-step-guide</guid><category><![CDATA[Vercel]]></category><category><![CDATA[shared hosting]]></category><category><![CDATA[dns]]></category><category><![CDATA[email]]></category><dc:creator><![CDATA[Trust Jamin]]></dc:creator><pubDate>Mon, 29 May 2023 12:12:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1691277144893/718f8c7d-f6d4-48b2-9361-a0a2851de9b9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This article explains how to send custom emails from shared hosting while your site is hosted on Netlify.</p>
<p><strong>Imagine this scenario:</strong> you have a website hosted on Netlify and want to send custom emails using your domain name, e.g., <a target="_blank" href="mailto:yourname@domain.com">yourname@domain.com</a>, so you purchased a shared hosting plan that gives you domain-based mailboxes for sending and receiving emails.</p>
<p>Why would you deploy your website on Netlify instead of your shared hosting plan? Well, they're both hosting providers for deploying modern frontend applications such as React and Vue, and they provide you with benefits such as automatic SSL, serverless functions, continuous deployment using git, and lots more. This article gives you a workaround to enjoy the best of both worlds.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To begin, you need the following:</p>
<ol>
<li><p>A free or <a target="_blank" href="https://netlify.com/">Netlify</a> account where you hosted your website</p>
</li>
<li><p>A domain name linked to your website</p>
</li>
<li><p>A hosting (shared or full access) plan that provides you with custom emails and Cpanel access.</p>
</li>
</ol>
<p>With these, you're good to go.</p>
<h2 id="heading-step-1-ip-address">Step 1: IP Address</h2>
<p>Login to your Cpanel dashboard on your hosting and get the IP address assigned to your server.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1684800467781/ca9c43f4-24c3-411f-8fee-9a29f0ff706d.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-step-2-email-server-address">Step 2: Email Server Address</h2>
<p>To create and access your email details, go to the email section of your cPanel. Here is a <a target="_blank" href="https://www.namecheap.com/support/knowledgebase/article.aspx/110/31/how-to-create-an-email-account-in-cpanel/">guide</a> on how to create emails and retrieve the details. Below is a screenshot of the details you need.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1684957858703/d96577ed-1282-4822-997e-a4ed4329e110.png" alt class="image--center mx-auto" /></p>
<p>So far, here are the details you've gathered from the shared host server:</p>
<ul>
<li><p>IP Address</p>
</li>
<li><p>Email server address</p>
</li>
</ul>
<p>These two items are essential for ensuring emails are sent from the shared hosting server.</p>
<h2 id="heading-step-3-configure-dns-records">Step 3: Configure DNS Records</h2>
<p>Now that you have the details you need from the shared hosting, you need to add those details to Netlify so that your emails can go through whenever you try sending an email.</p>
<p>You can find a step-by-step guide on deploying a website on Netlify <a target="_blank" href="https://www.netlify.com/blog/2016/09/29/a-step-by-step-guide-deploying-on-netlify/">here</a>, and you can set up a custom domain <a target="_blank" href="https://www.netlify.com/blog/2021/12/20/how-to-add-custom-domains-to-netlify-sites/">here</a>.</p>
<p>With those details set up, visit <a target="_blank" href="https://app.netlify.com/teams/team-name/dns/yourdomain.com">https://app.netlify.com/teams/team-name/dns/yourdomain.com</a> (replacing team-name and <a target="_blank" href="http://yourdomain.com">yourdomain.com</a> with your team name and domain name.</p>
<p>This shows you the DNS records for your domain.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686138071052/827c0172-6289-454b-a296-bd9586cbd992.png" alt class="image--center mx-auto" /></p>
<p>Using the same record from steps 1 and 2, click on the add new record button to update the records on Netlify with these two DNS records:</p>
<h3 id="heading-record-1">Record 1</h3>
<ul>
<li><p>Type: A</p>
</li>
<li><p>Name: mail.yourdomain.com (See step 2).</p>
</li>
<li><p>Value: IP address of your shared server (see step 1).</p>
</li>
<li><p>TTL: 60 (or allow to use default)</p>
</li>
</ul>
<h3 id="heading-record-2">Record 2</h3>
<ul>
<li><p>Type: MX</p>
</li>
<li><p>Name: yourdomain.com</p>
</li>
<li><p>Value: mail.yourdomain.com</p>
</li>
<li><p>TTL: 60 (or allow to use default)</p>
</li>
<li><p>Priority: 0</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686138106672/6d120361-8985-42a6-a0ca-258183ec14db.png" alt class="image--center mx-auto" /></p>
<p>DNS changes usually take 24–48 hours to reflect the changes made.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>That's it. You've just added details from a shared host to Netlify. Here is a quick summary of what you accomplished.</p>
<ul>
<li><p>Retrieved IP addresses from shared hosting</p>
</li>
<li><p>Retrieved email server details</p>
</li>
<li><p>Update the DNS records on Netlify to point to your shared hosting for sending emails.</p>
</li>
</ul>
<h2 id="heading-references">References</h2>
<ul>
<li><p><a target="_blank" href="https://app.netlify.com/signup">Create a free Netlify account</a>.</p>
</li>
<li><p><a target="_blank" href="https://www.netlify.com/blog/2016/09/29/a-step-by-step-guide-deploying-on-netlify/">Deploying on Netlify</a></p>
</li>
<li><p><a target="_blank" href="https://www.netlify.com/blog/2021/12/20/how-to-add-custom-domains-to-netlify-sites/">Add a custom domain to Netlify sites</a>.</p>
</li>
</ul>
<p>I'd love to connect with you on <a target="_blank" href="https://twitter.com/codejagaban"><strong>Twitter</strong></a> | <a target="_blank" href="https://www.linkedin.com/in/codejagaban/"><strong>LinkedIn</strong></a> | <a target="_blank" href="https://github.com/codejagaban/"><strong>GitHub</strong></a></p>
<p>I hope you find this article helpful. Cheers.</p>
]]></content:encoded></item><item><title><![CDATA[Effectiveness of Developer Relations Programs: A Study of MongoDB, AWS, and Vercel]]></title><description><![CDATA[As part of a challenge I started called #90DaysofDevRel, I've been learning about developer relations for some weeks and was given the task of researching and writing a report regarding three developer companies, their developer relations programs, a...]]></description><link>https://blog.jamin.sh/effectiveness-of-developer-relations-programs-a-study-of-mongodb-aws-and-vercel</link><guid isPermaLink="true">https://blog.jamin.sh/effectiveness-of-developer-relations-programs-a-study-of-mongodb-aws-and-vercel</guid><category><![CDATA[developer relations]]></category><category><![CDATA[Programs]]></category><category><![CDATA[community]]></category><category><![CDATA[documentation]]></category><category><![CDATA[education]]></category><dc:creator><![CDATA[Trust Jamin]]></dc:creator><pubDate>Thu, 04 May 2023 16:18:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1683215676562/52004fe4-fa31-4c5c-8b81-e6a2a9e56060.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As part of a challenge I started called #90DaysofDevRel, I've been learning about developer relations for some weeks and was given the task of researching and writing a report regarding three developer companies, their developer relations programs, and how effective their activities are. I picked <a target="_blank" href="https://mongodb.com/">MongoDB</a>, <a target="_blank" href="https://aws.amazon.com/">Amazon Web Services (AWS)</a>, and <a target="_blank" href="https://vercel.com/">Vercel</a>. I categorized each company's activities into three areas. Here are my findings thus far:</p>
<h2 id="heading-mongodb">MongoDB</h2>
<p>MongoDB is a popular cross-platform NoSQL database. This means that, unlike traditional relational databases, it stores data in a way that is not a table. MongoDB stores data in a format that is similar to JSON. This makes it flexible and scalable for a wide range of uses, from small applications to large enterprise systems. Here are some ways their DevRel team has actively educated and enabled its users:</p>
<ul>
<li><p><strong>Community</strong>: The company has a community version for its members and has built a developer community that is friendly and helpful. They host a variety of events and webinars, both online and offline, centered around MongoDB, and also go on global tours to connect with developers and learn from their experiences. This commitment to engaging with their community and seeking feedback is a testament to the company's drive to constantly improve and innovate its product.</p>
</li>
<li><p><strong>Education</strong>: MongoDB has several educational resources to help developers become skilled in their products, such as the MongoDB University program, certification programs, and academic courses and curriculums on their products for educators and universities. There are also numerous how-to guides provided by the community for its members.</p>
</li>
<li><p><strong>Resources and Tools</strong>: Their documentation is well structured and has code samples, an easy how-to-get-started guide, and specific sections for different developers on how to use their product, such as JavaScript, C#, and Python. Etc., use cases, examples, and code samples as to how to use their products. They’ve also created tools to empower developers, such as CLIs, plugins, and drivers.</p>
</li>
</ul>
<p>Overall, the MongoDB DevRel team has put in a great effort to create a sense of community, a well-thought-out educational guide, an easy-to-use user guide, and amazing events and activities.</p>
<h2 id="heading-amazon-web-services-aws">Amazon Web Services (AWS)</h2>
<p>AWS is the world's most widely adopted cloud computing platform. AWS provides a range of cloud-based services, including computing, storage, databases, analytics, machine learning, IoT, security, and more, to individuals, businesses, and governments worldwide. AWS allows developers to build and deploy scalable, reliable, and cost-effective cloud applications. Here are some initiatives they've implemented that have made them stand out:</p>
<ul>
<li><p><strong>Community</strong>: The AWS community includes developers, architects, administrators, engineers, business leaders, and more from all over the world. Overall, the AWS community is passionate, collaborative, and supportive. They share knowledge through various channels, such as events, meetups, and webinars, both in person and virtually, and host conferences about their tools and how best to use them. Amazon is also big on open-source, and they show this by supporting, contributing to, and partnering with open-source leaders globally.</p>
</li>
<li><p><strong>Education</strong>: They have several customer enablement programs, like certification programs, to help their users learn new skills. These programs have helped build a strong community of certified professionals who are known all over the world for their knowledge and skills in AWS.</p>
</li>
<li><p><strong>Resources and Tools</strong>: Having multiple products, AWS has put great effort into creating good documentation, how-to-get-started guides, blog posts from experts, and tutorials on how to use their products. It's also interesting to know that their documentation and tutorials are available in different languages so that users from all over the world can use them easily.</p>
</li>
</ul>
<h2 id="heading-vercel">Vercel</h2>
<p>Vercel is a cloud-based platform for developing, deploying, and hosting modern front-end applications. They are also the creators of Next.js, a popular open-source React framework for building server-side rendering (SSR) and static web applications.</p>
<ul>
<li><p><strong>Community:</strong> Vercel's developer community is extremely active. As a company with a strong commitment to open source, they have developed valuable, free, and user-friendly software that thousands of developers around the world adore. Nextjs, their open-source React framework that thousands of developers use to create front-end applications, is an illustration of this. In addition, they host conferences about the software and tools they've created for developers. This provides the community's developers with a sense of belonging.</p>
</li>
<li><p><strong>Education</strong>: The DevRel team at Vercel not only educates developers on how to use their platform and open-source software through tutorials, blog posts, practical use cases, and video content, but they also showcase their expertise by building amazing products using Vercel's tools and writing tutorials on how they accomplished their goals. This provides developers with real-world examples of how to build their own products, making it an exciting and valuable learning experience.</p>
</li>
<li><p><strong>Resources and Tools</strong>: Vercel provides developers and managers with a comprehensive set of tools and resources for utilizing their products. There are CLI tools, excellent documentation on how to use their product, guides for integrating with other tools, and simple-to-use templates for the most popular front-end frameworks and libraries.</p>
</li>
</ul>
<p>Conclusively, while the developer relations (DevRel) approach companies take depends entirely on the goals and mission of the company, based on my research, I have discovered that these companies have something in common. They all work towards building a healthy relationship with their customers by educating, enabling, and inspiring them to build with incredible tools.</p>
<hr />
<p>Thanks for reading. I hope you had as much fun reading it as I did writing it.<br />This article is part of my #<a target="_blank" href="https://twitter.com/hashtag/90DaysofDevRel?src=hashtag_click">90DaysofDevRel</a> learning journey. For more updates on the challenge, feel free to connect with me on <a target="_blank" href="https://twitter.com/codejaban">Twitter</a>, where I document my daily activities.</p>
]]></content:encoded></item></channel></rss>