<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Arman @programmerByDay</title>
    <description>The latest articles on DEV Community by Arman @programmerByDay (@programmerbyday).</description>
    <link>https://dev.to/programmerbyday</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F514636%2Fb9bf7c4d-80b7-417f-95f7-d3ff5b23eb61.jpg</url>
      <title>DEV Community: Arman @programmerByDay</title>
      <link>https://dev.to/programmerbyday</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/programmerbyday"/>
    <language>en</language>
    <item>
      <title>How to Enhance Your Dev Workflow with Privacy-First, Client-Side Tools</title>
      <dc:creator>Arman @programmerByDay</dc:creator>
      <pubDate>Mon, 21 Jul 2025 00:28:58 +0000</pubDate>
      <link>https://dev.to/programmerbyday/how-to-enhance-your-dev-workflow-with-privacy-first-client-side-tools-45op</link>
      <guid>https://dev.to/programmerbyday/how-to-enhance-your-dev-workflow-with-privacy-first-client-side-tools-45op</guid>
      <description>&lt;p&gt;I am the kind of developer who hates to install things and likes to use online quick tools for my daily small dev tasks.&lt;/p&gt;

&lt;p&gt;I recently found myself frustrated (again) with the usual dev utilities online: slow, ad-heavy, sketchy data leaks, and zero consistency. Every time I needed something as simple as a YAML validator or regex tester, it felt like stepping into a time warp of old-school websites with painful UX.&lt;/p&gt;

&lt;p&gt;I had enough, So I decided to do something about it and build something better. And this time, I do it &lt;em&gt;in public&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Why privacy-first and local?
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;No tracking or spying&lt;/strong&gt;: Everything runs in browser. No user data is ever sent to server or anyone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero latency&lt;/strong&gt;: Instant results = no loading bars, no waiting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secure &amp;amp; portable&lt;/strong&gt;: Works offline or behind firewalls. Perfect for corporate private environments or company setups.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  💡 How I Started
&lt;/h2&gt;

&lt;p&gt;I started by bundling together a suite of essential dev tools that always annoyingly require a tab:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;YAML &amp;amp; JSON Validators / Formatters&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Markdown Editor&lt;/strong&gt; + Markdown→PDF/DOCX converter
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regex tester &amp;amp; builder&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diff checker&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Base64&lt;/strong&gt;, &lt;strong&gt;Timestamp&lt;/strong&gt;, &lt;strong&gt;UUID&lt;/strong&gt;, and &lt;strong&gt;Hash generators&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSV ↔ JSON converter&lt;/strong&gt;, &lt;strong&gt;HTML/XML encoder-decoder&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;QR Code &amp;amp; OG Image generator&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All running locally, loading in under 200 ms, even for big files.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔧 Demo time
&lt;/h2&gt;

&lt;p&gt;Need to prettify some JSON? Paste it here and see it clean and tree-formatted.&lt;br&gt;&lt;br&gt;
Testing a regex? Type it and instantly validate it with sample text.&lt;br&gt;&lt;br&gt;
Want a QR code for a URL? Generate it in-browser with a click.&lt;/p&gt;

&lt;p&gt;It’s live here: &lt;a href="https://www.DigitalToolpad.com" rel="noopener noreferrer"&gt;DigitalToolPad.com/tools&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 What’s next
&lt;/h2&gt;

&lt;p&gt;I’m aiming to make this a go-to dev/workspace for teams. The long-term plan is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Team subscriptions&lt;/strong&gt; – let businesses manage access&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom tool bundles&lt;/strong&gt; – choose only the tools your team needs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More tools by demand&lt;/strong&gt; – just tell me what you’re missing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;White-label deployments&lt;/strong&gt; – embed it into company portals&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🤝 I’d love your feedback
&lt;/h2&gt;

&lt;p&gt;Would this fit into your workflow? What tool are you always searching for? Would love your insight, especially if it’s something simple you wish "just worked."&lt;/p&gt;

&lt;p&gt;Thanks for reading, and feel free to ping me with questions on the implementation, stack, SEO strategy, or anything in between.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Posted as part of my journey building in public, no sponsorships, no fluff, just real dev tooling.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>devtools</category>
      <category>javascript</category>
      <category>showdev</category>
    </item>
    <item>
      <title>What is an Embedding? And Why Should Devs Care?</title>
      <dc:creator>Arman @programmerByDay</dc:creator>
      <pubDate>Mon, 16 Jun 2025 23:54:33 +0000</pubDate>
      <link>https://dev.to/programmerbyday/what-is-an-embedding-and-why-should-devs-care-404c</link>
      <guid>https://dev.to/programmerbyday/what-is-an-embedding-and-why-should-devs-care-404c</guid>
      <description>&lt;p&gt;If you're venturing into AI-powered applications, understanding embeddings is crucial. In this post, I’ll show you exactly what they are — and how to use them in a modern TypeScript stack with PostgreSQL + &lt;strong&gt;pgvector&lt;/strong&gt;. Let's demystify this concept.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is an Embedding?
&lt;/h2&gt;

&lt;p&gt;An &lt;strong&gt;embedding&lt;/strong&gt; is a vector—a list of numbers—that captures the &lt;strong&gt;meaning&lt;/strong&gt; of a piece of data, such as text, images, or audio. It transforms:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;✍️ Text → 🧠 Meaning → 🔢 Vector&lt;/p&gt;

&lt;p&gt;"I love programming."\&lt;br&gt;
becomes → &lt;code&gt;[0.123, 0.089, ..., 0.245]&lt;/code&gt; (1536 dimensions)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Similar texts = similar vectors (close in distance).&lt;/p&gt;

&lt;h3&gt;
  
  
  Example:
&lt;/h3&gt;

&lt;p&gt;Consider these two sentences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;“I love programming.”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;“Coding is my passion.”&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These have different words but similar meaning. Their embeddings—numerical representations—are close in vector space, reflecting their semantic similarity.&lt;/p&gt;

&lt;h2&gt;
  
  
  So… How Are Embeddings Generated?
&lt;/h2&gt;

&lt;p&gt;Embedding models (like &lt;code&gt;text-embedding-ada-002&lt;/code&gt; from OpenAI or &lt;code&gt;all-MiniLM-L6-v2&lt;/code&gt; from HuggingFace) process your text through a deep neural network trained on massive corpora.&lt;/p&gt;

&lt;p&gt;Here’s what they do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Tokenize your input.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Process through Transformer layers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Output a vector—e.g., 384 or 1536 floats—that &lt;strong&gt;represents&lt;/strong&gt; that sentence in vector space.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You don’t need to train these from scratch. Just use the APIs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhfir8ketp0pfbb72z51q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhfir8ketp0pfbb72z51q.png" alt="Visual representation of similar sentences positioned closely in vector space" width="800" height="800"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.openai.com/v1/embeddings&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authorization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;I love programming.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-embedding-ada-002&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;embedding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;embedding&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// This is a 1536-dimensional vector&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why Should Developers Care?
&lt;/h2&gt;

&lt;p&gt;Embeddings power:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;🔍 &lt;strong&gt;Semantic Search&lt;/strong&gt;: Search by meaning, not just keywords.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;🧠 &lt;strong&gt;Chat with Documents&lt;/strong&gt;: Retrieval-Augmented Generation (RAG).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;🎯 &lt;strong&gt;Recommendation Systems&lt;/strong&gt;: Suggest similar items based on content.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;🗂️ &lt;strong&gt;Clustering and Classification&lt;/strong&gt;: Group similar data points.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🛠️ Store Embeddings in PostgreSQL (with pgvector extension)
&lt;/h2&gt;

&lt;p&gt;PostgreSQL supports &lt;code&gt;pgvector&lt;/code&gt;, which makes PostgreSQL a full-on vector database.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Create the table
&lt;/h3&gt;

&lt;p&gt;Use SQL to create your table with a &lt;code&gt;vector&lt;/code&gt; column:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;EXTENSION&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;documents&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;embedding&lt;/span&gt; &lt;span class="n"&gt;VECTOR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1536&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Insert from TypeScript
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Pool&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Pool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Your Neon DB URL&lt;/span&gt;
  &lt;span class="na"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;rejectUnauthorized&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INSERT INTO documents (content, embedding) VALUES ($1, $2)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;I love programming.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;embedding&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🔍 Perform a Semantic Search
&lt;/h2&gt;

&lt;p&gt;Let’s search for the top 5 documents semantically closest to a given input:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.openai.com/v1/embeddings&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authorization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Coding is fun&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-embedding-ada-002&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;queryVector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;embedding&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`
  SELECT content, embedding &amp;lt;#&amp;gt; $1 AS distance
  FROM documents
  ORDER BY distance ASC
  LIMIT 5
`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;queryVector&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;&amp;lt;#&amp;gt;&lt;/code&gt; is the cosine distance operator in &lt;code&gt;pgvector&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Smaller &lt;code&gt;distance&lt;/code&gt; = higher similarity.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🚀 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Embeddings are &lt;strong&gt;not just for ML engineers&lt;/strong&gt; anymore. With a few lines of TypeScript and a PostgreSQL DB, you can build semantic search, recommendations, AI chat, and more.&lt;/p&gt;

&lt;p&gt;All inside your favorite stack.&lt;/p&gt;

&lt;p&gt;If you want a starter template using Next.js + Neon + pgvector + OpenAI, let me know, I’ll publish it on GitHub.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;P.S: This post has been written via (JekyllPad)[&lt;a href="https://www.JekyllPad.com" rel="noopener noreferrer"&gt;https://www.JekyllPad.com&lt;/a&gt;]&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>vectordatabase</category>
      <category>postgres</category>
    </item>
    <item>
      <title>How I Created My Own Background Jobs Server At Home in TypeScript</title>
      <dc:creator>Arman @programmerByDay</dc:creator>
      <pubDate>Fri, 03 May 2024 00:30:03 +0000</pubDate>
      <link>https://dev.to/programmerbyday/how-i-created-my-own-background-jobs-server-at-home-in-typescript-330d</link>
      <guid>https://dev.to/programmerbyday/how-i-created-my-own-background-jobs-server-at-home-in-typescript-330d</guid>
      <description>&lt;p&gt;There are very good cloud services available to create background jobs in Nextjs serverless environments (such as Vercel or Netlify), however, they have a big problem. There is a function timeout on each call and therefore you cannot have long-running background jobs in there.&lt;/p&gt;

&lt;p&gt;That's why I decide to start my own background jobs server, but with a totally new approach. I wanted it use the same code but extract the job functions and run them in a docker container. It can be easily run on an old laptop or home PC.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Define job functions
&lt;/h2&gt;

&lt;p&gt;I checked and compared multiple npm packages and decided to use &lt;code&gt;Cron&lt;/code&gt; npm package for job functions. To install it,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="nx"&gt;cron&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cron npm package, lets me to define functions and assign cron time string to run them. Therefore, it's a great choice for me.&lt;/p&gt;

&lt;p&gt;Then, create a folder in your code called &lt;code&gt;worker&lt;/code&gt;, and inside that create a file called &lt;code&gt;run-jobs.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// run-jobs.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CronJob&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cron&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mySpecialFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Function Started!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;job1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;CronJob&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;cronTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0 */2 * * *&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;onTick&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`job1 started at &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;/// DO WHATEVER YOU WANT TO DO HERE      &lt;/span&gt;

      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`job1 finished at &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;onComplete&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;job1 ended&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;timeZone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Australia/Sydney&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Worker Started!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;mySpecialFunction&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you have a file that starts a function. You can define as many functions you want here, each with a different cron time string.&lt;/p&gt;

&lt;p&gt;To learn more about how cron functions are defined take a look &lt;a href="https://www.npmjs.com/package/cron"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To learn more about how cron time string should be defined, use this &lt;a href="https://crontab.guru/"&gt;crontab.guru tool&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Extract functions code using Webpack
&lt;/h2&gt;

&lt;p&gt;In order to run functions in a docker container, first I needed to extract them out of the code. There is no need to include all the codebase into the docker container. This way, your container will be as small as possible and can be run on a small Laptop or PC at home easily.&lt;/p&gt;

&lt;p&gt;In order to use Webpack, first we need to install it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;save&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;dev&lt;/span&gt; &lt;span class="nx"&gt;webpack&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You also need to install ts-loader package to be able to use typescript files in webpack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;save&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;dev&lt;/span&gt; &lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;loader&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, inside your worker folder, create a file called &lt;em&gt;webpack.config.js :&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;development&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./run-jobs.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;tsx&lt;/span&gt;&lt;span class="se"&gt;?&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;use&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ts-loader&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;exclude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/node_modules/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../src/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.tsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bundle.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dist&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Important for Node.js specific modules&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this config file, we are telling webpack to start from 'run-jobs.ts' file from current folder path. It tried to extract the code (with all their dependencies) into a bundle or package defined in the 'output' section.&lt;/p&gt;

&lt;p&gt;We added ts-loader plugin for webpack, so that it can work with Typescript files. Also, if you are using '@' in your import paths, you need to define where this '@' refers to. This is what I did in 'alias' section.&lt;/p&gt;

&lt;p&gt;You can test this easily with running this command in your worker folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;npx&lt;/span&gt; &lt;span class="nx"&gt;webpack&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should start webpack and based on the config we defined, extract the code require to run jobs and bundle them into a .js file called bundle.js in a folder called 'dist'.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Defining Docker Container
&lt;/h2&gt;

&lt;p&gt;Creating a docker container is easy now since everything is ready. First create a file called 'Dockerfile' in worker folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;FROM&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;18.19&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="nx"&gt;WORKDIR&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;

&lt;span class="nx"&gt;COPY&lt;/span&gt; &lt;span class="nx"&gt;node_modules&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;node_modules&lt;/span&gt;

&lt;span class="nx"&gt;COPY&lt;/span&gt; &lt;span class="nx"&gt;dist&lt;/span&gt;&lt;span class="cm"&gt;/* .

CMD ["node", "bundle.js"]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This file tells docker on what to do in order to create the docker container to run jobs. Remember that you cannot access any file outside of this folder in Dockerfile.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Run it!
&lt;/h2&gt;

&lt;p&gt;Now, it's time to put everything together, create the docker and run it for the first time. Create a bash file called 'build-and-run.sh' and put these command in it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;rm&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;rf&lt;/span&gt; &lt;span class="nx"&gt;dist&lt;/span&gt;
&lt;span class="nx"&gt;rm&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;rf&lt;/span&gt; &lt;span class="nx"&gt;node_modules&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cd&lt;/span&gt; &lt;span class="p"&gt;..&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cd&lt;/span&gt; &lt;span class="p"&gt;..&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;cp&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="nx"&gt;node_modules&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;npx&lt;/span&gt; &lt;span class="nx"&gt;webpack&lt;/span&gt;

&lt;span class="nx"&gt;docker&lt;/span&gt; &lt;span class="nx"&gt;build&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="nx"&gt;my&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;jobs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nx"&gt;docker&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;detach&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;rm&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="nx"&gt;my&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;jobs&lt;/span&gt; &lt;span class="nx"&gt;my&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;jobs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Couple of points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You need to do npm install first so that all dependencies already exist before you run Webpack. Webpack expects to have access to all node_modules when you run it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Docker cannot copy node_modules from outside folders, therefore I copy node_modules from upper-folder into this folder first.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Docker Build&lt;/code&gt; runs docker based on the Dockerfile we created before and creates the docker image for us.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Docker Run&lt;/code&gt; starts the docker in detach mode. Note that I copied my env file and referencing it to the docker container. This way all your environment variables will be available inside the container.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I like to use &lt;code&gt;--rm&lt;/code&gt; so that when the container is finished/stopped, docker automatically deletes it, so that there is no name conflict in future runs.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Run It At Home
&lt;/h2&gt;

&lt;p&gt;I'm not recommending it, but if you want to run it at home on an old laptop/pc, you just need to install docker on it, pull the code base on it, and run this shell script on it.&lt;/p&gt;

&lt;p&gt;Voila, now you can have infinite number of jobs defined and you won't be bounded by Vercel serverless function timeout or any other platform :)&lt;/p&gt;

&lt;p&gt;Let me know what you think about it, you can find me on &lt;a href="https://twitter.com/programmerByDay"&gt;Twitter (X) here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>vercel</category>
      <category>react</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Top 5 Online Markdown Editors (2024)</title>
      <dc:creator>Arman @programmerByDay</dc:creator>
      <pubDate>Thu, 04 Apr 2024 23:19:51 +0000</pubDate>
      <link>https://dev.to/programmerbyday/top-5-online-markdown-editors-2024-76h</link>
      <guid>https://dev.to/programmerbyday/top-5-online-markdown-editors-2024-76h</guid>
      <description>&lt;p&gt;When I first embarked on my blogging journey on Github Pages, one of the biggest challenges I faced was finding the right markdown editor. With an array of options available, each boasting different features and functionalities, it was a bit overwhelming to choose the perfect fit.&lt;/p&gt;

&lt;p&gt;Through trial and error, I've narrowed down the list to the top 5 online markdown editors that have significantly streamlined my writing process. In this post, I'm sharing these gems with you, hoping they'll make your content creation as enjoyable and efficient as they have made mine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.JekyllPad.com%2Fimg%2Fposts%2Fpost5-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.JekyllPad.com%2Fimg%2Fposts%2Fpost5-1.png" alt="top 5 online markdown editors "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. &lt;a href="https://www.jekyllpad.com/tools/online-markdown-wysiwyg-editor" rel="noopener noreferrer"&gt;JekyllPad Markdown Editor&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I started building JekyllPad when I felt there is not one that fits my needs.&lt;/p&gt;

&lt;p&gt;JekyllPad.com stands out as an innovative online markdown editor, specifically tailored for Jekyll blogs hosted on GitHub Pages. It redefines the blogging experience by providing a user-friendly, intuitive interface, making it accessible for both beginners and seasoned developers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Its WYSIWYG markdown editor simplifies content creation, allowing users to focus on their writing while the tool takes care of the technical details.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Key features of JekyllPad include seamless media integration, which enables easy addition of images and videos to enrich your content. It also offers efficient image gallery management, enhancing the visual appeal of your blogs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The direct syncing with GitHub ensures that your work is always up-to-date and securely stored. JekyllPad's commitment to simplicity and efficiency makes it arguably the best markdown editor on the internet for Jekyll users.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a detailed look at all the features and to experience JekyllPad yourself, visit &lt;a href="https://www.JekyllPad.com" rel="noopener noreferrer"&gt;JekyllPad.com&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. &lt;a href="https://pandao.github.io/editor.md/en.html" rel="noopener noreferrer"&gt;Editor.md&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Editor.md is an open-source online Markdown editor that is feature-rich and versatile. It supports Standard Markdown, CommonMark, GFM (GitHub Flavored Markdown), and Markdown Extras, making it highly adaptable for various markdown needs.&lt;/p&gt;

&lt;p&gt;Editor.md stands out with its full-featured capabilities including real-time preview, image upload, code syntax highlighting, and support for LaTeX expressions, Flowchart, and Sequence Diagram.&lt;/p&gt;

&lt;p&gt;It's ideal for those who need a comprehensive markdown editor that is compatible across major browsers and integrates well with different workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. &lt;a href="https://stackedit.io/app" rel="noopener noreferrer"&gt;StackEdit&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;StackEdit is a powerful online markdown editor perfect for writers, bloggers, and anyone needing a robust tool for their markdown needs.&lt;/p&gt;

&lt;p&gt;Its user-friendly interface and rich set of features, including live preview, synchronization with cloud services, and collaborative writing capabilities, make it a top choice.&lt;/p&gt;

&lt;p&gt;Whether you're drafting a blog post or taking notes, StackEdit offers a seamless and efficient writing experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. &lt;a href="https://dillinger.io" rel="noopener noreferrer"&gt;Dillinger&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Dillinger is an impressive cloud-enabled, mobile-ready markdown editor, ideal for those constantly on the move.&lt;/p&gt;

&lt;p&gt;It allows you to write and export markdown documents directly from your browser. The editor supports various cloud services for saving and retrieving your documents, making your writing accessible anywhere.&lt;/p&gt;

&lt;p&gt;Dillinger's simplicity and ease of use make it a great choice for markdown enthusiasts of all levels.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. &lt;a href="https://typora.io" rel="noopener noreferrer"&gt;Typora&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Typora stands out as a minimal markdown editor that provides a seamless live preview feature.&lt;/p&gt;

&lt;p&gt;It removes the preview window, mode switcher, and syntax symbols of markdown source code, offering a clean and immersive writing experience.&lt;/p&gt;

&lt;p&gt;Typora supports images, lists, tables, code fences, and more, making it a versatile tool for writing. It's ideal for those who prefer a distraction-free environment to focus solely on their writing.&lt;/p&gt;

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

&lt;p&gt;As I wrap up this list, I hope my journey through discovering these markdown editors helps you find your perfect match. Each editor has its own charm and set of features that cater to different writing styles and needs.&lt;/p&gt;

&lt;p&gt;Remember, the right tool can transform your writing experience from tedious to terrific. So, dive in, try them out, and see which one resonates with your creative flow!&lt;/p&gt;

</description>
      <category>markdown</category>
      <category>github</category>
      <category>jekyll</category>
      <category>blog</category>
    </item>
    <item>
      <title>How to Host an External Blog on Your Site's /blog URL</title>
      <dc:creator>Arman @programmerByDay</dc:creator>
      <pubDate>Thu, 28 Mar 2024 04:53:52 +0000</pubDate>
      <link>https://dev.to/programmerbyday/how-to-host-an-external-blog-on-your-sites-blog-url-34e5</link>
      <guid>https://dev.to/programmerbyday/how-to-host-an-external-blog-on-your-sites-blog-url-34e5</guid>
      <description>&lt;p&gt;Having a blog as part of your website is like opening a window into the heart of your business or passion project. It’s not just about sharing ideas; it’s a powerful tool to connect and grow. Especially when it’s located right on your site, under the easy-to-remember /blog URL. This isn't just good for your audience; it's great for search engines too.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--duQ47HgJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.jekyllpad.com/img/posts/post8-img-1.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--duQ47HgJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.jekyllpad.com/img/posts/post8-img-1.webp" alt="Modern and engaging blog page on a desktop in a cozy home office setup, illustrating the integration of personal passion with professional web presence" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Search engines love fresh content. A blog that's part of your site means there's always something new for them to index. This can boost your site's visibility and lead more people to discover what you have to offer. Whether you’re sharing insights, tips, or stories, each post helps paint a picture of what makes your work unique.&lt;/p&gt;

&lt;p&gt;Now, imagine having an external blog on your website. This could be a blog you've started on WordPress, Medium, or even GitHub Pages. \&lt;br&gt;
Integrating this into your site could bring all sorts of benefits. It means you can tap into the features and ease of use these platforms offer while keeping your audience close to home.&lt;/p&gt;

&lt;p&gt;Your readers won't have to hop between sites to catch up on your latest posts. Everything’s right there, under your /blog URL, making for a smoother, more cohesive user experience. On top of that, You'll get SEO juice for your website on every content you publish.&lt;/p&gt;
&lt;h2&gt;
  
  
  Understanding the Challenge
&lt;/h2&gt;

&lt;p&gt;Many website owners want their blog to live under the easy-to-remember &lt;strong&gt;/blog&lt;/strong&gt; URL but find the process challenging. Why is that?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YOEnU3jP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.jekyllpad.com/img/posts/post8-img-2.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YOEnU3jP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.jekyllpad.com/img/posts/post8-img-2.webp" alt="Web developer puzzled over blog integration, comparing subdomain and directory for SEO and user experience" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Well, every piece of your website needs to fit perfectly to create a smooth, enjoyable experience for your visitors. When it comes to adding a blog, especially one that's hosted externally on platforms like WordPress, Medium, or even GitHub Pages, the fit needs to be just right.&lt;/p&gt;

&lt;p&gt;The biggest hurdle? Ensuring a cohesive user experience and seamless integration. Your blog isn't just a collection of posts; it's a vital part of your website's identity. When visitors click from your homepage to your blog, they shouldn't feel like they've left your site. The design, navigation, and overall feel should be consistent. This unity is crucial not just for user experience but from an SEO standpoint as well.&lt;/p&gt;

&lt;p&gt;Speaking of SEO, let's talk about why hosting your blog as a subdomain (like &lt;strong&gt;blog.yoursite.com&lt;/strong&gt;) might not be the best idea. While it might seem like a simple solution, search engines like Google treat subdomains almost like separate websites. This means that all the hard work you put into your blog posts—those keywords you've researched, the quality content you've created—doesn't directly contribute to the SEO authority of your main website domain. Instead, hosting your blog in a subdirectory (like &lt;strong&gt;yoursite.com/blog&lt;/strong&gt;) ensures that your main site benefits from every visitor, every link, and every bit of recognition your blog receives.&lt;/p&gt;

&lt;p&gt;Achieving this seamless blend of blog and website, where each blog post reinforces the strength of your main domain, is the key to overcoming the integration challenge. It's about making sure every piece of the puzzle fits perfectly, enhancing both the user experience and your site's SEO performance.&lt;/p&gt;
&lt;h2&gt;
  
  
  Solutions Overview
&lt;/h2&gt;

&lt;p&gt;When you decide to host an external blog on your website's &lt;strong&gt;/blog&lt;/strong&gt; URL, you're taking a significant step towards enriching your site's content and SEO. But how do you go about it? There are two main paths you can take, each suited to different kinds of website management scenarios. Let's break them down.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ryFU_7tF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.jekyllpad.com/img/posts/post8-img-3.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ryFU_7tF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.jekyllpad.com/img/posts/post8-img-3.webp" alt="Crossroad signpost illustrating the choice between hosting server control and source code control for blog integration" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;If You Have Control of the Web Server \&lt;br&gt;
If you're in charge of your website's hosting web server—think Apache, Nginx, or similar platforms—you have the freedom to configure the server settings directly. This path allows you to set up reverse proxies, redirects, and other server-level configurations to seamlessly integrate your external blog into your main site. It's a bit like having the master keys to the building; you can set up the space exactly how you like it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If You Have Control of the Source Code of Your Website \&lt;br&gt;
For those who have direct control over their website's source code but might not have access to server settings, there's another route. This approach involves integrating the blog into your site through coding solutions—embedding, API calls, or even custom scripts that pull in your blog content to the /blog section of your site. It's akin to crafting the interior of your space to make it welcoming and functional, even if you can't alter the building itself.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each of these paths has its set of tools and techniques, which I'll dive into in the next sections. Whether you're a server guru or a code wizard, there's a way to make your blog feel right at home on your website.&lt;/p&gt;
&lt;h2&gt;
  
  
  Integrating Blog using Web Server
&lt;/h2&gt;

&lt;p&gt;Incorporating an external blog into your website's /blog URL can be seamlessly achieved through the strategic use of web server configurations, specifically with servers like NGINX and Apache. These powerful tools have the capability to act as intermediaries, or proxies, funneling requests from your visitors directly to an external blog platform without the user ever noticing a difference.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZyRbjPK---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.jekyllpad.com/img/posts/post8-img-4.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZyRbjPK---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.jekyllpad.com/img/posts/post8-img-4.webp" alt="Web developer configuring reverse proxy on NGINX, Apache, and IIS for blog integration" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Imagine you're at a busy train station, but instead of trains, you're directing internet traffic. This is what a reverse proxy does. It's like a traffic director for the web. When someone visits your blog, the reverse proxy decides where to send that request on your network. This way, you can have your blog somewhere else but make it appear as if it's part of your main website, under the &lt;strong&gt;/blog&lt;/strong&gt; URL.&lt;/p&gt;
&lt;h3&gt;
  
  
  What is a Reverse Proxy and How It Works?
&lt;/h3&gt;

&lt;p&gt;A reverse proxy sits between the internet and your web server. Think of it as a middleman. When someone types in your website looking for your blog, the reverse proxy takes this request and forwards it to where your blog is actually hosted, like on WordPress, Medium, or GitHub Pages. Then, it takes the blog's response and sends it back to the visitor. All of this happens behind the scenes, making your blog feel like an integral part of your website without actually being on your main server.&lt;/p&gt;
&lt;h3&gt;
  
  
  NGINX Reverse Proxy
&lt;/h3&gt;

&lt;p&gt;NGINX is a popular choice for setting up a reverse proxy due to its efficiency and flexibility. To host an external blog under the &lt;strong&gt;/blog&lt;/strong&gt; URL with NGINX, you would use a configuration snippet like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;location /blog/ &lt;span class="o"&gt;{&lt;/span&gt;
    proxy_pass https://your_external_blog_address&lt;span class="p"&gt;;&lt;/span&gt;
    proxy_set_header Host &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    proxy_set_header X-Real-IP &lt;span class="nv"&gt;$remote_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    proxy_set_header X-Forwarded-For &lt;span class="nv"&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    proxy_set_header X-Forwarded-Proto &lt;span class="nv"&gt;$scheme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells NGINX that whenever someone visits &lt;strong&gt;yourwebsite.com/blog&lt;/strong&gt;, it should forward those requests to &lt;strong&gt;&lt;a href="https://your_external_blog_address"&gt;https://your_external_blog_address&lt;/a&gt;&lt;/strong&gt; and then serve that content back to the visitor as if it were coming from your own site.&lt;/p&gt;

&lt;h3&gt;
  
  
  Apache Reverse Proxy
&lt;/h3&gt;

&lt;p&gt;Apache, another widely used web server, can also be configured to serve an external blog under the &lt;strong&gt;/blog&lt;/strong&gt; URL. An Apache reverse proxy configuration might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ProxyPass &lt;span class="s2"&gt;"/blog"&lt;/span&gt; &lt;span class="s2"&gt;"https://your_external_blog_address"&lt;/span&gt;
ProxyPassReverse &lt;span class="s2"&gt;"/blog"&lt;/span&gt; &lt;span class="s2"&gt;"https://your_external_blog_address"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This setup directs any traffic going to &lt;strong&gt;yourwebsite.com/blog&lt;/strong&gt; to your external blog platform and then back to the user, making the blog appear to be hosted on your main site.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reverse Proxy in IIS
&lt;/h3&gt;

&lt;p&gt;For those using Windows servers, Internet Information Services (IIS) can also be configured to use a reverse proxy. With the URL Rewrite module and Application Request Routing, you can set up a rule like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;rule&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"ReverseProxyInboundRule1"&lt;/span&gt; &lt;span class="na"&gt;stopProcessing=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;match&lt;/span&gt; &lt;span class="na"&gt;url=&lt;/span&gt;&lt;span class="s"&gt;"blog/(.*)"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;action&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"Rewrite"&lt;/span&gt; &lt;span class="na"&gt;url=&lt;/span&gt;&lt;span class="s"&gt;"https://your_external_blog_address/{R:1}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/rule&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This IIS configuration forwards all requests from &lt;strong&gt;yourwebsite.com/blog&lt;/strong&gt; to the external blog, ensuring visitors access your blog content under your main website’s URL.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating Blog using Source Code
&lt;/h2&gt;

&lt;p&gt;Integrating an external blog into your website's /blog URL through source code manipulation involves setting up a proxy within your application. This method allows you to route requests for your blog through your main application, fetching and displaying content from the external blog platform as if it were part of your original site. Let's explore how this can be achieved in various server-side and client-side frameworks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Next.js
&lt;/h3&gt;

&lt;p&gt;To integrate an external blog into your Next.js application under the /blog URL using Next.js rewrites, you can leverage the &lt;code&gt;rewrites&lt;/code&gt; feature in your &lt;code&gt;next.config.js&lt;/code&gt; file. This approach does not require server-side API routes but rather a configuration that tells Next.js to proxy requests for /blog to your external blog platform. Here’s how you can do it:&lt;/p&gt;

&lt;p&gt;Open or create the next.config.js file in the root of your Next.js project.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add a rewrites async function to define custom rewrite rules.&lt;/li&gt;
&lt;li&gt;Here is an example configuration that redirects requests from /blog to &lt;a href="https://external-blog.com:"&gt;https://external-blog.com:&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;rewrites&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/blog/:slug*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://external-blog.com/:slug*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// Proxy to External Blog&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This setup ensures that any request to yoursite.com/blog/_ will be proxied to the corresponding path at &lt;a href="https://external-blog.com/_"&gt;https://external-blog.com/_&lt;/a&gt;, seamlessly integrating the external blog content under your site’s /blog path without changing the URL in the browser.&lt;/p&gt;

&lt;p&gt;Remember, while rewrites are powerful for seamlessly integrating content, they do not enable server-side rendering of the proxied content. The content will be fetched client-side, which means the initial HTML response will not contain the blog content. This approach is great for user experience but consider SEO implications, as search engines may not index the proxied content as part of your site.&lt;/p&gt;

&lt;h3&gt;
  
  
  Next.js Server-Side
&lt;/h3&gt;

&lt;p&gt;Next.js supports API routes, which you can use to create a proxy endpoint for your external blog.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new API route in your Next.js project under pages/api/blog/[...slug].js.&lt;/li&gt;
&lt;li&gt;Use fetch to call the external blog API and return the blog content.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// pages/api/blog/[...slug].js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://external-blog.com/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  C# ASP.NET Core
&lt;/h3&gt;

&lt;p&gt;ASP.NET Core can use middleware to forward requests to an external blog.&lt;/p&gt;

&lt;p&gt;Create a middleware that intercepts requests to &lt;strong&gt;/blog&lt;/strong&gt; and forwards them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In your Startup.cs&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartsWithSegments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/blog"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;remainder&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;externalResponse&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"https://external-blog.com&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;remainder&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;externalResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAsStringAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContentType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;externalResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContentType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Client-side Frameworks (React, Vue.js, Angular, and Svelte)
&lt;/h3&gt;

&lt;p&gt;For client-side frameworks, integrating an external blog typically involves making an AJAX request to the external blog's API and rendering the content. Due to the similar nature of these frameworks in handling HTTP requests, the approach is somewhat uniform:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use the native fetch API or a library like axios to request the blog content.&lt;/li&gt;
&lt;li&gt;Set up a route in your application (using React Router, Vue Router, etc.) for /blog.&lt;/li&gt;
&lt;li&gt;In the component mounted to the /blog route, make the request to the external blog and render the response.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example in React (applicable concept for Vue, Angular, Svelte with respective syntax adjustments):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// BlogComponent.jsx in React&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;BlogComponent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;blogContent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setBlogContent&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://external-blog.com/api/posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setBlogContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;dangerouslySetInnerHTML&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;__html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;blogContent&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For each framework, adapt the fetching and state management according to its conventions. The key is to fetch the blog data from the external source and integrate it seamlessly into your app's component structure, making the external content appear as though it's a native part of your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating Blog using Feed or Its Url
&lt;/h2&gt;

&lt;p&gt;Integrating a blog into your website doesn't always mean you have to host the blog yourself. Sometimes, you might find it easier or more convenient to pull in content from an external blog. Two popular methods for doing this are using RSS feeds and iframes. Both offer unique advantages and considerations, especially when it comes to implementation and SEO.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8xmDd3nO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.jekyllpad.com/img/posts/post8-img-5.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8xmDd3nO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.jekyllpad.com/img/posts/post8-img-5.webp" alt="RSS and iframe" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Using RSS Feeds
&lt;/h3&gt;

&lt;p&gt;RSS stands for Really Simple Syndication. It's a type of web feed that allows users and applications to access updates to online content in a standardized, computer-readable format. By using the RSS feed of an external blog, you can display its latest posts directly on your website.&lt;/p&gt;

&lt;p&gt;To do this, you'd typically fetch the RSS feed programmatically and then parse the XML to render the blog posts in your site's HTML. This method keeps your site content fresh and ensures visitors have access to the latest posts without needing to navigate away from your site.&lt;/p&gt;

&lt;p&gt;Here's a simplified example in JavaScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://external-blog.com/rss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DOMParser&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;parseFromString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text/xml&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;item&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;article&amp;gt;
                &amp;lt;h2&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/h2&amp;gt;
                &amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;description&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/p&amp;gt;
              &amp;lt;/article&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blog-posts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using Iframes
&lt;/h3&gt;

&lt;p&gt;An iframe, or inline frame, is an HTML element that allows an external webpage to be embedded within your own webpage. This means you can simply place the external blog directly on your website by using its URL. However, while iframes are easy to implement, they have limitations, especially regarding SEO. Content within an iframe is considered part of the external site, not your site, so it doesn't contribute to your site's SEO.&lt;/p&gt;

&lt;p&gt;Here's how you might embed an external blog using an iframe:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;iframe&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://external-blog.com"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"100%"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"600px"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that, while iframes are convenient for embedding content like videos or external blogs, they're not ideal for SEO. Search engines typically crawl and index the content of the parent page, not the content within the iframe. This means that even though your site visitors can see and interact with the blog content through the iframe, this content doesn't directly boost your site's search engine ranking.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tips for Seamless Blog Integration into Your Website
&lt;/h2&gt;

&lt;p&gt;Integrating a blog into your main website isn't just about plugging in content; it's about creating a seamless experience for your visitors. This means ensuring that your blog feels like an integral part of your site, not just an afterthought. Here are some tips to help you achieve this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--htOITj77--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.jekyllpad.com/img/posts/post8-img-6.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--htOITj77--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.jekyllpad.com/img/posts/post8-img-6.webp" alt="Seamless Blog Integration" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Consistent Look and Feel
&lt;/h3&gt;

&lt;p&gt;Your blog and website should look like they belong together. This goes beyond just slapping your website's header on top of your blog posts. You'll want to match the font styles, color schemes, and even the button designs between your blog and the main site. If your website uses a minimalist design with lots of white space, your blog should follow suit. Consistency in design makes your whole site feel professional and cohesive.&lt;/p&gt;

&lt;h3&gt;
  
  
  Smooth Navigation and Linking
&lt;/h3&gt;

&lt;p&gt;Navigation between your blog and the main site should be effortless. Ideally, visitors shouldn't even have to think about whether they're on your blog or another part of your site. Here are a couple of ways to achieve this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use Relative URLs:&lt;/strong&gt; When linking to different parts of your site, use relative URLs (like &lt;strong&gt;/contact&lt;/strong&gt;) rather than absolute paths (like &lt;strong&gt;&lt;a href="http://www.yoursite.com/contact"&gt;www.yoursite.com/contact&lt;/a&gt;&lt;/strong&gt;). This ensures that links will work correctly regardless of the subdomain or domain changes and helps keep the user experience smooth and consistent.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unified Navigation Bar:&lt;/strong&gt; Ensure that your site’s navigation bar is present across all pages, including blog posts. This makes it easy for visitors to explore other sections of your site without having to backtrack.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Engaging User Experience
&lt;/h3&gt;

&lt;p&gt;Finally, consider the overall user experience. Your blog should load quickly, be easy to read, and be accessible on both desktop and mobile devices. Engaging images, videos, and other multimedia elements can also help to break up text and make your content more enjoyable to consume.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Pitfalls and How to Avoid Them
&lt;/h2&gt;

&lt;p&gt;Integrating an external blog into your main website can be a game-changer for content diversity and engagement. However, there are common pitfalls that can hinder your success and impact your site's SEO negatively.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4ArBZiE9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.jekyllpad.com/img/posts/post8-img-7.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4ArBZiE9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.jekyllpad.com/img/posts/post8-img-7.webp" alt="Web developer navigating SEO challenges in blog integration, highlighting the importance of overcoming common pitfalls for optimal website performance" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's explore how to navigate these challenges and ensure your blog enhances your website's overall search engine ranking.&lt;/p&gt;

&lt;h3&gt;
  
  
  Avoid Duplicate Content
&lt;/h3&gt;

&lt;p&gt;One of the biggest risks when integrating an external blog is creating duplicate content. Search engines penalize sites that publish content that exists elsewhere on the web. To avoid this, ensure that your integrated blog content is unique to your site or use canonical tags to indicate the preferred URL of content that's published in multiple places.&lt;/p&gt;

&lt;h3&gt;
  
  
  Maintain Loading Speed
&lt;/h3&gt;

&lt;p&gt;Another critical factor is your website's loading speed. Integrating content from external sources can slow down your site, which negatively affects user experience and SEO. Optimize images, cache blog content, and use lazy loading to keep your site speedy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ensure Mobile Responsiveness
&lt;/h3&gt;

&lt;p&gt;With the majority of users accessing the web through mobile devices, your integrated blog must be mobile-friendly. A responsive design ensures that your blog looks great and functions well on all devices, which is crucial for keeping visitors engaged and improving your SEO.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keep Navigation Seamless
&lt;/h3&gt;

&lt;p&gt;The integration should be seamless, with blog posts easily accessible from your main site. Avoid using absolute URLs that can create a disjointed experience. Instead, use relative paths that keep users within your domain, strengthening your site's internal linking and SEO.&lt;/p&gt;

&lt;h3&gt;
  
  
  Regularly Update Content
&lt;/h3&gt;

&lt;p&gt;Fresh, regularly updated content is key to driving traffic and improving SEO. Ensure that your blog integration allows for easy updates and additions. This keeps your site dynamic and interesting for return visitors and search engines alike.&lt;/p&gt;

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

&lt;p&gt;Integrating an external blog onto your website’s /blog URL can significantly enrich your site's content and enhance its SEO. By thoughtfully choosing how to host and display your blog, you can ensure that it serves as a dynamic extension of your main site, attracting more visitors and improving your search engine rankings.&lt;/p&gt;

&lt;p&gt;I've explored several methods for integrating a blog for my &lt;a href="https://www.JekyllPad.com"&gt;Jekyll Blogging Editor and CMS&lt;/a&gt;, from RSS feeds and iframes to web server proxies and direct source code adjustments. Each approach has its unique advantages and considerations, especially regarding SEO. The key is to experiment with these methods to discover which one aligns best with your website's goals and your audience's needs.&lt;/p&gt;

&lt;p&gt;I encourage you to try these techniques and see how they impact your site. And I'd love to hear from you! If you've experimented with integrating an external blog, or if you've faced any challenges along the way, reach out to me on social media, especially Twitter (X). Sharing your experiences can help others in the community make informed decisions and navigate their integration journeys more smoothly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/programmerByDay"&gt;&lt;br&gt;
    &lt;img alt="X (formerly Twitter) Follow" src="https://res.cloudinary.com/practicaldev/image/fetch/s--xP1J71ix--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://img.shields.io/twitter/follow/programmerByDay%3Flabel%3DFollow%2520me%2520%2540programmerByDay" width="193" height="20"&gt;&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

</description>
      <category>blog</category>
      <category>seo</category>
      <category>nextjs</category>
      <category>react</category>
    </item>
    <item>
      <title>How to Easily Start Blogging in 2023</title>
      <dc:creator>Arman @programmerByDay</dc:creator>
      <pubDate>Tue, 12 Dec 2023 20:50:02 +0000</pubDate>
      <link>https://dev.to/programmerbyday/how-to-easily-start-blogging-in-2023-4loo</link>
      <guid>https://dev.to/programmerbyday/how-to-easily-start-blogging-in-2023-4loo</guid>
      <description>&lt;p&gt;Blogging has evolved significantly, and today's landscape offers various platforms to share your voice. Among these, Jekyll combined with GitHub Pages stands out for its simplicity, power, and cost-effectiveness. &lt;/p&gt;

&lt;p&gt;In this comprehensive guide, we’ll walk you through the steps of setting up your blog using Jekyll, GitHub Pages and JekyllPad, perfect for beginners and seasoned bloggers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Jekyll and GitHub Pages
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is Jekyll?
&lt;/h3&gt;

&lt;p&gt;Jekyll is a popular static site generator, transforming plain text into static websites and blogs. &lt;/p&gt;

&lt;p&gt;It's widely praised for its simplicity, speed, and flexibility, allowing customization without the bloat of traditional CMS platforms. &lt;/p&gt;

&lt;p&gt;Ideal for bloggers who prefer control and efficiency, Jekyll is a cornerstone in the world of static site generation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why GitHub Pages?
&lt;/h3&gt;

&lt;p&gt;GitHub Pages (github.io) provides a free hosting solution, seamlessly integrating with Jekyll. &lt;/p&gt;

&lt;p&gt;It’s a perfect match for developers and bloggers who already use GitHub. Offering robust performance and ease of use, GitHub Pages makes publishing your Jekyll blog a hassle-free experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Your Jekyll Blog
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Creating a GitHub Account
&lt;/h3&gt;

&lt;p&gt;If you’re new to GitHub, setting up an account is your first step. It’s straightforward: visit GitHub’s website, sign up, and you're ready to go.&lt;/p&gt;

&lt;p&gt;A GitHub account not only gives you access to hosting on GitHub Pages but also opens up a world of possibilities for collaboration and version control.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Jekyll Now for Quick Setup
&lt;/h3&gt;

&lt;p&gt;By forking the &lt;a href="https://github.com/barryclark/jekyll-now"&gt;Jekyll Now repository&lt;/a&gt; on GitHub, you can bypass the complex configuration and jump straight into blogging. &lt;/p&gt;

&lt;p&gt;This approach is perfect for those who want to focus more on content than coding.&lt;/p&gt;

&lt;h3&gt;
  
  
  Customizing Your Jekyll Blog
&lt;/h3&gt;

&lt;p&gt;Customizing your Jekyll blog is easy. Start by editing the &lt;code&gt;_config.yml&lt;/code&gt; file to personalize settings like your blog’s title and description. &lt;/p&gt;

&lt;p&gt;You can also choose themes and customize layouts to match your style. Remember, changes you make are reflected once you push them to GitHub.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding Markdown
&lt;/h3&gt;

&lt;p&gt;Markdown is the heart of Jekyll’s content creation. It’s a simple markup language that lets you format text using plain text. &lt;/p&gt;

&lt;p&gt;For instance, # for headers or * for bullet points. It's straightforward, and there are plenty of online resources to get you started. &lt;/p&gt;

&lt;p&gt;For example, take a look at this &lt;a href="https://www.markdownguide.org/cheat-sheet/"&gt;Markdown cheat sheet&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start Using JekyllPad
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.JekyllPad.com"&gt;JekyllPad.com&lt;/a&gt; is an &lt;a href="https://www.JekyllPad.com"&gt;online Jekyll WYSIWYG editor and CMS&lt;/a&gt; for Jekyll blogs hosted on Github Pages. &lt;/p&gt;

&lt;p&gt;It takes the burden of dealing with Markdown directly of your shoulders and gives you tools to write, manage, tag and share your posts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Writing Your First Post
&lt;/h3&gt;

&lt;p&gt;Creating your first post in JekyllPad is easy and exciting.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Log into &lt;a href="https://www.JekyllPad.com"&gt;JekyllPad&lt;/a&gt; with you Github account&lt;/li&gt;
&lt;li&gt;Navigate to the Posts menu&lt;/li&gt;
&lt;li&gt;Click on &lt;code&gt;New Post&lt;/code&gt; button. This will open an empty editor for you.

&lt;ul&gt;
&lt;li&gt;File name follows the naming convention YYYY-MM-DD.md. You can modify that to whatever you want.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Start writing your content&lt;/li&gt;
&lt;li&gt;Click on &lt;code&gt;Save&lt;/code&gt;. Your post is now committed directly to Github and published.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Advanced Jekyll Blogging Tips
&lt;/h2&gt;

&lt;h3&gt;
  
  
  SEO Best Practices
&lt;/h3&gt;

&lt;p&gt;Optimizing your Jekyll blog for search engines is crucial. Focus on quality content, use relevant keywords, and ensure your site has a clean, responsive design. &lt;/p&gt;

&lt;p&gt;Utilizing SEO-friendly URLs and meta tags in your Jekyll configuration can also significantly boost your visibility.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enhancing Your Blog with Plugins
&lt;/h3&gt;

&lt;p&gt;Jekyll supports various plugins that can extend functionality, from SEO tools to feed generators. &lt;/p&gt;

&lt;p&gt;Explore Jekyll’s plugins directory to find ones that suit your needs. However, remember that GitHub Pages has some limitations on custom plugins for security reasons.&lt;/p&gt;

&lt;h2&gt;
  
  
  Maintaining and Updating Your Blog
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Regular Updates
&lt;/h3&gt;

&lt;p&gt;Keeping your blog updated with fresh content is key to engaging your audience and improving SEO. &lt;/p&gt;

&lt;p&gt;Establish a consistent posting schedule and stick to it, whether it's weekly, bi-weekly, or monthly. &lt;/p&gt;

&lt;p&gt;Regular updates keep your blog relevant and visitors coming back.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keeping Jekyll and Dependencies Updated
&lt;/h3&gt;

&lt;p&gt;Just like any software, Jekyll and its dependencies need to be kept up-to-date. &lt;/p&gt;

&lt;p&gt;Regular updates ensure security, introduce new features, and improve performance. Check for updates periodically and follow the Jekyll update guide to keep your blogging platform running smoothly.&lt;/p&gt;

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

&lt;p&gt;Starting a blog with Jekyll and GitHub Pages is a journey that combines the simplicity of static site generation with the power of web development. &lt;/p&gt;

&lt;p&gt;It’s a pathway to a more controlled, cost-effective, and enjoyable blogging experience. JekyllPad has been built and released so that it makes this journey even more enjoyable. &lt;/p&gt;

&lt;p&gt;Dive in, explore the possibilities, and start sharing your unique voice with the world.&lt;/p&gt;

</description>
      <category>blog</category>
      <category>github</category>
      <category>jekyll</category>
      <category>markdown</category>
    </item>
    <item>
      <title>Top 5 Playlist AI Tools (2023)</title>
      <dc:creator>Arman @programmerByDay</dc:creator>
      <pubDate>Tue, 12 Sep 2023 11:55:27 +0000</pubDate>
      <link>https://dev.to/programmerbyday/top-5-playlist-ai-tools-2023-dpe</link>
      <guid>https://dev.to/programmerbyday/top-5-playlist-ai-tools-2023-dpe</guid>
      <description>&lt;p&gt;Music is one of the most powerful forms of expression and entertainment. Whether you want to relax, work, study, or party, there is a playlist for every mood and occasion. But how do you find the perfect playlist for your needs? How do you discover new songs and artists that match your taste and preferences? How do you create your own playlists without spending hours browsing through millions of tracks?&lt;/p&gt;

&lt;p&gt;Artificial Intelligence (AI) has revolutionized many aspects of our lives, and music is no exception. Playlist AI tools are the latest innovation in the music industry, offering a personalized and enhanced listening experience. These tools use advanced algorithms to curate playlists based on your preferences, mood, and listening history. They can introduce you to new artists, help you rediscover old favorites, and even create the perfect soundtrack for your day. Here are the top 5 Playlist AI tools in 2023 that are changing the way we listen to music.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. &lt;a href="https://www.taranify.com"&gt;Taranify&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Taranify&lt;/strong&gt; stands out as the most unique tool on this list. It's not only a playlist Ai, but a mood-based recommendation ai.&lt;/p&gt;

&lt;p&gt;This innovative &lt;a href="https://www.taranify.com"&gt;Spotify Playlist AI&lt;/a&gt; discovers the perfect tunes to match your current mood and preferences. It's an experimental tool designed to simplify playlist creation by generating playlists according to your mood. &lt;/p&gt;

&lt;p&gt;If you're looking for a tool that offers a unique approach to playlist creation, Taranify is worth checking out. It can also recommends Netflix shows and Books based on how you are feeling at the moment.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. &lt;a href="https://www.playlistai.app"&gt;PlaylistAI&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;PlaylistAI&lt;/strong&gt; is another impressive tool that uses AI to generate music playlists. &lt;/p&gt;

&lt;p&gt;You can describe what you want to listen to, and PlaylistAI will make you a playlist on Spotify or Apple Music. It also offers unique music discovery experiences like instant playlists for music festivals. &lt;/p&gt;

&lt;p&gt;With its user-friendly interface and advanced features, PlaylistAI is a great choice for both casual listeners and music enthusiasts.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. &lt;a href="https://playlistable.io"&gt;Playlistable&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Playlistable&lt;/strong&gt; is an AI-powered music companion that creates personalized playlists based on your preferences. &lt;/p&gt;

&lt;p&gt;It manages your playlists effortlessly and integrates seamlessly with Spotify. What sets Playlistable apart is its ability to revolutionize your music experience by helping you discover new artists and songs.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. &lt;a href="https://uppbeat.io/ai-playlist-generator"&gt;Uppbeat AI Playlist Generator&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Uppbeat AI Playlist Generator&lt;/strong&gt; uses advanced AI technology to understand any prompt you give it and generates a customized playlist of the most suitable royalty-free music from the Uppbeat music catalog. &lt;/p&gt;

&lt;p&gt;This tool is perfect for content creators looking for copyright-free tracks for their projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. &lt;a href="https://www.playlistgenius.ai"&gt;PlaylistGenius AI&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Last but not least, &lt;strong&gt;PlaylistGenius AI&lt;/strong&gt; simplifies playlist creation by using song suggestions from ChatGPT and Spotify Web API to generate playlists according to your input. It's a handy tool for those who want a more hands-on approach in curating their playlists.&lt;/p&gt;

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

&lt;p&gt;In conclusion, these top 5 Playlist AI tools offer a new way of experiencing music. &lt;/p&gt;

&lt;p&gt;They take into account your personal preferences and use advanced algorithms to curate playlists that cater specifically to your taste. &lt;/p&gt;

&lt;p&gt;So why not give them a try and see how they can enhance your listening experience?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>music</category>
      <category>nextjs</category>
      <category>spotify</category>
    </item>
    <item>
      <title>The Magic of Mood-Based Playlist Ai</title>
      <dc:creator>Arman @programmerByDay</dc:creator>
      <pubDate>Tue, 29 Aug 2023 00:06:22 +0000</pubDate>
      <link>https://dev.to/programmerbyday/the-magic-of-mood-based-playlist-ai-mlf</link>
      <guid>https://dev.to/programmerbyday/the-magic-of-mood-based-playlist-ai-mlf</guid>
      <description>&lt;p&gt;Music is not just a collection of melodies and harmonies. It's a universal language that transcends borders, cultures, and, most importantly, our emotions. We've all experienced that overwhelming surge of nostalgia when a certain song plays or felt instantaneously happy listening to an upbeat track.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bridging Beats and Emotions
&lt;/h2&gt;

&lt;p&gt;Why does a melancholic tune on Spotify make us teary, and an energetic one uplift our spirits? The answer lies deep within our brain's neural pathways. When music enters our ears, it isn't merely processed as sound. Our brains interpret these melodies and harmonies, leading to emotional responses. Essentially, music becomes an emotion-translator.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Dance of Dopamine
&lt;/h2&gt;

&lt;p&gt;When you stumble upon a Spotify playlist that matches your mood perfectly, there's science at play. Listening to music releases dopamine, the feel-good neurotransmitter. The right song can literally bring joy, thanks to this neurochemical magic. So, when Taranify recommends a mood-based playlist, you're in for a dopamine treat!&lt;/p&gt;

&lt;h2&gt;
  
  
  AI: The Modern Maestro
&lt;/h2&gt;

&lt;p&gt;Enter Taranify Playlist AI, the technology making waves in the music world. Gone are the days of manually curating songs. With advanced algorithms, platforms like Taranify can gauge your mood and instantly curate a Spotify playlist tailored just for you. Think of it as having a personal maestro, understanding your feelings and setting them to music.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cultural Canvas
&lt;/h2&gt;

&lt;p&gt;Music and emotions aren't a new affair. Historically, different cultures have used music to express feelings, celebrate, or mourn. From the tribal beats of ancient civilizations to the grand orchestras of the Renaissance, music has always mirrored human emotion. Platforms like Spotify give us a modern twist, offering an endless cultural canvas of tracks to explore.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Power of Personalization
&lt;/h2&gt;

&lt;p&gt;Imagine having a Spotify playlist that understands not just your musical taste, but your heart's state. That's the power of mood-based playlists. By aligning with your emotions, it creates a deeply personal listening experience. Every song becomes a reflection of your inner world, making each note resonate deeper.&lt;/p&gt;

&lt;h2&gt;
  
  
  From Moods to Melodies
&lt;/h2&gt;

&lt;p&gt;As we progress in the world of AI and tech, the bond between our moods and melodies will only strengthen. Services like Taranify are at the forefront, pioneering a movement where music is more than just sound—it's a mirror to our souls. A world where every emotion has its own soundtrack is not far away.&lt;/p&gt;

&lt;h2&gt;
  
  
  To Conclude: An Emotional Encore
&lt;/h2&gt;

&lt;p&gt;Music is an ever-evolving journey, and with the advent of technologies like &lt;a href="https://www.taranify.com"&gt;Taranify Mood AI&lt;/a&gt;, we're entering an era of emotional encore. So, next time you dive into a Spotify playlist, remember, it's not just tunes you're listening to but a reflection of your very emotions.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>music</category>
      <category>api</category>
      <category>news</category>
    </item>
    <item>
      <title>Vertical Scaling vs. Horizontal Scaling: Explained Simply</title>
      <dc:creator>Arman @programmerByDay</dc:creator>
      <pubDate>Mon, 31 Jul 2023 04:40:59 +0000</pubDate>
      <link>https://dev.to/programmerbyday/vertical-scaling-vs-horizontal-scaling-explained-simply-4nh8</link>
      <guid>https://dev.to/programmerbyday/vertical-scaling-vs-horizontal-scaling-explained-simply-4nh8</guid>
      <description>&lt;p&gt;Scalability is one of the aspects to make any system future-proof. In this blog post, I will share my learnings about what the scaling is in software deployment, the difference between vertical scaling and horizontal scaling, and when to use each one.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is scaling?
&lt;/h2&gt;

&lt;p&gt;An app or an API is useless unless it is deployed to a publicly available server. As you know, servers are computers with specifically designed hardware. These hardwares (CPU, Memory, Storage, processing units, GPUs, etc.) are designed to be switched on all the time, and endure under severe workloads and be durable. However, they have one drawback. They are not limitless. They can only process so much work, and when the workload is increased, they won’t be able to process in a timely manner. This is when scaling comes into the play.&lt;/p&gt;

&lt;p&gt;Scaling means increasing the capacity of a server with the goal of being able to process more requests/workloads. There are two ways of doing it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vertical Scaling
&lt;/h2&gt;

&lt;p&gt;Vertical Scaling is when we swap a server’s hardwares with another hardware with higher capacity. For example, we swap the Memory or the storage to a bigger one. Or change the CPU with another one with more cores. When we change the server, in a way that it becomes bigger with more resources and capacity, this is called Vertical Scaling.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftjxxcqpw72qk4j4nxoyw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftjxxcqpw72qk4j4nxoyw.png" alt="Vertical Scaling" width="761" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In today’s world, most of the servers are created using Virtual Machines. Virtual machines are configurables and therefore each parts of them (such as CPU or memory or storage) can be increased or decreased via a configuration setting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Horizontal Scaling
&lt;/h2&gt;

&lt;p&gt;It is not always possible to add a bigger resource to a server. However, sometimes we might be able to increase the number of servers. When we increase the number of servers, in a way that they collectively process more requests, this is called Horizontal Scaling.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvii5zoirws8qgletho0e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvii5zoirws8qgletho0e.png" alt="Horizontal Scaling" width="686" height="245"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As I said, most servers are deployed as Virtual Machines, and duplicating a virtual machine is a simple task these days. However, with more servers, comes more complexity. Requests need to be distributed among multiple servers. This is usually done by a load-balancer server that sits in front of all the servers to do this distribution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vertical Scaling vs. Horizontal Scaling
&lt;/h2&gt;

&lt;p&gt;The are differences in terms of implementation, technicality, costs and etc. I’ve captured it in a simple table below:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Vertical Scaling&lt;/th&gt;
&lt;th&gt;Horizontal Scaling&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;How it works&lt;/td&gt;
&lt;td&gt;Increases the capacity of a single server&lt;/td&gt;
&lt;td&gt;Increases the number of servers usually each with the same capacity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pros&lt;/td&gt;
&lt;td&gt;Easier to implement&lt;/td&gt;
&lt;td&gt;Infinite scalability / Can scale down easily when the load is less / More cost effective&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cons&lt;/td&gt;
&lt;td&gt;Scalability is limited to available hardwares in the market / Can be more costly in the long run / It takes time to spin up a new server with higher capacity and switch it with the current one / Can cause disruption to the users&lt;/td&gt;
&lt;td&gt;-- More complex to implement (needs a load-balancer) / It Is not suitable with legacy system (e.g. &lt;a href="https://stackoverflow.com/questions/10494431/sticky-and-non-sticky-sessions"&gt;sticky sessions issue&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best use case&lt;/td&gt;
&lt;td&gt;When workload has increased and it is predicted to stay that high from now on OR for a long time&lt;/td&gt;
&lt;td&gt;When the workload can increase/decrease at any time&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;p&gt;Vertical Scaling is when we increase the resources/hardwares in a single server, whereas Horizontal Scaling is when we increase the number of servers. Each has its own merits and pitfalls. I'd recommend to lean towards horizontal scaling for green field projects. Even if you are working on a legacy system, try to change it in a way that it is more deployable with horizontal scaling.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyumqw7i85fjwkflz5pqy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyumqw7i85fjwkflz5pqy.png" alt="Horizontal Scaling vs Vertical Scaling" width="800" height="629"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>webdev</category>
      <category>api</category>
      <category>learning</category>
    </item>
    <item>
      <title>How to Run dotnet apps Like npm run on Every Platform</title>
      <dc:creator>Arman @programmerByDay</dc:creator>
      <pubDate>Tue, 29 Nov 2022 07:00:00 +0000</pubDate>
      <link>https://dev.to/programmerbyday/how-to-run-dotnet-apps-like-npm-run-on-every-platform-354g</link>
      <guid>https://dev.to/programmerbyday/how-to-run-dotnet-apps-like-npm-run-on-every-platform-354g</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Instead of publishing your dotnet application for each platform separately, there is a way to publish your app once as platform agnostic and run it on every platform easily.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We all know, dotnet applications can be run on any platform. Be it a windows machine, macOS (both x64 and arm64 architectures) and linux, dotnet can run our application. Although I will explain how to publish an executable of your application for any platform, there is a way to publish your app platform agnostic. A platform agnostic is when you publish your application once and you can run it on every platform. This is similar to the same approach &lt;em&gt;npm&lt;/em&gt; has been doing since the beginning.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to publish a dotnet application for different platforms?
&lt;/h2&gt;

&lt;p&gt;dotnet cli has a nice parameter for that:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dotnet publish -r &amp;lt;runtime-ID&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;em&gt;runtime-ID&lt;/em&gt; tells dotnet which platform this application is going to run on. Common IDs are win-x64 , osx-x64 , osx-arm64 and linux-x64. To see the full list of all runtime IDs you can publish to, &lt;a href="https://learn.microsoft.com/en-us/dotnet/core/rid-catalog#using-rids"&gt;check here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A few examples I usually use, are:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dotnet publish -r win-x64 -p:Configuration=Release -p:DebugType=None -p:DebugSymbols=false -p:Version=1.0.1&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;



&lt;p&gt;&lt;code&gt;dotnet publish -r osx-x64 -p:Configuration=Release -p:DebugType=None -p:DebugSymbols=false -p:Version=1.1.25&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  How to publish platform-agnostic?
&lt;/h2&gt;

&lt;p&gt;That's a good question. There is a simple way to do that, but there is an issue with that. So, you can publish the app in platform agnostic way, by not mentioning &lt;em&gt;-r&lt;/em&gt; option in &lt;em&gt;dotnet publish&lt;/em&gt;. Here is an example:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dotnet publish -p:Configuration=Release -p:DebugType=None -p:DebugSymbols=false -p:Version=1.0.1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;When you don't mention a specific runtime platform, &lt;em&gt;dotnet publish&lt;/em&gt; generates an executable for the current platform you are on as well as the dll file for the app. Even if it is a console application, it still generates a dll for it. The executable file is platform-dependant but the dll file is not. But as you know, you cannot run a dll file directly by clicking on it. So how do end users get to run the application by using its dll file? here is how:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dotnet &amp;lt;dll filename&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dotnet ConsoleApp1.dll&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is a very similar pattern to how npm applications and packages are run via &lt;em&gt;npm run &lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How and What to Release to end users?
&lt;/h2&gt;

&lt;p&gt;What I like to do is that I publish my app in runtime-agnostic way, then I remove any executable it might have generated and keep only dll files. Then I can easily zip this folder and ship it to end users or other developers. I tend to put a small &lt;em&gt;README.md&lt;/em&gt; file to explain how they should run it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What would make it better?
&lt;/h2&gt;

&lt;p&gt;As you've seen, when we publish our .NET application in runtime agnostic manner, it generates a dll file. In order to run it we have to give the whole filename and its extensions to the dotnet CLI. This is a little bit bothersome, as a .dll file is not usually an executable file and this can confuse users or developers. I wish there was a way to remove this extension completely and just use the filename.&lt;/p&gt;

&lt;p&gt;I haven't been able to find any solution for that, if you know, please share it with us in the comment section.&lt;/p&gt;

</description>
      <category>npm</category>
      <category>dotnet</category>
      <category>programming</category>
      <category>csharp</category>
    </item>
    <item>
      <title>What is GraphQL? How to Use it in ASP.NET Core WebApi? Let Me Explain Simply…</title>
      <dc:creator>Arman @programmerByDay</dc:creator>
      <pubDate>Thu, 06 May 2021 08:50:38 +0000</pubDate>
      <link>https://dev.to/programmerbyday/what-is-graphql-how-to-use-it-in-asp-net-core-webapi-let-me-explain-simply-2hhm</link>
      <guid>https://dev.to/programmerbyday/what-is-graphql-how-to-use-it-in-asp-net-core-webapi-let-me-explain-simply-2hhm</guid>
      <description>&lt;p&gt;From ASP.NET Web Forms to ASP.NET AJAX, then ASP.NET MVC and ASP.NET Web API, building an API has evolved massively. An API started from being a function you can run on another computer, evolved massively to accommodate what today's applications need.&lt;/p&gt;

&lt;p&gt;Throughout the projects I have been involved in, I have always worked with REST APIs. REST API architecture is simple and clean, it's easy to pick up for new developers and it is less mistake-prone since each and every API is going to have the same structure.&lt;/p&gt;

&lt;p&gt;In a typical REST API, you would have a separate endpoint for each object type. That endpoint, based on your implementation, would provide GET, POST, PUT, PATCH, DELETE actions. In addition to that, they could get some query parameters, to filter the data (for example based on an ID or date, etc.). But when you would get the result, you would get the whole object. And that can be a bigger headache when you are using Domain-Driven Design architecture and dealing with millions/billions of aggregate objects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Entering GraphQL...
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;GraphQL is a query language for APIs. GraphQL gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://graphql.org/" rel="noopener noreferrer"&gt;graphql.org&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In 2012, Facebook built GraphQL to address the above issue. GraphQL, typically has one endpoint. And, that endpoint accepts a query. So far, it is not that fascinating, but the actual beauty is in the "query" I just mentioned. In the query, you mention what type (or types) you want, what property values you'd want to use as filter, and lastly, what properties of those types you'd like to get back.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does GraphQL work?
&lt;/h2&gt;

&lt;p&gt;As you guessed, you can request for one or more types, you can search/filter based on any property and you can only get the properties you are interested in. The query is in JSON format and you'd get the result back in JSON format. This can save you multiple roundtrips to the server and decrease your server load as well as network traffic and latency.&lt;/p&gt;

&lt;p&gt;I know you are excited to see an example of a query .. so let me show you:&lt;/p&gt;

&lt;h4&gt;
  
  
  Query
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="nx"&gt;PersonAndFriends&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;person &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2001&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;name&lt;/span&gt;
      &lt;span class="nx"&gt;friends&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="nx"&gt;name&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Result
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;person&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rose DeWitt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;friends&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
       &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Jack Dawson&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
       &lt;span class="p"&gt;},&lt;/span&gt;
       &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cal Hockley&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
       &lt;span class="p"&gt;},&lt;/span&gt;
       &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Ruth DeWitt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Above, I defined a query with the name "PersonAndFriends", I'm asking for a &lt;em&gt;person&lt;/em&gt; with ID=2001, and I am interested to get back its &lt;em&gt;name&lt;/em&gt; and &lt;em&gt;friends&lt;/em&gt; fields. Within &lt;em&gt;friends&lt;/em&gt; (which can be an array), I'm only asking to get back &lt;em&gt;name&lt;/em&gt; field. On top of that, the shape of a GraphQL query closely matches the result of it. It's cool, isn't it?&lt;/p&gt;

&lt;p&gt;There are 3 types of query. "&lt;em&gt;query&lt;/em&gt;" itself, "&lt;em&gt;mutation&lt;/em&gt;" and "&lt;em&gt;subscription&lt;/em&gt;". &lt;em&gt;query&lt;/em&gt; is your way to request for data, &lt;em&gt;mutate&lt;/em&gt; is the way to change the data (such as create a new record, update it, delete it).&lt;/p&gt;

&lt;p&gt;Queries accept variables so that you don't need to manipulate string to put your arguments dynamically.&lt;/p&gt;

&lt;h4&gt;
  
  
  Query with variables
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="nc"&gt;PersonQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2001&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
"id": 2001
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Result
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;person&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rose DeWitt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Internally, The query and each field of types is backed by a separate function called &lt;em&gt;resolver&lt;/em&gt; which is provided by the developer to GraphQL. Execution of a query starts by calling the resolver function of the query with passed-in arguments. If the function returns an object, GraphQL will execute its resolver passing in the object. For each selected field, GraphQL calls their resolver functions to get their values. This process continues until all resolvers return Scalar types and not objects. It is as if GraphQL traverses a graph from its root until it covers all the leaves, hence the name &lt;em&gt;Graph Query Language&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use GraphQL?
&lt;/h2&gt;

&lt;p&gt;In order to use GraphQL, two things should be provided to build a GraphQL server. Firstly, object types, what data can be queried, and how it can be queried. Defining types and schemas, help GraphQL to validate queries and execute them. Secondly, resolver functions for each type and its fields.&lt;/p&gt;

&lt;h3&gt;
  
  
  Defining types
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Query&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;episode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Episode&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Cast&lt;/span&gt;
  &lt;span class="nf"&gt;car&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Vehicle&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Cast&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
  &lt;span class="nx"&gt;episode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Episode&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
  &lt;span class="nf"&gt;height&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LengthUnit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;METER&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Float&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;Episode&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;PILOT&lt;/span&gt;
  &lt;span class="nx"&gt;ONE&lt;/span&gt;
  &lt;span class="nx"&gt;FINALE&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"!" comes after the field type and shows that field is non-nullable and when you query that field, it will always have a value. [ and ] represent an array. Fields can have arguments, and arguments can have default values(e.g. &lt;em&gt;height&lt;/em&gt; field). Built-In scalar types can be Int (32-bit integer), Float, String, Boolean and ID (which is non-human-readable and unique string).&lt;/p&gt;

&lt;p&gt;The query structure is actually another type named "Query". It defines, what fields can be queried, and what arguments each field can take. Also, it defined what fields and arguments are &lt;em&gt;non-nullable&lt;/em&gt;. Mutation is also defined in the same way.&lt;/p&gt;

&lt;p&gt;GraphQL allows you to define &lt;em&gt;input object types&lt;/em&gt; which are objects that you can pass as an argument to a query or mutation. Input types need to be defined separately with &lt;em&gt;input&lt;/em&gt; keyword. Input types can have relationship with other input types but cannot refer object types or have arguments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;FoodReviewInput&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;stars&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
  &lt;span class="nx"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Defining resolver functions
&lt;/h3&gt;

&lt;p&gt;It's quite straight-forward, you start with a function to resolve the query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getActorByID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Actor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each function has four arguments, &lt;em&gt;obj&lt;/em&gt; is the object resulted from running the previous function, &lt;em&gt;args&lt;/em&gt; is field or query arguments, &lt;em&gt;context&lt;/em&gt; is a contextual object containing information like the logged-in user and etcetera, &lt;em&gt;info&lt;/em&gt; contains information about the query and its types.&lt;/p&gt;

&lt;p&gt;Just like that, you define the rest of the functions for types and fields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Actor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;Vehicle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vehicleIDs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getVehicleByID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Vehicle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  But That seems to be a lot of work!
&lt;/h2&gt;

&lt;p&gt;Yes, but the good news is, there are many libraries available that would take the complexity away from you. They take care of object definition, authorization, security, pagination, caching, etc. GraphQL website provides you with a list of libraries and tools you can use in your preferred programming language &lt;a href="https://graphql.org/code/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use GraphQL in .NET Core?
&lt;/h2&gt;

&lt;p&gt;I found &lt;a href="https://github.com/ChilliCream/hotchocolate" rel="noopener noreferrer"&gt;hotchocolate library&lt;/a&gt; which does most of the work and creates a neat GraphQL server in no time. I found its tutorial quite succinct and to-the-point, you can find it &lt;a href="https://chillicream.com/docs/hotchocolate/get-started/" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Architect discussion: When to use GraphQL?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprogrammerbyday.files.wordpress.com%2F2021%2F04%2Farchitect.png%3Fw%3D300" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprogrammerbyday.files.wordpress.com%2F2021%2F04%2Farchitect.png%3Fw%3D300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Like any other technology, GraphQL has its own pros and cons. When you want to make an architectural decision, you need to be aware of these pros and cons and make sure that this technology can do what you want to achieve. I found these points about GraphQL versus REST Api:&lt;/p&gt;

&lt;h3&gt;
  
  
  What you get:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Ask for what you need: As you know by now, in GraphQL you mention the fields you want to be returned to you, and that is one of the main benefits of using GraphQL. Especially if you are dealing with large aggregate objects and you need to transfer data over public internet (which incurs cost), This is very beneficial. Although REST API doesn't have this feature by itself, it is technically possible to use &lt;a href="https://www.odata.org/" rel="noopener noreferrer"&gt;OData&lt;/a&gt; to query REST API. However, in my opinion, GraphQL is more like a standard for this and it's better to rely on a standard than a combination of technologies.&lt;/li&gt;
&lt;li&gt;  Solves n+1 problem: Imagine a situation where you get a root object (like a Person) and then loop through its Friends collection and send another request to fetch each Friend object separately. GraphQL solves this problem, since you can mention whatever you want in your query.&lt;/li&gt;
&lt;li&gt;  Combined Query: Combined queries are when you request for separate not-related objects in the same query. For example, you can write a query that returns persons and books. Normally you would have to make two separate API calls, but with GraphQL you can do it in one query.&lt;/li&gt;
&lt;li&gt;  API Versioning: GraphQL query and its result is in JSON format. Therefore, if there is any changes in the schema, JSON inherently handles that for you. And every subsequent systems that use your GraphQL endpoint, since they use JSON, it's safe for them as well. Obviously, if you delete/rename a field, that's still a breaking change.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What to watch out:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Caching: REST API is heavily based on how HTTP works, and HTTP has a nice caching mechanism. However, GraphQL needs a bit of more work to implement its own caching.&lt;/li&gt;
&lt;li&gt;  Harder with &lt;a href="https://microservices.io/patterns/microservices.html" rel="noopener noreferrer"&gt;Microservice Architecture&lt;/a&gt;: When you have separate micro-services for different aggregates, in REST API, you can call separate URLs and get both objects. But in GraphQL, since you only deal with one endpoint, GraphQL needs to call those endpoints separately behind-the-scene, aggregate the data and send it back to you. Which can be not-ideal in some solutions.&lt;/li&gt;
&lt;li&gt;  Combined Query: Combined query is one of the great features, however, if you are not careful, it can expose some data to the users that should not have access to that part of the data.&lt;/li&gt;
&lt;li&gt;  Monitoring: Since REST API is based on HTTP protocol, there are many layers of monitoring already built around that. You can monitor and log your REST API calls inside and out. However, the monitoring tools for GraphQL is still thin and you need to consider what's available if monitoring and logging is a requirement for your solution.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to learn more...
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://graphql.org/learn" rel="noopener noreferrer"&gt;https://graphql.org/learn&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://graphql.org/code" rel="noopener noreferrer"&gt;https://graphql.org/code&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://chillicream.com/docs/hotchocolate/get-started/" rel="noopener noreferrer"&gt;https://chillicream.com/docs/hotchocolate/get-started/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Volia! Thanks for reading.&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>dotnet</category>
      <category>api</category>
    </item>
    <item>
      <title>How to Secure Your ASP.NET Core WebApi with Azure AD and OAuth 2.0</title>
      <dc:creator>Arman @programmerByDay</dc:creator>
      <pubDate>Tue, 20 Apr 2021 12:54:15 +0000</pubDate>
      <link>https://dev.to/programmerbyday/how-to-secure-your-asp-net-core-webapi-with-azure-ad-and-oauth-2-0-545e</link>
      <guid>https://dev.to/programmerbyday/how-to-secure-your-asp-net-core-webapi-with-azure-ad-and-oauth-2-0-545e</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Azure AD is a common way of access control these days. OAuth is a well-known protocol that is used and expected from APIs. I found it tricky to integrate my APIs with Azure AD. So I decided to explain it all in very simple terms in this post.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Twenty years ago, when Active Directory was part of &lt;a href="https://en.wikipedia.org/wiki/Windows_NT"&gt;Windows NT&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Windows_2000"&gt;Windows 2000 Server&lt;/a&gt;, I was no big fan of it. Nowadays, Active Directory (AD) is a core service offered in Microsoft Azure and it really is a comprehensive access management service. It offers various ways of Authentication, Single Sign-on (SSO), Business to Business authentication (B2B), Business to Customer/Guest Authentication (B2C), Application/API management, Device management and etc. On top of that, it provides conditional access rules and Multi-factor Authentication (MFA).&lt;/p&gt;

&lt;p&gt;One of the common industry authentication standards these days is OAuth. OAuth is an open protocol for simple and secure authorization of web, mobile and desktop applications. It's widely used and expected and if any API doesn't have that, I'd say that's a big negative point. As I always say, best practices and standards help us to know how that part of the system works generally and how it's going to behave in different edge cases. No one has the time to study and learn how your API authentication mechanism works and how it's going to behave in different situations.&lt;/p&gt;

&lt;p&gt;OAuth offers different authentication paths (which are called as Grant Types). Each Grant Type is designed for a specific situation. For example, client credential grant type is for when an application (such as an API or a mobile App) wants to authenticate itself to another system. If you want to read more about OAuth, I'd suggest to look &lt;a href="https://oauth.net/2/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to accept authenticated requests in your API?
&lt;/h2&gt;

&lt;p&gt;Microsoft recommends using &lt;a href="https://www.nuget.org/packages/Microsoft.Identity.Web"&gt;Microsoft.Identity.Web&lt;/a&gt; library, and it's a great library. It's super easy to secure controllers with this library and only let in signed-in requests.&lt;/p&gt;

&lt;p&gt;In Startup.cs or where you have ConfigureServices method, add this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt; &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Identity.Web&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

 &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;  &lt;span class="nf"&gt;ConfigureServices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IServiceCollection&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
 &lt;span class="p"&gt;{&lt;/span&gt; 

 &lt;span class="c1"&gt;// Adds Microsoft Identity platform (AAD v2.0) support to protect this Api &lt;/span&gt;
 &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddMicrosoftIdentityWebApiAuthentication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

 &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddControllers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And, in Configure method, add these middlewares to app-builder instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAuthentication&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
 &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAuthorization&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And, finally, in your controllers, you can easily use Authorize custom attribute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Authorize&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
 &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TodoListController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Controller&lt;/span&gt; 
 &lt;span class="p"&gt;{&lt;/span&gt; 
 &lt;span class="c1"&gt;/// controller actions &lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to make an authenticated request to an API?
&lt;/h2&gt;

&lt;p&gt;Again, we are using &lt;a href="https://www.nuget.org/packages/Microsoft.Identity.Web"&gt;Microsoft.Identity.Web&lt;/a&gt; library. By default, the configuration of this library should be in a*ppsettings.json*:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt; 
&lt;span class="s"&gt;"AzureAd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt; 
 &lt;span class="s"&gt;"Instance"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"https://login.microsoftonline.com/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
 &lt;span class="s"&gt;"Domain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"[Enter the domain of your tenant, e.g. contoso.onmicrosoft.com]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
 &lt;span class="s"&gt;"TenantId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"[Enter 'common', or 'organizations' or the Tenant Id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
 &lt;span class="s"&gt;"ClientId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"[Enter the Client Id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
 &lt;span class="s"&gt;"ClientSecret"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"[Copy the client secret added to the app from the Azure portal]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 

 &lt;span class="c1"&gt;// If using other OAuth authentication paths &lt;/span&gt;
 &lt;span class="s"&gt;"CallbackPath"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"/signin-oidc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
 &lt;span class="s"&gt;"SignedOutCallbackPath"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"/signout-callback-oidc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 

 &lt;span class="c1"&gt;// If instead of client_id and client_secret, the Api requires a certificate &lt;/span&gt;
 &lt;span class="s"&gt;"ClientCertificates"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"[or Enter the certificate details]"&lt;/span&gt;

 &lt;span class="p"&gt;}&lt;/span&gt; 
 &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, in order to obtain an access token, simply inject &lt;em&gt;ITokenAcquisition&lt;/em&gt; in the constructor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt; &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Identity.Web&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

 &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ITokenAcquisition&lt;/span&gt; &lt;span class="n"&gt;_tokenAcquisition&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

 &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;TodoListService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ITokenAcquisition&lt;/span&gt; &lt;span class="n"&gt;tokenAcquisition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
 &lt;span class="p"&gt;{&lt;/span&gt; 
 &lt;span class="n"&gt;_tokenAcquisition&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tokenAcquisition&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
 &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And, for client credentials flow, simply do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;accessToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_tokenAcquisition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAccessTokenForAppAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;Put your scope here&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Voila! You have the accessToken. You can assign it now to &lt;em&gt;Authorization&lt;/em&gt; header of your HttpClient and make the call.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>azure</category>
      <category>security</category>
    </item>
  </channel>
</rss>
