<?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: Kingsley Amankwah</title>
    <description>The latest articles on DEV Community by Kingsley Amankwah (@kingsley).</description>
    <link>https://dev.to/kingsley</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%2F999371%2Fe3aa02c7-caef-4da9-b0f2-afac221f480c.jpg</url>
      <title>DEV Community: Kingsley Amankwah</title>
      <link>https://dev.to/kingsley</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kingsley"/>
    <language>en</language>
    <item>
      <title>Building Secure Authentication in Angular with Supabase</title>
      <dc:creator>Kingsley Amankwah</dc:creator>
      <pubDate>Fri, 06 Jun 2025 08:59:50 +0000</pubDate>
      <link>https://dev.to/kingsley/building-secure-authentication-in-angular-with-supabase-2e1p</link>
      <guid>https://dev.to/kingsley/building-secure-authentication-in-angular-with-supabase-2e1p</guid>
      <description>&lt;p&gt;&lt;strong&gt;Hey Angular developers! 🅰️&lt;/strong&gt; It's about that time again for yet another article. In this guide, we're going to dive into how to integrate &lt;a href="https://supabase.com/" rel="noopener noreferrer"&gt;Supabase&lt;/a&gt;, with Angular to build a secure authentication application. We’ll set up signup, and login authentication with Supabase in Angular and protect routes of some pages. Let’s get started&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before we dive in, make sure you've got:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An Angular project&lt;/li&gt;
&lt;li&gt;Node.js v16+ installed&lt;/li&gt;
&lt;li&gt;A Supabase account at &lt;a href="https://supabase.com/" rel="noopener noreferrer"&gt;Supabase Website&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Set Up a Supabase Project
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Create a New Project:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Log in to Supabase and click New Project.&lt;/li&gt;
&lt;/ul&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%2Fogtm299o4qas51hyo70t.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%2Fogtm299o4qas51hyo70t.png" alt="Supabase Create New Project Image" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enter a project name, and database password, and choose a region.&lt;/li&gt;
&lt;/ul&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%2Fu3378dorrxdu3sh6kw7h.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%2Fu3378dorrxdu3sh6kw7h.png" alt="Supabase New Project Form Image" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wait a few minutes for the project to provision.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Retrieve API Credentials:&lt;/strong&gt;&lt;br&gt;
On the project overview section, Copy the &lt;em&gt;Project URL&lt;/em&gt; and &lt;em&gt;anon public&lt;/em&gt; (API Key).&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%2Fho4tds7n0g97me5o7p6j.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%2Fho4tds7n0g97me5o7p6j.png" alt="Supabase Project Overview Image" width="800" height="312"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 2: Create an Angular Project
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Generate a New Angular App:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng new supabase-auth-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Choose your preferred styling when prompted.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install Dependencies: Install the Supabase JavaScript client:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @supabase/supabase-js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 3: Configure Supabase in Angular
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Set Up Environment Variables: Store the Supabase credentials securely in Angular’s environment files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open &lt;strong&gt;src/environments/environment.ts&lt;/strong&gt; and add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;const environment &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  production: &lt;span class="nb"&gt;false&lt;/span&gt;,
  supabaseUrl: &lt;span class="s1"&gt;'SUPABASE_URL'&lt;/span&gt;,
  supabaseKey: &lt;span class="s1"&gt;'SUPABASE_ANON_KEY'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;strong&gt;SUPABASE_URL&lt;/strong&gt; and &lt;strong&gt;SUPABASE_ANON_KEY&lt;/strong&gt; with values from the Supabase dashboard.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create Type Definitions: In &lt;strong&gt;src/app/types/user.type.ts&lt;/strong&gt;, define types for user data and payloads:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export type &lt;/span&gt;User &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;id&lt;/span&gt;: string&lt;span class="p"&gt;;&lt;/span&gt;
  email?: string&lt;span class="p"&gt;;&lt;/span&gt;
  phone?: string&lt;span class="p"&gt;;&lt;/span&gt;
  user_metadata: &lt;span class="o"&gt;{&lt;/span&gt;
    displayName?: string&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nb"&gt;export type &lt;/span&gt;SignupPayload &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  name: string&lt;span class="p"&gt;;&lt;/span&gt;
  email: string&lt;span class="p"&gt;;&lt;/span&gt;
  password: string&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nb"&gt;export type &lt;/span&gt;LoginPayload &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  email: string&lt;span class="p"&gt;;&lt;/span&gt;
  password: string&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create a Supabase Service: Generate a service to manage Supabase interactions:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng generate service services/supabase
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update &lt;strong&gt;src/app/services/supabase.service.ts&lt;/strong&gt; to initialize the Supabase client and handle authentication:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;import &lt;span class="o"&gt;{&lt;/span&gt; Injectable &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'@angular/core'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="o"&gt;{&lt;/span&gt; createClient, SupabaseClient &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'@supabase/supabase-js'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="o"&gt;{&lt;/span&gt; environment &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'../../environments/environment'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="o"&gt;{&lt;/span&gt; LoginPayload, SignupPayload &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'../types/user.type'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

@Injectable&lt;span class="o"&gt;({&lt;/span&gt;
  providedIn: &lt;span class="s1"&gt;'root'&lt;/span&gt;,
&lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;class SupabaseService &lt;span class="o"&gt;{&lt;/span&gt;
  private &lt;span class="nb"&gt;readonly &lt;/span&gt;supabase: SupabaseClient&lt;span class="p"&gt;;&lt;/span&gt;
  constructor&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    this.supabase &lt;span class="o"&gt;=&lt;/span&gt; createClient&lt;span class="o"&gt;(&lt;/span&gt;
      environment.supabaseUrl,
      environment.supabaseKey
    &lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  async signInWithEmail&lt;span class="o"&gt;(&lt;/span&gt;payload: LoginPayload&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;await this.supabase.auth.signInWithPassword&lt;span class="o"&gt;({&lt;/span&gt;
      email: payload.email,
      password: payload.password,
    &lt;span class="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  async signUpWithEmail&lt;span class="o"&gt;(&lt;/span&gt;payload: SignupPayload&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;await this.supabase.auth.signUp&lt;span class="o"&gt;({&lt;/span&gt;
      email: payload.email,
      password: payload.password,
      options: &lt;span class="o"&gt;{&lt;/span&gt;
        data: &lt;span class="o"&gt;{&lt;/span&gt;
          displayName: payload.name,
        &lt;span class="o"&gt;}&lt;/span&gt;,
      &lt;span class="o"&gt;}&lt;/span&gt;,
    &lt;span class="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  async getUser&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;await this.supabase.auth.getUser&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  async signOut&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;await this.supabase.auth.signOut&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="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The SupabaseService centralizes authentication logic, making it reusable across components. It handles initialization, user state, and auth methods, ensuring clean and maintainable code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Set Up Authentication Components
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;We’ll create components for login, signup, and profile pages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Generate Components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng generate component auth/login
ng generate component auth/signup 
ng generate component profile 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Login Component: Update &lt;strong&gt;src/app/auth/login/login.component.ts&lt;/strong&gt; to handle email/password login:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;import &lt;span class="o"&gt;{&lt;/span&gt; Component, inject, signal &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'@angular/core'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="o"&gt;{&lt;/span&gt; SupabaseService &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'../../services/supabase.service'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="o"&gt;{&lt;/span&gt; Router &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'@angular/router'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="o"&gt;{&lt;/span&gt; FormsModule &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'@angular/forms'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

@Component&lt;span class="o"&gt;({&lt;/span&gt;
  selector: &lt;span class="s1"&gt;'app-login'&lt;/span&gt;,
  imports: &lt;span class="o"&gt;[&lt;/span&gt;FormsModule],
  templateUrl: &lt;span class="s1"&gt;'./login.component.html'&lt;/span&gt;,
  styleUrl: &lt;span class="s1"&gt;'./login.component.css'&lt;/span&gt;,
&lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;class LoginComponent &lt;span class="o"&gt;{&lt;/span&gt;
  email &lt;span class="o"&gt;=&lt;/span&gt; signal&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  password &lt;span class="o"&gt;=&lt;/span&gt; signal&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  private &lt;span class="nb"&gt;readonly &lt;/span&gt;supabaseService &lt;span class="o"&gt;=&lt;/span&gt; inject&lt;span class="o"&gt;(&lt;/span&gt;SupabaseService&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  private &lt;span class="nb"&gt;readonly &lt;/span&gt;router &lt;span class="o"&gt;=&lt;/span&gt; inject&lt;span class="o"&gt;(&lt;/span&gt;Router&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  async signInWithEmail&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    const &lt;span class="o"&gt;{&lt;/span&gt; error &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; await this.supabaseService.signInWithEmail&lt;span class="o"&gt;({&lt;/span&gt;
      email: this.email&lt;span class="o"&gt;()&lt;/span&gt;,
      password: this.password&lt;span class="o"&gt;()&lt;/span&gt;,
    &lt;span class="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;error&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      alert&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Error signing in: '&lt;/span&gt; + error.message&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="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      this.router.navigate&lt;span class="o"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'/profile'&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="o"&gt;}&lt;/span&gt;

  navigateToSignup&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    this.router.navigate&lt;span class="o"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'/signup'&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="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Update &lt;strong&gt;src/app/auth/login/login.component.html&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"container"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &amp;lt;h2&amp;gt;Login&amp;lt;/h2&amp;gt;
  &amp;lt;form&amp;gt;
    &amp;lt;input
      &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"email"&lt;/span&gt;
      &lt;span class="o"&gt;[(&lt;/span&gt;ngModel&lt;span class="o"&gt;)]=&lt;/span&gt;&lt;span class="s2"&gt;"email"&lt;/span&gt;
      &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"email"&lt;/span&gt;
      &lt;span class="nv"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Email"&lt;/span&gt;
      required
    /&amp;gt;
    &amp;lt;input
      &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"password"&lt;/span&gt;
      &lt;span class="o"&gt;[(&lt;/span&gt;ngModel&lt;span class="o"&gt;)]=&lt;/span&gt;&lt;span class="s2"&gt;"password"&lt;/span&gt;
      &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"password"&lt;/span&gt;
      &lt;span class="nv"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Password"&lt;/span&gt;
      required
    /&amp;gt;
    &amp;lt;button &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"button"&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;click&lt;span class="o"&gt;)=&lt;/span&gt;&lt;span class="s2"&gt;"signInWithEmail()"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;Sign In&amp;lt;/button&amp;gt;
  &amp;lt;/form&amp;gt;
  &amp;lt;p&amp;gt;Don&lt;span class="s1"&gt;'t have an account? &amp;lt;a (click)="navigateToSignup()"&amp;gt;Sign Up&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Add styling(optional), in &lt;strong&gt;src/app/auth/login/login.component.css&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;.container &lt;span class="o"&gt;{&lt;/span&gt;
  max-width: 400px&lt;span class="p"&gt;;&lt;/span&gt;
  margin: 50px auto&lt;span class="p"&gt;;&lt;/span&gt;
  padding: 20px&lt;span class="p"&gt;;&lt;/span&gt;
  border: 1px solid &lt;span class="c"&gt;#ccc;&lt;/span&gt;
  border-radius: 5px&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
input, button &lt;span class="o"&gt;{&lt;/span&gt;
  display: block&lt;span class="p"&gt;;&lt;/span&gt;
  width: 100%&lt;span class="p"&gt;;&lt;/span&gt;
  margin: 10px 0&lt;span class="p"&gt;;&lt;/span&gt;
  padding: 10px&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
button &lt;span class="o"&gt;{&lt;/span&gt;
  background-color: &lt;span class="c"&gt;#007bff;&lt;/span&gt;
  color: white&lt;span class="p"&gt;;&lt;/span&gt;
  border: none&lt;span class="p"&gt;;&lt;/span&gt;
  cursor: pointer&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
button:hover &lt;span class="o"&gt;{&lt;/span&gt;
  background-color: &lt;span class="c"&gt;#0056b3;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Signup Component: Update &lt;strong&gt;src/app/auth/signup/signup.component.ts&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;import &lt;span class="o"&gt;{&lt;/span&gt; Component, inject, signal &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'@angular/core'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="o"&gt;{&lt;/span&gt; FormsModule &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'@angular/forms'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="o"&gt;{&lt;/span&gt; SupabaseService &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'../../services/supabase.service'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="o"&gt;{&lt;/span&gt; Router &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'@angular/router'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

@Component&lt;span class="o"&gt;({&lt;/span&gt;
  selector: &lt;span class="s1"&gt;'app-signup'&lt;/span&gt;,
  imports: &lt;span class="o"&gt;[&lt;/span&gt;FormsModule],
  templateUrl: &lt;span class="s1"&gt;'./signup.component.html'&lt;/span&gt;,
  styleUrl: &lt;span class="s1"&gt;'./signup.component.css'&lt;/span&gt;,
&lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;class SignupComponent &lt;span class="o"&gt;{&lt;/span&gt;
  name &lt;span class="o"&gt;=&lt;/span&gt; signal&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  email &lt;span class="o"&gt;=&lt;/span&gt; signal&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  password &lt;span class="o"&gt;=&lt;/span&gt; signal&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  private &lt;span class="nb"&gt;readonly &lt;/span&gt;supabaseService &lt;span class="o"&gt;=&lt;/span&gt; inject&lt;span class="o"&gt;(&lt;/span&gt;SupabaseService&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  private &lt;span class="nb"&gt;readonly &lt;/span&gt;router &lt;span class="o"&gt;=&lt;/span&gt; inject&lt;span class="o"&gt;(&lt;/span&gt;Router&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  async signUp&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    const &lt;span class="o"&gt;{&lt;/span&gt; error &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; await this.supabaseService.signUpWithEmail&lt;span class="o"&gt;({&lt;/span&gt;
      name: this.name&lt;span class="o"&gt;()&lt;/span&gt;,
      email: this.email&lt;span class="o"&gt;()&lt;/span&gt;,
      password: this.password&lt;span class="o"&gt;()&lt;/span&gt;,
    &lt;span class="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;error&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      alert&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Error signing up: '&lt;/span&gt; + error.message&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="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      alert&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Check your email to confirm your account!'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      this.router.navigate&lt;span class="o"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'/login'&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="o"&gt;}&lt;/span&gt;

  navigateToLogin&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    this.router.navigate&lt;span class="o"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'/login'&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="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Update &lt;strong&gt;src/app/auth/signup/signup.component.html&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"container"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &amp;lt;h2&amp;gt;Sign Up&amp;lt;/h2&amp;gt;
  &amp;lt;form&amp;gt;
    &amp;lt;input
      &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"text"&lt;/span&gt;
      &lt;span class="o"&gt;[(&lt;/span&gt;ngModel&lt;span class="o"&gt;)]=&lt;/span&gt;&lt;span class="s2"&gt;"name"&lt;/span&gt;
      &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"name"&lt;/span&gt;
      &lt;span class="nv"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Full Name"&lt;/span&gt;
      required
    /&amp;gt;
    &amp;lt;input
      &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"email"&lt;/span&gt;
      &lt;span class="o"&gt;[(&lt;/span&gt;ngModel&lt;span class="o"&gt;)]=&lt;/span&gt;&lt;span class="s2"&gt;"email"&lt;/span&gt;
      &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"email"&lt;/span&gt;
      &lt;span class="nv"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Email"&lt;/span&gt;
      required
    /&amp;gt;
    &amp;lt;input
      &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"password"&lt;/span&gt;
      &lt;span class="o"&gt;[(&lt;/span&gt;ngModel&lt;span class="o"&gt;)]=&lt;/span&gt;&lt;span class="s2"&gt;"password"&lt;/span&gt;
      &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"password"&lt;/span&gt;
      &lt;span class="nv"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Password"&lt;/span&gt;
      required
    /&amp;gt;
    &amp;lt;button &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"button"&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;click&lt;span class="o"&gt;)=&lt;/span&gt;&lt;span class="s2"&gt;"signUp()"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;Sign Up&amp;lt;/button&amp;gt;
  &amp;lt;/form&amp;gt;
  &amp;lt;p&amp;gt;Already have an account? &amp;lt;a &lt;span class="o"&gt;(&lt;/span&gt;click&lt;span class="o"&gt;)=&lt;/span&gt;&lt;span class="s2"&gt;"navigateToLogin()"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;Log In&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use the same CSS as the login component &lt;em&gt;(signup.component.css)&lt;/em&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Profile Component: Update &lt;strong&gt;src/app/profile/profile.component.ts&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;import &lt;span class="o"&gt;{&lt;/span&gt; Component, inject, OnInit &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'@angular/core'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="o"&gt;{&lt;/span&gt; SupabaseService &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'../services/supabase.service'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="o"&gt;{&lt;/span&gt; Router &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'@angular/router'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="o"&gt;{&lt;/span&gt; User &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'../types/user.type'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

@Component&lt;span class="o"&gt;({&lt;/span&gt;
  selector: &lt;span class="s1"&gt;'app-profile'&lt;/span&gt;,
  imports: &lt;span class="o"&gt;[]&lt;/span&gt;,
  templateUrl: &lt;span class="s1"&gt;'./profile.component.html'&lt;/span&gt;,
  styleUrl: &lt;span class="s1"&gt;'./profile.component.css'&lt;/span&gt;,
&lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;class ProfileComponent implements OnInit &lt;span class="o"&gt;{&lt;/span&gt;
  user: User | null &lt;span class="o"&gt;=&lt;/span&gt; null&lt;span class="p"&gt;;&lt;/span&gt;

  private &lt;span class="nb"&gt;readonly &lt;/span&gt;supabaseService &lt;span class="o"&gt;=&lt;/span&gt; inject&lt;span class="o"&gt;(&lt;/span&gt;SupabaseService&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  private &lt;span class="nb"&gt;readonly &lt;/span&gt;router &lt;span class="o"&gt;=&lt;/span&gt; inject&lt;span class="o"&gt;(&lt;/span&gt;Router&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  ngOnInit&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    this.fetchUser&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  async fetchUser&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    const &lt;span class="o"&gt;{&lt;/span&gt; data &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; await this.supabaseService.getUser&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    this.user &lt;span class="o"&gt;=&lt;/span&gt; data.user&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;this.user&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      this.router.navigate&lt;span class="o"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'/login'&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="o"&gt;}&lt;/span&gt;
  async signOut&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    await this.supabaseService.signOut&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    this.router.navigate&lt;span class="o"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'/login'&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="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/app/profile/profile.component.html&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"container"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &amp;lt;h2&amp;gt;User Profile&amp;lt;/h2&amp;gt;
  &amp;lt;p&amp;gt;
    Congratulations! Welcome to secure auth with Angular + Supabase is running.
    🎉
  &amp;lt;/p&amp;gt;
  @if &lt;span class="o"&gt;(&lt;/span&gt;user&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &amp;lt;p&amp;gt;User ID: &lt;span class="o"&gt;{{&lt;/span&gt; user.id &lt;span class="o"&gt;}}&lt;/span&gt;&amp;lt;/p&amp;gt;
  &amp;lt;p&amp;gt;Email: &lt;span class="o"&gt;{{&lt;/span&gt; user.email &lt;span class="o"&gt;}}&lt;/span&gt;&amp;lt;/p&amp;gt;
  &amp;lt;p&amp;gt;Display Name: &lt;span class="o"&gt;{{&lt;/span&gt; user.user_metadata.displayName &lt;span class="o"&gt;}}&lt;/span&gt;&amp;lt;/p&amp;gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &amp;lt;button &lt;span class="o"&gt;(&lt;/span&gt;click&lt;span class="o"&gt;)=&lt;/span&gt;&lt;span class="s2"&gt;"signOut()"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;Sign Out&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Configure Routing and Route Protection
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Create an Auth Guard: Generate a guard:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng generate guard guards/auth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Update &lt;strong&gt;src/app/guards/auth.guard.ts&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;import &lt;span class="o"&gt;{&lt;/span&gt; inject &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'@angular/core'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="o"&gt;{&lt;/span&gt; CanActivateFn, Router &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'@angular/router'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="o"&gt;{&lt;/span&gt; SupabaseService &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'../services/supabase.service'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nb"&gt;export &lt;/span&gt;const authGuard: CanActivateFn &lt;span class="o"&gt;=&lt;/span&gt; async &lt;span class="o"&gt;(&lt;/span&gt;route, state&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  const supabaseService &lt;span class="o"&gt;=&lt;/span&gt; inject&lt;span class="o"&gt;(&lt;/span&gt;SupabaseService&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  const router &lt;span class="o"&gt;=&lt;/span&gt; inject&lt;span class="o"&gt;(&lt;/span&gt;Router&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  const user &lt;span class="o"&gt;=&lt;/span&gt; await supabaseService.getUser&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;user&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    router.navigate&lt;span class="o"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'/login'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;, &lt;span class="o"&gt;{&lt;/span&gt; queryParams: &lt;span class="o"&gt;{&lt;/span&gt; returnUrl: state.url &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Set Up Routes: Update &lt;strong&gt;src/app/app.routes.ts&lt;/strong&gt; to use lazy loading and protect the profile route:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;import &lt;span class="o"&gt;{&lt;/span&gt; Routes &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'@angular/router'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="o"&gt;{&lt;/span&gt; authGuard &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'./guards/auth.guard'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nb"&gt;export &lt;/span&gt;const routes: Routes &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
  &lt;span class="o"&gt;{&lt;/span&gt; path: &lt;span class="s1"&gt;''&lt;/span&gt;, redirectTo: &lt;span class="s1"&gt;'/login'&lt;/span&gt;, pathMatch: &lt;span class="s1"&gt;'full'&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;,
  &lt;span class="o"&gt;{&lt;/span&gt;
    path: &lt;span class="s1"&gt;'login'&lt;/span&gt;,
    loadComponent: &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      import&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'./auth/login/login.component'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;.then&lt;span class="o"&gt;((&lt;/span&gt;c&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; c.LoginComponent&lt;span class="o"&gt;)&lt;/span&gt;,
  &lt;span class="o"&gt;}&lt;/span&gt;,
  &lt;span class="o"&gt;{&lt;/span&gt;
    path: &lt;span class="s1"&gt;'signup'&lt;/span&gt;,
    loadComponent: &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      import&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'./auth/signup/signup.component'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;.then&lt;span class="o"&gt;((&lt;/span&gt;c&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; c.SignupComponent&lt;span class="o"&gt;)&lt;/span&gt;,
  &lt;span class="o"&gt;}&lt;/span&gt;,
  &lt;span class="o"&gt;{&lt;/span&gt;
    path: &lt;span class="s1"&gt;'profile'&lt;/span&gt;,
    loadComponent: &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      import&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'./profile/profile.component'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;.then&lt;span class="o"&gt;((&lt;/span&gt;c&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; c.ProfileComponent&lt;span class="o"&gt;)&lt;/span&gt;,
    canActivate: &lt;span class="o"&gt;[&lt;/span&gt;authGuard],
  &lt;span class="o"&gt;}&lt;/span&gt;,
&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Run Application
&lt;/h2&gt;

&lt;p&gt;Using the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng serve -o
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will run and open the application in the default browser.&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%2Fuexbq8mfv0yqr8lko57x.jpg" 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%2Fuexbq8mfv0yqr8lko57x.jpg" alt="Angular+Suapbase+Successful+integration" width="800" height="271"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After successful sign-in🎉🎉🎉&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%2Fglnxsdat4i8su8lx4sfj.jpg" 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%2Fglnxsdat4i8su8lx4sfj.jpg" alt="Supabase+Angular+Succesful+Login" width="800" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;We’ve just built a secure authentication system in Angular using Supabase, complete with email/password signup, login, and route protection.&lt;/p&gt;

&lt;p&gt;This setup is a solid foundation for more advanced features like role-based access, password resets, or social logins, all supported by Supabase.&lt;/p&gt;

&lt;p&gt;Access the full source code on &lt;a href="https://github.com/KingsleyAmankwah/angular-supabase-auth" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For more customization and ideas, explore the &lt;a href="https://supabase.com/docs" rel="noopener noreferrer"&gt;Supabase Docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy coding! 🅰️⚡&lt;/p&gt;

</description>
      <category>angular</category>
      <category>webdev</category>
      <category>programming</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Underrated Angular Features Everyone Should Be Using</title>
      <dc:creator>Kingsley Amankwah</dc:creator>
      <pubDate>Fri, 16 May 2025 14:19:58 +0000</pubDate>
      <link>https://dev.to/kingsley/underrated-angular-features-everyone-should-be-using-55k5</link>
      <guid>https://dev.to/kingsley/underrated-angular-features-everyone-should-be-using-55k5</guid>
      <description>&lt;p&gt;&lt;strong&gt;Hey Angular developers! 🅰️&lt;/strong&gt; While features like &lt;a href="https://angular.dev/guide/signals" rel="noopener noreferrer"&gt;signals&lt;/a&gt; and &lt;a href="https://angular.dev/guide/components" rel="noopener noreferrer"&gt;standalone components&lt;/a&gt; get all the attention, Angular has quietly introduced many smaller (but just as impactful) improvements. These lesser-known tools can make the codebase cleaner, faster, and easier to maintain.&lt;/p&gt;

&lt;p&gt;In this article, I’ll reveal some powerful but underused Angular features, along with the version they were introduced in.&lt;/p&gt;

&lt;h2&gt;
  
  
  takeUntilDestroyed Operator (v16+)
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;takeUntilDestroyed&lt;/code&gt; operator, as part of the &lt;code&gt;@angular/core/rxjs- &lt;br&gt;
interop&lt;/code&gt; package, is a utility in Angular for managing observable &lt;br&gt;
subscriptions to prevent memory leaks. It automatically completes an &lt;br&gt;
observable when the associated Angular component, directive, service, or &lt;br&gt;
pipe is destroyed, eliminating the need for a manual subscription.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; import &lt;span class="o"&gt;{&lt;/span&gt; Component &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'@angular/core'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 import &lt;span class="o"&gt;{&lt;/span&gt; interval &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'rxjs'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 import &lt;span class="o"&gt;{&lt;/span&gt; takeUntilDestroyed &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'@angular/core/rxjs-interop'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

 @Component&lt;span class="o"&gt;({&lt;/span&gt;
  selector: &lt;span class="s1"&gt;'app-timer'&lt;/span&gt;,
  template: &lt;span class="sb"&gt;`&lt;/span&gt;&amp;lt;p&amp;gt;Timer: &lt;span class="o"&gt;{{&lt;/span&gt; count &lt;span class="o"&gt;}}&lt;/span&gt;&amp;lt;/p&amp;gt;&lt;span class="sb"&gt;`&lt;/span&gt;,
 &lt;span class="o"&gt;})&lt;/span&gt;
 &lt;span class="nb"&gt;export &lt;/span&gt;class TimerComponent &lt;span class="o"&gt;{&lt;/span&gt;
  count &lt;span class="o"&gt;=&lt;/span&gt; 0&lt;span class="p"&gt;;&lt;/span&gt;

  constructor&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    interval&lt;span class="o"&gt;(&lt;/span&gt;1000&lt;span class="o"&gt;)&lt;/span&gt;
      .pipe&lt;span class="o"&gt;(&lt;/span&gt;takeUntilDestroyed&lt;span class="o"&gt;())&lt;/span&gt;
      .subscribe&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; this.count++&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="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Eliminates manual cleanup with &lt;code&gt;ngOnDestroy&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Prevents memory leaks effortlessly.&lt;/li&gt;
&lt;li&gt;Works in any injection context (no &lt;code&gt;DestroyRef&lt;/code&gt; needed in constructors).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Use it in constructors or providers for maximum simplicity.&lt;/p&gt;

&lt;h2&gt;
  
  
  inject() – Dependency Injection Without a Constructor (v14+)
&lt;/h2&gt;

&lt;p&gt;Gone are the days when DI was limited to constructors. With &lt;code&gt;inject()&lt;/code&gt;,  we grab dependencies anywhere, even in utility functions.&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;inject&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;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&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;HttpClient&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;@angular/common/http&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// No constructor needed!&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Works outside components (e.g., in functions or services).&lt;/li&gt;
&lt;li&gt;It makes unit testing easier (there is no need for TestBed in some cases).&lt;/li&gt;
&lt;li&gt; Reduces boilerplate in standalone components.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  NgOptimizedImage Directive (Angular 15+)
&lt;/h2&gt;

&lt;p&gt;Images can slow down your app if not optimized. This &lt;a href="https://angular.dev/guide/image-optimization" rel="noopener noreferrer"&gt;directive&lt;/a&gt; automatically handles lazy loading and performance tweaks!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Although the NgOptimizedImage directive was made a stable feature in Angular version 15, it has been backported and is available as a stable feature in versions 13.4.0 and 14.3.0 as well.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&amp;lt;img &lt;span class="nv"&gt;ngSrc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"hero.jpg"&lt;/span&gt; &lt;span class="nv"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"1200"&lt;/span&gt; &lt;span class="nv"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"800"&lt;/span&gt; priority&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatic &lt;code&gt;srcset&lt;/code&gt; generation&lt;/li&gt;
&lt;li&gt;Lazy-loads images to boost performance.&lt;/li&gt;
&lt;li&gt;Prevents layout shifts with proper sizing.&lt;/li&gt;
&lt;li&gt;Supports CDN optimizations like automatic srcset.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Use the priority attribute for above-the-fold images to prioritize loading.&lt;/p&gt;

&lt;h2&gt;
  
  
  provideHttpClient() (Angular 15+)
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;provideHttpClient()&lt;/code&gt; function sets up HTTP services in one line, with support for interceptors, making it a must-have for standalone apps.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;import &lt;span class="o"&gt;{&lt;/span&gt; ApplicationConfig &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'@angular/core'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="o"&gt;{&lt;/span&gt; provideHttpClient&lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'@angular/common/http'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nb"&gt;export &lt;/span&gt;const appConfig: ApplicationConfig &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  providers: &lt;span class="o"&gt;[&lt;/span&gt;
    provideHttpClient&lt;span class="o"&gt;()&lt;/span&gt;,
  &lt;span class="o"&gt;]&lt;/span&gt;,
&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Eliminates HttpClientModule boilerplate.&lt;/li&gt;
&lt;li&gt;Simplifies HTTP setup for standalone components.&lt;/li&gt;
&lt;li&gt;Supports interceptors for advanced request handling (e.g., auth tokens)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  input/output with Signals (v17+)
&lt;/h2&gt;

&lt;p&gt;These features are Signal-based functions that replace the traditional &lt;code&gt;@Input()&lt;/code&gt; and &lt;code&gt;@Output()&lt;/code&gt; decorators&lt;/p&gt;

&lt;p&gt;Below is a code sample of its usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;import &lt;span class="o"&gt;{&lt;/span&gt; Component, input, output &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'@angular/core'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

// Child Component
@Component&lt;span class="o"&gt;({&lt;/span&gt;
  selector: &lt;span class="s1"&gt;'app-counter'&lt;/span&gt;,
  template: &lt;span class="sb"&gt;`&lt;/span&gt;
    &amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"counter"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &amp;lt;button &lt;span class="o"&gt;(&lt;/span&gt;click&lt;span class="o"&gt;)=&lt;/span&gt;&lt;span class="s2"&gt;"decrement()"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;-&amp;lt;/button&amp;gt;
      &amp;lt;span&amp;gt;&lt;span class="o"&gt;{{&lt;/span&gt; count&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt;&amp;lt;/span&amp;gt;
      &amp;lt;button &lt;span class="o"&gt;(&lt;/span&gt;click&lt;span class="o"&gt;)=&lt;/span&gt;&lt;span class="s2"&gt;"increment()"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;+&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
   &lt;span class="sb"&gt;`&lt;/span&gt;,
  standalone: &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;class CounterComponent &lt;span class="o"&gt;{&lt;/span&gt;
  count &lt;span class="o"&gt;=&lt;/span&gt; input&lt;span class="o"&gt;(&lt;/span&gt;0&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; // Equivalent to @Input&lt;span class="o"&gt;()&lt;/span&gt;
  countChanged &lt;span class="o"&gt;=&lt;/span&gt; output&amp;lt;number&amp;gt;&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; // Equivalent to @Output&lt;span class="o"&gt;()&lt;/span&gt;

  increment&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    const newValue &lt;span class="o"&gt;=&lt;/span&gt; this.count&lt;span class="o"&gt;()&lt;/span&gt; + 1&lt;span class="p"&gt;;&lt;/span&gt;
    this.countChanged.emit&lt;span class="o"&gt;(&lt;/span&gt;newValue&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  decrement&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    this.countChanged.emit&lt;span class="o"&gt;(&lt;/span&gt;this.count&lt;span class="o"&gt;()&lt;/span&gt; - 1&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="o"&gt;}&lt;/span&gt;

// Parent Component
@Component&lt;span class="o"&gt;({&lt;/span&gt;
  selector: &lt;span class="s1"&gt;'app-parent'&lt;/span&gt;,
  template: &lt;span class="sb"&gt;`&lt;/span&gt;
    &amp;lt;app-counter 
      &lt;span class="o"&gt;[&lt;/span&gt;count]&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"currentCount()"&lt;/span&gt; 
      &lt;span class="o"&gt;(&lt;/span&gt;countChanged&lt;span class="o"&gt;)=&lt;/span&gt;&lt;span class="s2"&gt;"handleCountChange(&lt;/span&gt;&lt;span class="nv"&gt;$event&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;
    /&amp;gt;
  &lt;span class="sb"&gt;`&lt;/span&gt;,
  standalone: &lt;span class="nb"&gt;true&lt;/span&gt;,
  imports: &lt;span class="o"&gt;[&lt;/span&gt;CounterComponent]
&lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;class ParentComponent &lt;span class="o"&gt;{&lt;/span&gt;
  currentCount &lt;span class="o"&gt;=&lt;/span&gt; signal&lt;span class="o"&gt;(&lt;/span&gt;5&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  handleCountChange&lt;span class="o"&gt;(&lt;/span&gt;newValue: number&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    this.currentCount.set&lt;span class="o"&gt;(&lt;/span&gt;newValue&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="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Type-safe by default&lt;/li&gt;
&lt;li&gt;Works seamlessly with Signals&lt;/li&gt;
&lt;li&gt;Simpler than traditional @Input/@Output&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Required Inputs Signal (Angular 17+)
&lt;/h2&gt;

&lt;p&gt;Missing component inputs can lead to runtime errors. Marking inputs as required ensures they’re always provided, catching issues early.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;import &lt;span class="o"&gt;{&lt;/span&gt; Component, input &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'@angular/core'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

@Component&lt;span class="o"&gt;({&lt;/span&gt;
  selector: &lt;span class="s1"&gt;'app-card'&lt;/span&gt;,
  template: &lt;span class="sb"&gt;`&lt;/span&gt;&amp;lt;h2&amp;gt;&lt;span class="o"&gt;{{&lt;/span&gt; title&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt;&amp;lt;/h2&amp;gt;&lt;span class="sb"&gt;`&lt;/span&gt;,
&lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;class CardComponent &lt;span class="o"&gt;{&lt;/span&gt;
  title &lt;span class="o"&gt;=&lt;/span&gt; input.required&amp;lt;string&amp;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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  model() Function – Reactive Two-Way Binding (Angular 17+)
&lt;/h2&gt;

&lt;p&gt;It replaces the &lt;code&gt;@Input()&lt;/code&gt; and &lt;code&gt;@Output()&lt;/code&gt; decorators with &lt;code&gt;model()&lt;/code&gt; function for a unified, reactive API that simplifies component communication.&lt;/p&gt;

&lt;p&gt;Below is a code sample:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;import &lt;span class="o"&gt;{&lt;/span&gt; Component, model &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'@angular/core'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

// Child Component &lt;span class="o"&gt;(&lt;/span&gt;Reusable Toggle&lt;span class="o"&gt;)&lt;/span&gt;
@Component&lt;span class="o"&gt;({&lt;/span&gt;
  selector: &lt;span class="s1"&gt;'app-toggle'&lt;/span&gt;,
  template: &lt;span class="sb"&gt;`&lt;/span&gt;
    &amp;lt;button &lt;span class="o"&gt;(&lt;/span&gt;click&lt;span class="o"&gt;)=&lt;/span&gt;&lt;span class="s2"&gt;"toggle()"&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;class.active]&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"value()"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;{{&lt;/span&gt; value&lt;span class="o"&gt;()&lt;/span&gt; ? &lt;span class="s1"&gt;'ON'&lt;/span&gt; : &lt;span class="s1"&gt;'OFF'&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt;
    &amp;lt;/button&amp;gt;
  &lt;span class="sb"&gt;`&lt;/span&gt;,
  styles: &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
    button &lt;span class="o"&gt;{&lt;/span&gt; 
      padding: 0.5rem 1rem&lt;span class="p"&gt;;&lt;/span&gt;
      border: 1px solid &lt;span class="c"&gt;#ccc; &lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    .active &lt;span class="o"&gt;{&lt;/span&gt;
      background: &lt;span class="c"&gt;#3f51b5;&lt;/span&gt;
      color: white&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;,
  standalone: &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;class ToggleComponent &lt;span class="o"&gt;{&lt;/span&gt;
  // Creates a two-way binding model
  value &lt;span class="o"&gt;=&lt;/span&gt; model&amp;lt;boolean&amp;gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; // Default: &lt;span class="nb"&gt;false

  &lt;/span&gt;toggle&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    this.value.set&lt;span class="o"&gt;(!&lt;/span&gt;this.value&lt;span class="o"&gt;())&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; // Updates parent automatically
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

// Parent Component
@Component&lt;span class="o"&gt;({&lt;/span&gt;
  selector: &lt;span class="s1"&gt;'app-parent'&lt;/span&gt;,
  template: &lt;span class="sb"&gt;`&lt;/span&gt;
    &amp;lt;h2&amp;gt;Current State: &lt;span class="o"&gt;{{&lt;/span&gt; isToggled&lt;span class="o"&gt;()&lt;/span&gt; ? &lt;span class="s1"&gt;'ACTIVE'&lt;/span&gt; : &lt;span class="s1"&gt;'INACTIVE'&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt;&amp;lt;/h2&amp;gt;

    &amp;lt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nt"&gt;--&lt;/span&gt; Two-way binding syntax &lt;span class="nt"&gt;--&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &amp;lt;app-toggle &lt;span class="o"&gt;[(&lt;/span&gt;value&lt;span class="o"&gt;)]=&lt;/span&gt;&lt;span class="s2"&gt;"isToggled"&lt;/span&gt; /&amp;gt;

    &amp;lt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nt"&gt;--&lt;/span&gt; Manual binding alternative &lt;span class="nt"&gt;--&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &amp;lt;app-toggle 
      &lt;span class="o"&gt;[&lt;/span&gt;value]&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"isToggled()"&lt;/span&gt; 
      &lt;span class="o"&gt;(&lt;/span&gt;valueChange&lt;span class="o"&gt;)=&lt;/span&gt;&lt;span class="s2"&gt;"isToggled.set(&lt;/span&gt;&lt;span class="nv"&gt;$event&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt; 
    /&amp;gt;
  &lt;span class="sb"&gt;`&lt;/span&gt;,
  standalone: &lt;span class="nb"&gt;true&lt;/span&gt;,
  imports: &lt;span class="o"&gt;[&lt;/span&gt;ToggleComponent]
&lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;class ParentComponent &lt;span class="o"&gt;{&lt;/span&gt;
  isToggled &lt;span class="o"&gt;=&lt;/span&gt; signal&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; // Parent manages state
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Combines input and output for two-way binding.&lt;/li&gt;
&lt;li&gt;Reactive and efficient with Signals.&lt;/li&gt;
&lt;li&gt;Reduces component boilerplate.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Deferrable Views (v17+)
&lt;/h2&gt;

&lt;p&gt;As part of the new control flow syntax, the &lt;a href="https://angular.dev/guide/templates/defer" rel="noopener noreferrer"&gt;deferrable view&lt;/a&gt; was introduced to lazy load template content.&lt;/p&gt;

&lt;p&gt;Below is a code sample for its use case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;@defer &lt;span class="o"&gt;(&lt;/span&gt;when condition&lt;span class="p"&gt;;&lt;/span&gt; on trigger&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &amp;lt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nt"&gt;--&lt;/span&gt; Heavy content to lazy load &lt;span class="nt"&gt;--&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &amp;lt;expensive-component /&amp;gt;

&lt;span class="o"&gt;}&lt;/span&gt; @placeholder &lt;span class="o"&gt;(&lt;/span&gt;optional&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &amp;lt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nt"&gt;--&lt;/span&gt; Shown &lt;span class="k"&gt;while &lt;/span&gt;waiting to load &lt;span class="nt"&gt;--&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &amp;lt;skeleton-loader /&amp;gt;

&lt;span class="o"&gt;}&lt;/span&gt; @loading &lt;span class="o"&gt;(&lt;/span&gt;optional&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &amp;lt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nt"&gt;--&lt;/span&gt; Shown during loading &lt;span class="nt"&gt;--&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &amp;lt;spinner /&amp;gt;

&lt;span class="o"&gt;}&lt;/span&gt; @error &lt;span class="o"&gt;(&lt;/span&gt;optional&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &amp;lt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nt"&gt;--&lt;/span&gt; Shown &lt;span class="k"&gt;if &lt;/span&gt;loading fails &lt;span class="nt"&gt;--&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &amp;lt;error-message /&amp;gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;90%+ reduction in initial bundle size&lt;/li&gt;
&lt;li&gt;Built-in loading/error states&lt;/li&gt;
&lt;li&gt;Multiple trigger conditions (viewport, idle, interaction)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s a quick overview of the underutilized Angular features covered in this article:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;th&gt;Primary Use Case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;takeUntilDestroyed&lt;/td&gt;
&lt;td&gt;16+&lt;/td&gt;
&lt;td&gt;Observable cleanup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;inject()&lt;/td&gt;
&lt;td&gt;14+&lt;/td&gt;
&lt;td&gt;Flexible dependency injection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NgOptimizedImage&lt;/td&gt;
&lt;td&gt;15+&lt;/td&gt;
&lt;td&gt;Image optimization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;provideHttpClient()&lt;/td&gt;
&lt;td&gt;15+&lt;/td&gt;
&lt;td&gt;Simplified HTTP setup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;input/output (Signals)&lt;/td&gt;
&lt;td&gt;17+&lt;/td&gt;
&lt;td&gt;Type-safe component communication&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Required Inputs&lt;/td&gt;
&lt;td&gt;17+&lt;/td&gt;
&lt;td&gt;Enforce input presence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;model()&lt;/td&gt;
&lt;td&gt;17+&lt;/td&gt;
&lt;td&gt;Reactive two-way binding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deferrable Views&lt;/td&gt;
&lt;td&gt;17+&lt;/td&gt;
&lt;td&gt;Lazy-loaded templates&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;These features may not be seen in the spotlight, but very effective. Let's make use of these hidden gems, we can streamline our development process and build cleaner, faster, and more robust Angular applications with ease.&lt;/p&gt;

&lt;p&gt;Happy coding! 🅰️&lt;/p&gt;

</description>
      <category>angular</category>
      <category>typescript</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to Integrate Sanity CMS with Angular</title>
      <dc:creator>Kingsley Amankwah</dc:creator>
      <pubDate>Fri, 18 Apr 2025 12:33:19 +0000</pubDate>
      <link>https://dev.to/kingsley/how-to-integrate-sanity-cms-with-angular-4i74</link>
      <guid>https://dev.to/kingsley/how-to-integrate-sanity-cms-with-angular-4i74</guid>
      <description>&lt;p&gt;&lt;strong&gt;Hey Angular developers! 🅰️&lt;/strong&gt; Most of the time, we find ourselves in an endless cycle of updating hard-coded content, making code changes, rebuilding our apps, and redeploying just to fix a typo or update a small description, which is not efficient because there's a smarter way to go about it. In this guide, I'll walk you through how to integrate &lt;a href="https://www.sanity.io/" rel="noopener noreferrer"&gt;Sanity CMS&lt;/a&gt;, with &lt;a href="https://angular.dev/overview" rel="noopener noreferrer"&gt;Angular&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Pro tip: Sanity content platform lets your marketing team edit content directly on the application while you focus on building great features.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Sanity And Angular?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Real-time content updates&lt;/strong&gt; without app redeploys&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structured content modeling&lt;/strong&gt; for consistent data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TypeScript-first&lt;/strong&gt; developer experience&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Image optimization&lt;/strong&gt; built-in&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free tier&lt;/strong&gt; perfect for getting started&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;Before we dive in, make sure you've got:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An Angular project&lt;/li&gt;
&lt;li&gt;Node.js v16+ installed&lt;/li&gt;
&lt;li&gt;A Sanity.io account (free tier works)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Section 1: Setting Up Sanity Studio
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;Run the command &lt;code&gt;npm install -g @sanity/cli&lt;/code&gt; to install Sanity CLI globally. After successful installation, run the command &lt;code&gt;sanity init&lt;/code&gt; to initialise a new sanity project&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up Your Content Structure
&lt;/h3&gt;

&lt;p&gt;When running &lt;code&gt;sanity init&lt;/code&gt;, you'll encounter an important choice:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;? Select project template
❯ Clean project with no predefined schemas
  Blog &lt;span class="o"&gt;(&lt;/span&gt;schema&lt;span class="o"&gt;)&lt;/span&gt;
  E-commerce &lt;span class="o"&gt;(&lt;/span&gt;schema&lt;span class="o"&gt;)&lt;/span&gt;
  Portfolio &lt;span class="o"&gt;(&lt;/span&gt;schema&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;For this tutorial, select &lt;code&gt;Blog (schema)&lt;/code&gt; because:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provides ready-to-use content models&lt;/li&gt;
&lt;li&gt;Demonstrates Sanity's core concepts&lt;/li&gt;
&lt;li&gt;Lets us focus on Angular integration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;The blog schema includes:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Posts with titles, slugs, and rich text&lt;/li&gt;
&lt;li&gt;Author management&lt;/li&gt;
&lt;li&gt;Category system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;This is perfect for learning how Sanity structures content before creating custom schemas.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For Experienced Users&lt;/strong&gt;&lt;br&gt;
Choose &lt;code&gt;Clean project with no predefined schemas&lt;/code&gt; if you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Need complete control&lt;/li&gt;
&lt;li&gt;Have existing content models&lt;/li&gt;
&lt;li&gt;Want to build from scratch&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re in the sanity project directory, run:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Then, open your browser and go to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:3333
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Expected Output:
&lt;/h3&gt;

&lt;p&gt;If everything goes as planned, the &lt;code&gt;http://localhost:3333&lt;/code&gt; will show the page below:&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%2F5rypw6zaauwc8rk2emv7.jpg" 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%2F5rypw6zaauwc8rk2emv7.jpg" alt="Sanity Success Page" width="800" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The view shows a page for you to log in to your sanity studio&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After a successful login based on the provider chosen, if you selected the &lt;code&gt;Blog (Schema)&lt;/code&gt; as the project template, below is how the structure is going to look:&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%2Fof69hqvp8wn81c5w0xgt.jpg" 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%2Fof69hqvp8wn81c5w0xgt.jpg" alt="Sanity Studio Structure" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The view shows the structure for the blog schema&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Section 2: Configuring Sanity In Angular
&lt;/h2&gt;

&lt;p&gt;Now that our Sanity Studio is running, it’s time to configure &lt;code&gt;Sanity Client&lt;/code&gt; in the Angular app.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1: Install Required Packages
&lt;/h4&gt;

&lt;p&gt;We’ll need a few npm packages to fetch and work with data from Sanity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @sanity/client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Click on the user profile section on the &lt;code&gt;http://localhost:3333&lt;/code&gt;&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%2Fb4fs7omfq1ink6ef7vsg.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%2Fb4fs7omfq1ink6ef7vsg.png" alt="Sanity profile Section" width="800" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the displayed dropdown, select the &lt;code&gt;Manage Project&lt;/code&gt; to navigate to the Sanity Dashboard&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%2Fjegzz3ajmk8d9w6rj2s2.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%2Fjegzz3ajmk8d9w6rj2s2.png" alt="Sanity-Manage-Project" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the Sanity Dashboard below, we can find the &lt;code&gt;projectId&lt;/code&gt; and can manage datasets, tokens, and collaborators. We'll need this info to configure the Angular client.&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%2Fvc2jlla63pv424l2lur7.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%2Fvc2jlla63pv424l2lur7.png" alt="Sanity Dashboard" width="800" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The image above is a general overview of the Sanity Dashboard&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2: Set Up Sanity Client in Angular
&lt;/h4&gt;

&lt;p&gt;Create a new directory, e.g., &lt;code&gt;config&lt;/code&gt; and a new file inside the &lt;code&gt;config&lt;/code&gt; app directory, to handle the setup for sanity in Angular.&lt;/p&gt;

&lt;p&gt;Here is a simplified structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/app/config/sanity-client.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, add the following code details:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;// src/app/config/sanity-client.ts
import sanityClient from &lt;span class="s1"&gt;'@sanity/client'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;const client &lt;span class="o"&gt;=&lt;/span&gt; sanityClient&lt;span class="o"&gt;({&lt;/span&gt;
  projectId: &lt;span class="s1"&gt;'your_project_id'&lt;/span&gt;,
  dataset: &lt;span class="s1"&gt;'your-dataset-title'&lt;/span&gt;,     
  useCdn: &lt;span class="nb"&gt;true&lt;/span&gt;,                 // &lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;you want fresh data
  apiVersion: &lt;span class="s1"&gt;'2023-01-01'&lt;/span&gt;,     // Use a UTC &lt;span class="nb"&gt;date &lt;/span&gt;string
&lt;span class="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Placing &lt;code&gt;Sanity config&lt;/code&gt; in its file keeps things modular and reusable, especially if we need to call the client from different parts of the Angular app (services, components, etc)&lt;/p&gt;

&lt;h2&gt;
  
  
  Section 3: Creating Sanity GROQ Queries In Angular
&lt;/h2&gt;

&lt;p&gt;Now that we’ve set up Sanity Studio and configured the Angular app to connect to it, it’s time to define the actual queries we'll use to fetch content.&lt;/p&gt;

&lt;p&gt;With &lt;a href="https://www.sanity.io/docs/groq" rel="noopener noreferrer"&gt;GROQ&lt;/a&gt;, we can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Filter documents &lt;code&gt;(*[_type == "post"])&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Fetch nested and referenced fields (author-&amp;gt;name)&lt;/li&gt;
&lt;li&gt;Sort, limit, and slice data&lt;/li&gt;
&lt;li&gt;Shape your responses exactly how you want&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To keep our project clean and maintainable, let’s create a dedicated directory for all our GROQ queries.&lt;br&gt;
Here's a simplified structure&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;src/app/queries/posts.groq.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the file and paste in the following query to get all posts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;// src/app/queries/posts.groq.ts

&lt;span class="nb"&gt;export &lt;/span&gt;const getAllPostsQuery &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;_type &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"post"&lt;/span&gt;&lt;span class="o"&gt;]{&lt;/span&gt;
  _id,
  title,
  slug,
  mainImage &lt;span class="o"&gt;{&lt;/span&gt;
    asset-&amp;gt;&lt;span class="o"&gt;{&lt;/span&gt;
      url
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;,
  author-&amp;gt;&lt;span class="o"&gt;{&lt;/span&gt;
    name,
    image&lt;span class="o"&gt;{&lt;/span&gt;
    asset-&amp;gt;&lt;span class="o"&gt;{&lt;/span&gt;
       url
      &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;,
    categories[]-&amp;gt;&lt;span class="o"&gt;{&lt;/span&gt;
      title,
      description
    &lt;span class="o"&gt;}&lt;/span&gt;,
  publishedAt,
  body[0]
&lt;span class="o"&gt;}&lt;/span&gt; | order&lt;span class="o"&gt;(&lt;/span&gt;publishedAt desc&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the query above, &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;[_type == "post"]&lt;/strong&gt; – Fetch all documents of type post&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;{ ... }&lt;/strong&gt; – Project only the fields we want: title, slug, mainImage, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;mainImage.asset-&amp;gt;url&lt;/strong&gt; – Traverse the image reference to get its url&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;author-&amp;gt;name&lt;/strong&gt; – Follow the reference to the author and grab their name&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;body[0]&lt;/strong&gt; – Just grab the first block of the body (optional for previews)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;| order(publishedAt desc)&lt;/strong&gt; – Sort posts from newest to oldest&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's add another query in the &lt;code&gt;src/app/queries/posts.groq.ts&lt;/code&gt; file to get full post details by &lt;code&gt;slug&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;const getPostBySlugQuery &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;slug: string&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;_type &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"post"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; slug.current &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;slug&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;][&lt;/span&gt;0]&lt;span class="o"&gt;{&lt;/span&gt;
  _id,
  title,
  slug,
  publishedAt,
  mainImage &lt;span class="o"&gt;{&lt;/span&gt;
    asset-&amp;gt;&lt;span class="o"&gt;{&lt;/span&gt;
      url
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;,
  author-&amp;gt;&lt;span class="o"&gt;{&lt;/span&gt;
    name,
    bio,
    image &lt;span class="o"&gt;{&lt;/span&gt;
      asset-&amp;gt;&lt;span class="o"&gt;{&lt;/span&gt;
        url
      &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;,
  categories[]-&amp;gt;&lt;span class="o"&gt;{&lt;/span&gt;
    title
  &lt;span class="o"&gt;}&lt;/span&gt;,
  body
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the slug query above,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;[_type == "post" &amp;amp;&amp;amp; slug.current == "${slug}"]&lt;/strong&gt; – Find a post where the &lt;code&gt;slug&lt;/code&gt; matches the one passed in&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;[0]&lt;/strong&gt; – Get just the first (and hopefully only) match&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;mainImage.asset-&amp;gt;url&lt;/strong&gt; – Resolve the image reference to its URL&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;author-&amp;gt;&lt;/strong&gt; – Expand author details to get both name and profile image&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;categories[]-&amp;gt;&lt;/strong&gt; – Get titles for all linked categories&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;body&lt;/strong&gt; – Get the full post content (use this for rendering detail view)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Add Sample Data to Sanity
&lt;/h3&gt;

&lt;p&gt;Before jumping into building the Angular service, let’s add some sample data to our Sanity Studio so we actually have something to display.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;code&gt;http://localhost:3333&lt;/code&gt; to access the Sanity Studio.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click the &lt;code&gt;"Category"&lt;/code&gt; tab and add a few categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Programming concepts &lt;/li&gt;
&lt;li&gt;CMS &amp;amp; Headless&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;Angular&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Then move to the &lt;code&gt;"Author"&lt;/code&gt; tab and add authors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kingsley Amankwah – Tech Writer with a passion for clean code&lt;/li&gt;
&lt;li&gt;Angelina Jolie – Full Stack Dev &amp;amp; Coffee Enthusiast&lt;/li&gt;
&lt;li&gt;Iddris Alba – Dev Advocate @ AngularVerse&lt;/li&gt;
&lt;li&gt;Jason Stathan – GDE Dev Advocate @ Google&lt;/li&gt;
&lt;li&gt;Tommy Shelby – NgRx Co-Founder&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, go to the &lt;code&gt;"Post"&lt;/code&gt; tab and add posts:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;“Building a Blog with Sanity and Angular from Scratch”&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Author: Iddris Alba&lt;/li&gt;
&lt;li&gt;Categories: Angular, CMS &amp;amp; Headless&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;“Creating SEO-Friendly Angular Apps with SSR and Sanity”&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Author: Iddris Alba&lt;/li&gt;
&lt;li&gt;Categories: Angular, Programming Concepts, CMS &amp;amp; Headless&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;“Why Angular + Sanity CMS is a Power Combo”&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Author: Jason Stathan&lt;/li&gt;
&lt;li&gt;Categories: Programming Concepts, Angular, CMS &amp;amp; Headless&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;“TypeScript Tips for Clean Angular Code”&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Author: Tommy Shelby&lt;/li&gt;
&lt;li&gt;Categories: Angular, TypeScript&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;“How to Handle Rich Text from Sanity in Angular Without Packages”&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Author: Kingsley Amankwah&lt;/li&gt;
&lt;li&gt;Categories: TypeScript, Angular, CMS &amp;amp; Headless&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;“Top 5 CMS Choices for Angular Developers in 2025”&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Author: Angelina Jolie&lt;/li&gt;
&lt;li&gt;Categories: CMS &amp;amp; Headless&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's a simplified image of how to add a Category:&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%2F27s8vxjxl1kgjo72hay6.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%2F27s8vxjxl1kgjo72hay6.png" alt="Sanity-Blog-Category-Addition" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we have data in our Sanity Studio, we’re ready to create a service in Angular that pulls this content and renders it in the UI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Section 4: Creating a Sanity Service in Angular
&lt;/h2&gt;

&lt;p&gt;Now that our Sanity client is configured, let’s create an Angular service to fetch content from Sanity. This service will handle communication with the Sanity API using the GROQ queries we defined earlier.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Generate the Sanity Service
&lt;/h3&gt;

&lt;p&gt;From your terminal, generate a new service inside the sanity directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng generate service services/sanity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create two files: &lt;code&gt;sanity.service.ts&lt;/code&gt; and &lt;code&gt;sanity.service.spec.ts&lt;/code&gt; in the src/app/services directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Set Up the Service to Use the Sanity Client
&lt;/h3&gt;

&lt;p&gt;Open the newly created &lt;code&gt;sanity.service.ts&lt;/code&gt; file and update it as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;//src/app/services/sanity.service.ts
import &lt;span class="o"&gt;{&lt;/span&gt; Injectable &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'@angular/core'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="o"&gt;{&lt;/span&gt; client &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'../config/sanity-client'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="o"&gt;{&lt;/span&gt; getAllPostsQuery, getPostBySlugQuery &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'../queries/posts.groq'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
import &lt;span class="o"&gt;{&lt;/span&gt; Post &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'../models/post.model'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

@Injectable&lt;span class="o"&gt;({&lt;/span&gt;
  providedIn: &lt;span class="s1"&gt;'root'&lt;/span&gt;,
&lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;class SanityService &lt;span class="o"&gt;{&lt;/span&gt;
  async getPost&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    try &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return &lt;/span&gt;await client.fetch&lt;span class="o"&gt;(&lt;/span&gt;getAllPostsQuery&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; catch &lt;span class="o"&gt;(&lt;/span&gt;error&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      console.log&lt;span class="o"&gt;(&lt;/span&gt;error&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      throw error&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  async getPostBySlug&lt;span class="o"&gt;(&lt;/span&gt;slug: string&lt;span class="o"&gt;)&lt;/span&gt;: Promise&amp;lt;Post | null&amp;gt; &lt;span class="o"&gt;{&lt;/span&gt;
    try &lt;span class="o"&gt;{&lt;/span&gt;
      const query &lt;span class="o"&gt;=&lt;/span&gt; getPostBySlugQuery&lt;span class="o"&gt;(&lt;/span&gt;slug&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;return &lt;/span&gt;await client.fetch&lt;span class="o"&gt;(&lt;/span&gt;query&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; catch &lt;span class="o"&gt;(&lt;/span&gt;error&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      console.error&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;Error fetching post with slug &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;slug&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;:&lt;span class="sb"&gt;`&lt;/span&gt;, error&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      throw error&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Section 5: Displaying Content from Sanity
&lt;/h2&gt;

&lt;p&gt;Now that we’ve created our Angular service, let’s proceed to generate components that will display the content fetched from Sanity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Generate the Post Component
&lt;/h3&gt;

&lt;p&gt;From your terminal, generate a new component inside the directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng generate component post
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/app/post
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Which will contain the component class, its template, and its styles.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Inside &lt;code&gt;src/app/post/post.component.ts&lt;/code&gt;, update the component to fetch data from Sanity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;class PostsComponent implements OnInit &lt;span class="o"&gt;{&lt;/span&gt;
  private &lt;span class="nb"&gt;readonly &lt;/span&gt;sanityService &lt;span class="o"&gt;=&lt;/span&gt; inject&lt;span class="o"&gt;(&lt;/span&gt;SanityService&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  private &lt;span class="nb"&gt;readonly &lt;/span&gt;router &lt;span class="o"&gt;=&lt;/span&gt; inject&lt;span class="o"&gt;(&lt;/span&gt;Router&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  protected posts &lt;span class="o"&gt;=&lt;/span&gt; signal&amp;lt;Post[]&amp;gt;&lt;span class="o"&gt;([])&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


  ngOnInit&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    this.loadPosts&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  protected async loadPosts&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    const fetchPosts &lt;span class="o"&gt;=&lt;/span&gt; await this.sanityService.getPost&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    this.posts.set&lt;span class="o"&gt;(&lt;/span&gt;fetchPosts&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;

  protected navigateToPostBySlug&lt;span class="o"&gt;(&lt;/span&gt;slug: string&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    this.router.navigate&lt;span class="o"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'post'&lt;/span&gt;, slug]&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="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A method to fetch all posts from Sanity.&lt;/li&gt;
&lt;li&gt;A method to navigate to a post's detail page using the slug.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add the Component Template&lt;br&gt;
Here’s a simple UI template to display the posts using TailwindCSS:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Note:&lt;/strong&gt; Sanity returns rich text content in a &lt;code&gt;block&lt;/code&gt; format. To cleanly display this in the Angular templates (e.g., for the post body), &lt;br&gt;
we can use a custom pipe like &lt;code&gt;blockContentToText&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;You can access the pipe implementation in the codebase &lt;a href="https://github.com/KingsleyAmankwah/angular-sanity-article/blob/master/angular/src/app/pipe/block-content-to-text.pipe.ts" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; &amp;lt;h2 &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"text-3xl font-bold mb-6 text-gray-800"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;Latest Posts&amp;lt;/h2&amp;gt;
  &amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"grid gap-6 md:grid-cols-2 lg:grid-cols-3"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    @for &lt;span class="o"&gt;(&lt;/span&gt;post of posts&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; track post._id&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &amp;lt;div
      &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"bg-white rounded-2xl shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-300"&lt;/span&gt;
    &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &amp;lt;img
        &lt;span class="o"&gt;[&lt;/span&gt;src]&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"post.mainImage?.asset?.url"&lt;/span&gt;
        &lt;span class="nv"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{{ post.title }}"&lt;/span&gt;
        &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"h-48 w-full object-cover"&lt;/span&gt;
      /&amp;gt;

      &amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"p-5"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &amp;lt;h3 &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"text-xl font-semibold text-gray-800 mb-2"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;{{&lt;/span&gt; post.title &lt;span class="o"&gt;}}&lt;/span&gt;
        &amp;lt;/h3&amp;gt;

        &amp;lt;p &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"text-gray-600 text-sm mb-3"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;{{&lt;/span&gt; post.body | blockContentToText : 100 &lt;span class="o"&gt;}}&lt;/span&gt;
        &amp;lt;/p&amp;gt;

        &amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"flex flex-wrap gap-2 mt-4"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          @for &lt;span class="o"&gt;(&lt;/span&gt;category of post.categories&lt;span class="p"&gt;;&lt;/span&gt; track &lt;span class="nv"&gt;$index&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
          &amp;lt;span
            &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"bg-gray-200 text-gray-800 text-xs px-3 py-1 rounded-full"&lt;/span&gt;
          &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;{{&lt;/span&gt; category.title &lt;span class="o"&gt;}}&lt;/span&gt;
          &amp;lt;/span&amp;gt;
          &lt;span class="o"&gt;}&lt;/span&gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"flex items-center gap-2 mt-4"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &amp;lt;img
            &lt;span class="o"&gt;[&lt;/span&gt;src]&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"post.author.image?.asset?.url"&lt;/span&gt;
            &lt;span class="nv"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{{ post.author.name }}"&lt;/span&gt;
            &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"w-8 h-8 rounded-full object-cover"&lt;/span&gt;
          /&amp;gt;
          &amp;lt;span &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"text-gray-700 text-sm"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;By &lt;span class="o"&gt;{{&lt;/span&gt; post.author.name &lt;span class="o"&gt;}}&lt;/span&gt;&amp;lt;/span&amp;gt;

          &amp;lt;a
            &lt;span class="o"&gt;(&lt;/span&gt;click&lt;span class="o"&gt;)=&lt;/span&gt;&lt;span class="s2"&gt;"navigateToPostBySlug(post.slug.current)"&lt;/span&gt;
            &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"bg-blue-400 text-white text-sm ml-auto px-3 py-1 rounded-full cursor-pointer"&lt;/span&gt;
            &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;Read more...&amp;lt;/a
          &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this setup the first error we will encounter is &lt;strong&gt;CORS ERROR&lt;/strong&gt;&lt;br&gt;
Below is an image showing how it will be displayed:&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%2Fo3b6n1y2849cnr8psw6z.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%2Fo3b6n1y2849cnr8psw6z.png" alt="Sanity CORS ERROR" width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To fix that, go to the Sanity Dashboard and follow the instructions in the image below to fix the &lt;code&gt;CORS ERROR&lt;/code&gt;:&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%2Frbqw8wr66r254nfnm7zk.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%2Frbqw8wr66r254nfnm7zk.png" alt="Sanity CORS ERROR SOLUTION" width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After adding the development URL e.g &lt;code&gt;(http://localhost:4200)&lt;/code&gt; to the allowed CORS origins, re-run the application. You should now see the content fetched from Sanity.&lt;/p&gt;

&lt;p&gt;Here’s what the UI will look like after successful integration:&lt;br&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%2F54k5v4npep7375exkrsn.jpg" 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%2F54k5v4npep7375exkrsn.jpg" alt="Sanity+Angular Integration" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: This UI is styled with &lt;a href="https://tailwindcss.com/docs/installation/framework-guides" rel="noopener noreferrer"&gt;TailwindCSS&lt;/a&gt; , which helps achieve a clean, responsive layout.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 2: Generate the View Post Component
&lt;/h3&gt;

&lt;p&gt;Now, let's proceed to fetch the content using the &lt;code&gt;getPostBySlugQuery&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Run the following in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng generate component view-post
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/app/view-post
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Which will contain the component class, its template, and its styles.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;src/app/view-post/view-post.component.ts&lt;/code&gt;, use the code below to fetch the post by it's slug:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;class ViewPostComponent implements OnInit &lt;span class="o"&gt;{&lt;/span&gt;
  private &lt;span class="nb"&gt;readonly &lt;/span&gt;sanityService &lt;span class="o"&gt;=&lt;/span&gt; inject&lt;span class="o"&gt;(&lt;/span&gt;SanityService&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  private &lt;span class="nb"&gt;readonly &lt;/span&gt;route &lt;span class="o"&gt;=&lt;/span&gt; inject&lt;span class="o"&gt;(&lt;/span&gt;ActivatedRoute&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  protected post &lt;span class="o"&gt;=&lt;/span&gt; signal&amp;lt;Post | null&amp;gt;&lt;span class="o"&gt;(&lt;/span&gt;null&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  ngOnInit&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    this.fetchPostDetails&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  protected async fetchPostDetails&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    const slug &lt;span class="o"&gt;=&lt;/span&gt; this.route.snapshot.paramMap.get&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'slug'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; ?? &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    const response &lt;span class="o"&gt;=&lt;/span&gt; await this.sanityService.getPostBySlug&lt;span class="o"&gt;(&lt;/span&gt;slug&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    this.post.set&lt;span class="o"&gt;(&lt;/span&gt;response&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="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;The code above contains a method to fetch post details by utilizing the activate route to get content slug&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Inside the &lt;code&gt;src/app/view-post/view-post.component.html&lt;/code&gt;, add this UI to display full post:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"max-w-4xl mx-auto px-4 py-12"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &amp;lt;img
    &lt;span class="o"&gt;[&lt;/span&gt;src]&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"post()?.mainImage?.asset?.url"&lt;/span&gt;
    &lt;span class="nv"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{{ post()?.title }}"&lt;/span&gt;
    &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"w-full h-96 object-cover rounded-xl shadow-md mb-8"&lt;/span&gt;
  /&amp;gt;

  &amp;lt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nt"&gt;--&lt;/span&gt; Title &lt;span class="nt"&gt;--&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &amp;lt;h1 &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"text-4xl font-bold text-gray-900 mb-4"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;{{&lt;/span&gt; post&lt;span class="o"&gt;()&lt;/span&gt;?.title &lt;span class="o"&gt;}}&lt;/span&gt;
  &amp;lt;/h1&amp;gt;


  &amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"flex items-center justify-between text-sm text-gray-500 mb-6"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"flex items-center gap-2"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &amp;lt;img
        &lt;span class="o"&gt;[&lt;/span&gt;src]&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"post()?.author?.image?.asset?.url"&lt;/span&gt;
        &lt;span class="nv"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{{ post()?.author?.name }}"&lt;/span&gt;
        &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"w-8 h-8 rounded-full object-cover"&lt;/span&gt;
      /&amp;gt;
      &amp;lt;span &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"font-medium text-gray-700"&lt;/span&gt;
        &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;By &lt;span class="o"&gt;{{&lt;/span&gt; post&lt;span class="o"&gt;()&lt;/span&gt;?.author?.name &lt;span class="o"&gt;}}&lt;/span&gt;&amp;lt;/span
      &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;span&amp;gt;&lt;span class="o"&gt;{{&lt;/span&gt; post&lt;span class="o"&gt;()&lt;/span&gt;?.publishedAt | &lt;span class="nb"&gt;date&lt;/span&gt; : &lt;span class="s2"&gt;"longDate"&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt;&amp;lt;/span&amp;gt;
  &amp;lt;/div&amp;gt;

    &amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"flex flex-wrap gap-2 mt-4"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    @for &lt;span class="o"&gt;(&lt;/span&gt;category of post&lt;span class="o"&gt;()&lt;/span&gt;?.categories&lt;span class="p"&gt;;&lt;/span&gt; track &lt;span class="nv"&gt;$index&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &amp;lt;span &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"bg-gray-200 text-gray-800 text-xs px-3 py-1 rounded-full"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;{{&lt;/span&gt; category.title &lt;span class="o"&gt;}}&lt;/span&gt;
    &amp;lt;/span&amp;gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &amp;lt;/div&amp;gt;

  &amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"prose prose-lg max-w-none text-gray-800 leading-relaxed"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &amp;lt;p &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"text-gray-600 text-sm mb-3"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;{{&lt;/span&gt; post&lt;span class="o"&gt;()&lt;/span&gt;?.body | blockContentToText &lt;span class="o"&gt;}}&lt;/span&gt;
    &amp;lt;/p&amp;gt;
  &amp;lt;/div&amp;gt;

  &amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"mt-12 border-t-gray-400 border-t-[0.2px] pt-6"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &amp;lt;h3 &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"text-lg font-semibold text-gray-800 mb-2"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;About the author&amp;lt;/h3&amp;gt;
    &amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"flex items-center gap-4"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &amp;lt;img
        &lt;span class="o"&gt;[&lt;/span&gt;src]&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"post()?.author?.image?.asset?.url"&lt;/span&gt;
        &lt;span class="nv"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{{ post()?.author?.name }}"&lt;/span&gt;
        &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"w-12 h-12 rounded-full object-cover"&lt;/span&gt;
      /&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;p &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"font-medium"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;{{&lt;/span&gt; post&lt;span class="o"&gt;()&lt;/span&gt;?.author?.name &lt;span class="o"&gt;}}&lt;/span&gt;&amp;lt;/p&amp;gt;
        &amp;lt;p &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"text-sm text-gray-600"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;{{&lt;/span&gt; post&lt;span class="o"&gt;()&lt;/span&gt;?.author?.bio | blockContentToText &lt;span class="o"&gt;}}&lt;/span&gt;
        &amp;lt;/p&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Below is an image of the content fetched using the &lt;code&gt;getPostBySlugQuery&lt;/code&gt;:&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%2F8nuj5kahdqbdjozm4b0z.jpg" 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%2F8nuj5kahdqbdjozm4b0z.jpg" alt="Sanity+Angular+fetchbyslug" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;PS: As stated ealier, the UI has been styled using &lt;a href="https://tailwindcss.com/docs/installation/framework-guides" rel="noopener noreferrer"&gt;TailwindCSS&lt;/a&gt; hence the reason for the nice design&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tips When Writing Queries
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Always start with &lt;strong&gt;[_type == "yourType"]&lt;/strong&gt; &lt;code&gt;(e.g., "post", "author")&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;{}&lt;/strong&gt; to specify the fields you want back&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;-&amp;gt;&lt;/strong&gt; to follow references&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;[0]&lt;/strong&gt; to get the first result, or slice/limit &lt;strong&gt;([0...5])&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;In this tutorial, we walked through the full process of integrating Sanity CMS with Angular, covering everything from setting up the Sanity Studio to displaying dynamic blog content in an Angular application. Here’s a quick recap of what we achieved:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Set up and configured Sanity CMS&lt;/li&gt;
&lt;li&gt; Defined GROQ queries for fetching posts and post details&lt;/li&gt;
&lt;li&gt; Created Angular services to interact with Sanity&lt;/li&gt;
&lt;li&gt; Displayed content using Angular components&lt;/li&gt;
&lt;li&gt; Styled everything beautifully using TailwindCSS&lt;/li&gt;
&lt;li&gt; Handled CORS configuration for local development&lt;/li&gt;
&lt;li&gt; Built a full blog-like experience with navigation to post detail pages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whether you're building a blog, portfolio, or a content-driven application, this Sanity + Angular combo gives you the flexibility of a headless CMS with the power of Angular’s frontend ecosystem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Access the Full Code on GitHub
&lt;/h3&gt;

&lt;p&gt;The entire source code for this project is available on GitHub:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/KingsleyAmankwah/angular-sanity-article" rel="noopener noreferrer"&gt;Access the Full Code Here&lt;/a&gt;&lt;br&gt;
Don't forget to leave a star if you found it helpful!&lt;/p&gt;

&lt;h3&gt;
  
  
  Let's Connect!
&lt;/h3&gt;

&lt;p&gt;If you have questions, feedback, or want to see more tutorials like this, feel free to reach out or follow me on my socials:&lt;/p&gt;

&lt;p&gt;Twitter/X: &lt;a href="https://x.com/IAmKingsley001" rel="noopener noreferrer"&gt;@IAmKingsley001&lt;/a&gt;&lt;br&gt;
LinkedIn: &lt;a href="https://www.linkedin.com/in/kingsleyamankwah/" rel="noopener noreferrer"&gt;KingsleyAmankwah&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/KingsleyAmankwah" rel="noopener noreferrer"&gt;KingsleyAmankwah&lt;/a&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>sanity</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to Configure GraphQL in Angular: For Public and Private APIs</title>
      <dc:creator>Kingsley Amankwah</dc:creator>
      <pubDate>Fri, 11 Apr 2025 12:27:32 +0000</pubDate>
      <link>https://dev.to/kingsley/how-to-configure-graphql-in-angular-for-public-and-private-apis-3fc7</link>
      <guid>https://dev.to/kingsley/how-to-configure-graphql-in-angular-for-public-and-private-apis-3fc7</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Hey, Angular devs🅰️, as we already know, &lt;a href="https://graphql.org/learn/" rel="noopener noreferrer"&gt;GraphQL&lt;/a&gt; provides precise data fetching and reduces over-fetching. In this tutorial, I’ll walk you through how to configure GraphQL in Angular, covering both authenticated (private APIs) and unauthenticated (public APIs) setups.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;Before we dive in, make sure you’ve got:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An Angular project, using the command &lt;code&gt;ng new my-app&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Apollo Angular Setup for GraphQL using the command &lt;code&gt;ng add apollo-angular&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Optional: State management using &lt;code&gt;NgRx Signal Store&lt;/code&gt; for the private apis approach.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;Let's set up a new angular project using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng new ang-grapql-setup

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After successful installations, let's proceed to install Apollo Angular using the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng add apollo-angular
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will add the following packages to the app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;apollo-angular&lt;/strong&gt; - Angular integration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;apollo/client&lt;/strong&gt; - Core GraphQL client&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;graphql&lt;/strong&gt; - Query language parser&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let's install NgRx Signals using the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng add @ngrx/signals
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will add the package &lt;code&gt;@ngrx/signals&lt;/code&gt; to help us manage the state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Section 1: GraphQL Setup For Public APIs
&lt;/h2&gt;

&lt;p&gt;Let's start with a simple public API connection - the fastest way to get GraphQL working in the Angular app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuration
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;graphql-provider-public-api.config.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;// src/app/config/graphql-provider-public-api.config.ts
&lt;span class="nb"&gt;export &lt;/span&gt;const apolloOptionsFactory &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  const graphqlURI &lt;span class="o"&gt;=&lt;/span&gt; environment.GRAPHQL_URI_NO_TOKEN&lt;span class="p"&gt;;&lt;/span&gt;
  const httpLink &lt;span class="o"&gt;=&lt;/span&gt; inject&lt;span class="o"&gt;(&lt;/span&gt;HttpLink&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;link&lt;/span&gt;: httpLink.create&lt;span class="o"&gt;({&lt;/span&gt; uri: graphqlURI &lt;span class="o"&gt;})&lt;/span&gt;,
    cache: new InMemoryCache&lt;span class="o"&gt;()&lt;/span&gt;,
    defaultOptions: &lt;span class="o"&gt;{&lt;/span&gt;
      watchQuery: &lt;span class="o"&gt;{&lt;/span&gt;
        fetchPolicy: &lt;span class="s1"&gt;'cache-first'&lt;/span&gt;,
        errorPolicy: &lt;span class="s1"&gt;'all'&lt;/span&gt;,
      &lt;span class="o"&gt;}&lt;/span&gt;,
      query: &lt;span class="o"&gt;{&lt;/span&gt;
        fetchPolicy: &lt;span class="s1"&gt;'cache-first'&lt;/span&gt;,
        errorPolicy: &lt;span class="s1"&gt;'all'&lt;/span&gt;,
      &lt;span class="o"&gt;}&lt;/span&gt;,
    &lt;span class="o"&gt;}&lt;/span&gt;,
  &lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nb"&gt;export &lt;/span&gt;const graphqlProviderConfig: ApplicationConfig[&lt;span class="s1"&gt;'providers'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;[&lt;/span&gt;
    Apollo,
    &lt;span class="o"&gt;{&lt;/span&gt;
      provide: APOLLO_OPTIONS,
      useFactory: apolloOptionsFactory,
    &lt;span class="o"&gt;}&lt;/span&gt;,
  &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code, the &lt;code&gt;apolloOptionsFactory&lt;/code&gt; function pulls in the GraphQL server URI from your environment config and uses Angular’s inject to grab the &lt;code&gt;HttpLink&lt;/code&gt; service, creating a direct connection to the endpoint.&lt;/p&gt;

&lt;p&gt;We set up an &lt;strong&gt;InMemoryCache to store query results, reducing unnecessary network calls&lt;/strong&gt; and apply default options like &lt;strong&gt;cache-first to prioritize cached data while fetching fresh results when needed&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;errorPolicy&lt;/code&gt;: "all" ensures we get both data and errors, giving us the flexibility in handling responses. &lt;/p&gt;

&lt;p&gt;Finally, the &lt;code&gt;graphqlProviderConfig&lt;/code&gt; ties it all together, providing Apollo Client to the app.&lt;/p&gt;

&lt;h3&gt;
  
  
  App Configuration
&lt;/h3&gt;

&lt;p&gt;Update &lt;code&gt;app.config.ts&lt;/code&gt; with the &lt;code&gt;graphqlProviderConfig&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;// src/app/app.config.ts
&lt;span class="nb"&gt;export &lt;/span&gt;const appConfig: ApplicationConfig &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  providers: &lt;span class="o"&gt;[&lt;/span&gt;
    provideZoneChangeDetection&lt;span class="o"&gt;({&lt;/span&gt; eventCoalescing: &lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="o"&gt;})&lt;/span&gt;,
    provideRouter&lt;span class="o"&gt;(&lt;/span&gt;routes&lt;span class="o"&gt;)&lt;/span&gt;,
    provideHttpClient&lt;span class="o"&gt;()&lt;/span&gt;,
    graphqlProviderConfig,
  &lt;span class="o"&gt;]&lt;/span&gt;,
&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setup Public API Query
&lt;/h3&gt;

&lt;p&gt;Let’s set up a query from a public &lt;a href="https://countries.trevorblades.com/" rel="noopener noreferrer"&gt;GraphQL API&lt;/a&gt; to fetch country details.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;// src/app/graphql/queries.ts
&lt;span class="nb"&gt;export &lt;/span&gt;const FETCH_COUNTRIES &lt;span class="o"&gt;=&lt;/span&gt; gql&lt;span class="sb"&gt;`&lt;/span&gt;
  query &lt;span class="o"&gt;{&lt;/span&gt;
    countries &lt;span class="o"&gt;{&lt;/span&gt;
      name
      capital
      currency
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="sb"&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, let's set up a countries component to fetch and display the data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;// src/app/countries/countries.component.ts
@Component&lt;span class="o"&gt;({&lt;/span&gt;
  selector: &lt;span class="s1"&gt;'app-countries'&lt;/span&gt;,
  imports: &lt;span class="o"&gt;[&lt;/span&gt;CommonModule],
  templateUrl: &lt;span class="s1"&gt;'./countries.component.html'&lt;/span&gt;,
&lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;class CountriesComponent &lt;span class="o"&gt;{&lt;/span&gt;
  protected data: Countries[] &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  constructor&lt;span class="o"&gt;(&lt;/span&gt;private &lt;span class="nb"&gt;readonly &lt;/span&gt;apollo: Apollo&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    this.apollo
      .query&amp;lt;CountriesResponse&amp;gt;&lt;span class="o"&gt;({&lt;/span&gt; query: FETCH_COUNTRIES &lt;span class="o"&gt;})&lt;/span&gt;
      .subscribe&lt;span class="o"&gt;((&lt;/span&gt;result&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;this.data &lt;span class="o"&gt;=&lt;/span&gt; result.data.countries&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="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Displaying the Data
&lt;/h3&gt;

&lt;p&gt;Now the countries template, we set up to display the countries' data we need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;// src/app/countries/countries.component.html
@if &lt;span class="o"&gt;(&lt;/span&gt;data&lt;span class="p"&gt;;&lt;/span&gt; as countries&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"grid"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  @for &lt;span class="o"&gt;(&lt;/span&gt;country of countries&lt;span class="p"&gt;;&lt;/span&gt; track country.name&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"card"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &amp;lt;h3&amp;gt;&lt;span class="o"&gt;{{&lt;/span&gt; country.name &lt;span class="o"&gt;}}&lt;/span&gt;&amp;lt;/h3&amp;gt;
    &amp;lt;p&amp;gt;Currency: &lt;span class="o"&gt;{{&lt;/span&gt; country.currency &lt;span class="o"&gt;}}&lt;/span&gt;&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;Capital: &lt;span class="o"&gt;{{&lt;/span&gt; country.capital &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;"N/A"&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt;&amp;lt;/p&amp;gt;
  &amp;lt;/div&amp;gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&amp;lt;/div&amp;gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Expected Output:
&lt;/h3&gt;

&lt;p&gt;Here's how the output looks when everything is working correctly from the countries' public API based on the query setup:&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%2Fva7bo6wcfrhxk9zap6tp.jpg" 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%2Fva7bo6wcfrhxk9zap6tp.jpg" alt="Countries showing their capital and currencies" width="800" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The view shows countries their capital and currency&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Section 2: GraphQL Setup For Private API's With Authentication
&lt;/h2&gt;

&lt;p&gt;For us to access a private API, we will need an access token, and so for that, let's update or create a new config file &lt;code&gt;graphql-provider-private-api.config.ts&lt;/code&gt; with these improvements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;// src/app/config/graphql-provider-private-api.config.ts
&lt;span class="nb"&gt;export &lt;/span&gt;const apolloOptionsFactory &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  const graphqlURI &lt;span class="o"&gt;=&lt;/span&gt; environment.GRAPHQL_URI_WITH_TOKEN&lt;span class="p"&gt;;&lt;/span&gt;
  const httpLink &lt;span class="o"&gt;=&lt;/span&gt; inject&lt;span class="o"&gt;(&lt;/span&gt;HttpLink&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  const userStore &lt;span class="o"&gt;=&lt;/span&gt; inject&lt;span class="o"&gt;(&lt;/span&gt;UserStore&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  const errorLink &lt;span class="o"&gt;=&lt;/span&gt; onError&lt;span class="o"&gt;(({&lt;/span&gt; graphQLErrors, networkError &lt;span class="o"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;graphQLErrors&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      graphQLErrors.forEach&lt;span class="o"&gt;(({&lt;/span&gt; message &lt;span class="o"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        console.error&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;GraphQL error]: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;message&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;message.includes&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Bad credentials'&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
          userStore.logout&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="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;networkError&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      console.error&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;Network error]: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;networkError&lt;/span&gt;&lt;span class="p"&gt;.message&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&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="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  const authMiddleware &lt;span class="o"&gt;=&lt;/span&gt; new ApolloLink&lt;span class="o"&gt;((&lt;/span&gt;operation, forward&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    const token &lt;span class="o"&gt;=&lt;/span&gt; userStore.authData&lt;span class="o"&gt;()&lt;/span&gt;.app_token&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;token&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      console.warn&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'No token available'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;return &lt;/span&gt;forward&lt;span class="o"&gt;(&lt;/span&gt;operation&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    operation.setContext&lt;span class="o"&gt;({&lt;/span&gt;
      headers: new HttpHeaders&lt;span class="o"&gt;()&lt;/span&gt;.set&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Authorization'&lt;/span&gt;, &lt;span class="sb"&gt;`&lt;/span&gt;Bearer &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;token&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;,
    &lt;span class="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;forward&lt;span class="o"&gt;(&lt;/span&gt;operation&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  const httpLinkHandler &lt;span class="o"&gt;=&lt;/span&gt; httpLink.create&lt;span class="o"&gt;({&lt;/span&gt; uri: graphqlURI &lt;span class="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  const &lt;span class="nb"&gt;link&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; ApolloLink.from&lt;span class="o"&gt;([&lt;/span&gt;errorLink, authMiddleware, httpLinkHandler]&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;link&lt;/span&gt;,
    cache: new InMemoryCache&lt;span class="o"&gt;()&lt;/span&gt;,
    defaultOptions: &lt;span class="o"&gt;{&lt;/span&gt;
      watchQuery: &lt;span class="o"&gt;{&lt;/span&gt;
        fetchPolicy: &lt;span class="s1"&gt;'network-only'&lt;/span&gt;,
        errorPolicy: &lt;span class="s1"&gt;'all'&lt;/span&gt;,
      &lt;span class="o"&gt;}&lt;/span&gt;,
      query: &lt;span class="o"&gt;{&lt;/span&gt;
        fetchPolicy: &lt;span class="s1"&gt;'network-only'&lt;/span&gt;,
        errorPolicy: &lt;span class="s1"&gt;'all'&lt;/span&gt;,
      &lt;span class="o"&gt;}&lt;/span&gt;,
    &lt;span class="o"&gt;}&lt;/span&gt;,
  &lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nb"&gt;export &lt;/span&gt;const graphqlProviderConfig: ApplicationConfig[&lt;span class="s1"&gt;'providers'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
  Apollo,
  &lt;span class="o"&gt;{&lt;/span&gt;
    provide: APOLLO_OPTIONS,
    useFactory: apolloOptionsFactory,
  &lt;span class="o"&gt;}&lt;/span&gt;,
&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this configuration, the &lt;code&gt;apolloOptionsFactory&lt;/code&gt; constructs a secure GraphQL client through three layered operations.&lt;/p&gt;

&lt;p&gt;First, the &lt;code&gt;errorLink&lt;/code&gt; handles authentication failures by automatically logging out users when it detects invalid credentials and logs all GraphQL/network errors. &lt;/p&gt;

&lt;p&gt;Second, the &lt;code&gt;authMiddleware&lt;/code&gt; intercepts each request to inject the bearer token from UserStore into authorization headers, gracefully bypassing when no token exists. &lt;/p&gt;

&lt;p&gt;Finally, the &lt;code&gt;httpLinkHandler&lt;/code&gt; establishes the connection to the GraphQL endpoint. These links chain together through &lt;code&gt;ApolloLink.from()&lt;/code&gt;, creating a pipeline that wraps every request with authentication and error handling while maintaining consistent cache-first query policies across the application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update App Configuration
&lt;/h3&gt;

&lt;p&gt;The application configuration in &lt;code&gt;app.config.ts&lt;/code&gt; follows the same pattern as the public api setup but now imports the authentication-ready provider from the new configuration file &lt;code&gt;src/app/config/graphql-provider-private-api.config.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;// src/app/app.config.ts
&lt;span class="nb"&gt;export &lt;/span&gt;const appConfig: ApplicationConfig &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  providers: &lt;span class="o"&gt;[&lt;/span&gt;
    provideZoneChangeDetection&lt;span class="o"&gt;({&lt;/span&gt; eventCoalescing: &lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="o"&gt;})&lt;/span&gt;,
    provideRouter&lt;span class="o"&gt;(&lt;/span&gt;routes&lt;span class="o"&gt;)&lt;/span&gt;,
    provideHttpClient&lt;span class="o"&gt;()&lt;/span&gt;,
    graphqlProviderConfig,
  &lt;span class="o"&gt;]&lt;/span&gt;,
&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  State Management for Private APIs
&lt;/h3&gt;

&lt;p&gt;While the focus is on GraphQL configuration, we need a robust way to manage the authentication state for private APIs, so for that we're going to leverage the &lt;a href="https://ngrx.io/guide/signals" rel="noopener noreferrer"&gt;Signal Store&lt;/a&gt; for this implementation. &lt;/p&gt;

&lt;p&gt;Here's how we'll handle the state management:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;// src/app/store/user.store.ts
const initialState &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  authData: &lt;span class="o"&gt;{&lt;/span&gt; app_token: &lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;,
  isAuthenticated: &lt;span class="nb"&gt;false&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nb"&gt;export &lt;/span&gt;const UserStore &lt;span class="o"&gt;=&lt;/span&gt; signalStore&lt;span class="o"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;{&lt;/span&gt; providedIn: &lt;span class="s1"&gt;'root'&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;,
  withState&lt;span class="o"&gt;(&lt;/span&gt;initialState&lt;span class="o"&gt;)&lt;/span&gt;,
  withMethods&lt;span class="o"&gt;((&lt;/span&gt;store&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;({&lt;/span&gt;
    setToken&lt;span class="o"&gt;(&lt;/span&gt;token: string&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      patchState&lt;span class="o"&gt;(&lt;/span&gt;store, &lt;span class="o"&gt;{&lt;/span&gt;
        authData: &lt;span class="o"&gt;{&lt;/span&gt; app_token: token &lt;span class="o"&gt;}&lt;/span&gt;,
        isAuthenticated: &lt;span class="o"&gt;!!&lt;/span&gt;token
      &lt;span class="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      localStorage.setItem&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'github_token'&lt;/span&gt;, token&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;,
    initialize&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      const token &lt;span class="o"&gt;=&lt;/span&gt; localStorage.getItem&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'github_token'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;token&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        this.setToken&lt;span class="o"&gt;(&lt;/span&gt;token&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="o"&gt;}&lt;/span&gt;,
    &lt;span class="nb"&gt;logout&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      patchState&lt;span class="o"&gt;(&lt;/span&gt;store, initialState&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      localStorage.removeItem&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'github_token'&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="o"&gt;}))&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Authentication Flow: Login Component
&lt;/h3&gt;

&lt;p&gt;Before we can make authenticated queries, we need a way to collect and store the private api token. &lt;/p&gt;

&lt;p&gt;Here's a minimal login component that bridges our state management and GraphQL setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;// src/app/login/login.component.ts
@Component&lt;span class="o"&gt;({&lt;/span&gt;
  selector: &lt;span class="s1"&gt;'app-login'&lt;/span&gt;,
  imports: &lt;span class="o"&gt;[&lt;/span&gt;FormsModule],
  templateUrl: &lt;span class="s1"&gt;'./login.component.html'&lt;/span&gt;,
&lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;class LoginComponent &lt;span class="o"&gt;{&lt;/span&gt;
  protected token &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  private &lt;span class="nb"&gt;readonly &lt;/span&gt;userStore &lt;span class="o"&gt;=&lt;/span&gt; inject&lt;span class="o"&gt;(&lt;/span&gt;UserStore&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  private &lt;span class="nb"&gt;readonly &lt;/span&gt;router &lt;span class="o"&gt;=&lt;/span&gt; inject&lt;span class="o"&gt;(&lt;/span&gt;Router&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  login&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;this.token&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      this.userStore.setToken&lt;span class="o"&gt;(&lt;/span&gt;this.token&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      this.router.navigate&lt;span class="o"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'/profile'&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="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

// src/app/login/login.component.html
&amp;lt;div&amp;gt;
  &amp;lt;h2&amp;gt;Login with GitHub Token&amp;lt;/h2&amp;gt;
  &amp;lt;input &lt;span class="o"&gt;[(&lt;/span&gt;ngModel&lt;span class="o"&gt;)]=&lt;/span&gt;&lt;span class="s2"&gt;"token"&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"password"&lt;/span&gt; &lt;span class="nv"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"GitHub Token"&lt;/span&gt; /&amp;gt;
  &amp;lt;button &lt;span class="o"&gt;(&lt;/span&gt;click&lt;span class="o"&gt;)=&lt;/span&gt;&lt;span class="s2"&gt;"login()"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;Login&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Making Authenticated GraphQL Queries
&lt;/h3&gt;

&lt;p&gt;Now that we have our authentication flow done, let's set up a query from a private &lt;a href="https://api.github.com/graphql" rel="noopener noreferrer"&gt;GitHub's GraphQL API&lt;/a&gt; to get a user's GitHub profile details.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;// src/app/graphql/queries.ts
&lt;span class="nb"&gt;export &lt;/span&gt;const FETCH_USER &lt;span class="o"&gt;=&lt;/span&gt; gql&lt;span class="sb"&gt;`&lt;/span&gt;
  query &lt;span class="o"&gt;{&lt;/span&gt;
    viewer &lt;span class="o"&gt;{&lt;/span&gt;
      login
      name
      email
      bio
      avatarUrl
      company
      location
      websiteUrl
      repositories&lt;span class="o"&gt;(&lt;/span&gt;first: 5, orderBy: &lt;span class="o"&gt;{&lt;/span&gt; field: UPDATED_AT, direction: DESC &lt;span class="o"&gt;})&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        nodes &lt;span class="o"&gt;{&lt;/span&gt;
          name
          description
          url
          createdAt
          updatedAt
          isPrivate
        &lt;span class="o"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Implementing the Authenticated Component
&lt;/h3&gt;

&lt;p&gt;With our GraphQL query ready, let's examine the component that brings everything together. This &lt;code&gt;AuthenticatedComponent&lt;/code&gt; demonstrates:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Token verification before making requests
&lt;/li&gt;
&lt;li&gt;Proper loading and error states
&lt;/li&gt;
&lt;li&gt;Type-safe data handling
&lt;/li&gt;
&lt;li&gt;Automatic logout on authentication failures
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;// src/app/authenticated/authenticated.component.ts
@Component&lt;span class="o"&gt;({&lt;/span&gt;
  selector: &lt;span class="s1"&gt;'app-authenticated'&lt;/span&gt;,
  standalone: &lt;span class="nb"&gt;true&lt;/span&gt;,
  imports: &lt;span class="o"&gt;[&lt;/span&gt;CommonModule],
  templateUrl: &lt;span class="s1"&gt;'./authenticated.component.html'&lt;/span&gt;
&lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;class AuthenticatedComponent &lt;span class="o"&gt;{&lt;/span&gt;
  private &lt;span class="nb"&gt;readonly &lt;/span&gt;apollo &lt;span class="o"&gt;=&lt;/span&gt; inject&lt;span class="o"&gt;(&lt;/span&gt;Apollo&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  private &lt;span class="nb"&gt;readonly &lt;/span&gt;userStore &lt;span class="o"&gt;=&lt;/span&gt; inject&lt;span class="o"&gt;(&lt;/span&gt;UserStore&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  private &lt;span class="nb"&gt;readonly &lt;/span&gt;router &lt;span class="o"&gt;=&lt;/span&gt; inject&lt;span class="o"&gt;(&lt;/span&gt;Router&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  userData: GitHubUser | null &lt;span class="o"&gt;=&lt;/span&gt; null&lt;span class="p"&gt;;&lt;/span&gt;
  error: string | null &lt;span class="o"&gt;=&lt;/span&gt; null&lt;span class="p"&gt;;&lt;/span&gt;
  loading &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  ngOnInit&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    this.userStore.initialize&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    this.fetchUserData&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  protected fetchUserData&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;this.userStore.isAuthenticated&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      this.router.navigate&lt;span class="o"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'/login'&lt;/span&gt;&lt;span class="o"&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;}&lt;/span&gt;

    this.loading &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    this.error &lt;span class="o"&gt;=&lt;/span&gt; null&lt;span class="p"&gt;;&lt;/span&gt;

    this.apollo.query&amp;lt;GitHubUserResponse&amp;gt;&lt;span class="o"&gt;({&lt;/span&gt;
      query: FETCH_USER,
    &lt;span class="o"&gt;})&lt;/span&gt;.subscribe&lt;span class="o"&gt;({&lt;/span&gt;
      next: &lt;span class="o"&gt;({&lt;/span&gt; data &lt;span class="o"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        this.userData &lt;span class="o"&gt;=&lt;/span&gt; data.viewer&lt;span class="p"&gt;;&lt;/span&gt;
        this.loading &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;,
      error: &lt;span class="o"&gt;(&lt;/span&gt;err&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        this.error &lt;span class="o"&gt;=&lt;/span&gt; err.message&lt;span class="p"&gt;;&lt;/span&gt;
        this.loading &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        this.userStore.logout&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="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Displaying the Data
&lt;/h3&gt;

&lt;p&gt;The template uses Angular's new @if syntax for conditional rendering:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;// src/app/authenticated/authenticated.component.html
@if &lt;span class="o"&gt;(&lt;/span&gt;loading&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&amp;lt;p&amp;gt;Loading GitHub profile...&amp;lt;/p&amp;gt;

&lt;span class="o"&gt;}&lt;/span&gt; @if &lt;span class="o"&gt;(&lt;/span&gt;error&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&amp;lt;p &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;Sorry something went wrong&amp;lt;/p&amp;gt;
&lt;span class="o"&gt;}&lt;/span&gt; @if &lt;span class="o"&gt;(&lt;/span&gt;userData&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

&amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"profile-header"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &amp;lt;img &lt;span class="o"&gt;[&lt;/span&gt;src]&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"userData.avatarUrl"&lt;/span&gt; &lt;span class="nv"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"100px"&lt;/span&gt; &lt;span class="nv"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Avatar"&lt;/span&gt; &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"avatar"&lt;/span&gt; /&amp;gt;
  &amp;lt;h2&amp;gt;&lt;span class="o"&gt;{{&lt;/span&gt; userData.name &lt;span class="o"&gt;}}&lt;/span&gt;&amp;lt;/h2&amp;gt;
  &amp;lt;p&amp;gt;&lt;span class="o"&gt;{{&lt;/span&gt; userData.login &lt;span class="o"&gt;}}&lt;/span&gt;&amp;lt;/p&amp;gt;
  &amp;lt;p&amp;gt;&lt;span class="o"&gt;{{&lt;/span&gt; userData.bio &lt;span class="o"&gt;}}&lt;/span&gt;&amp;lt;/p&amp;gt;
  &amp;lt;p &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="nv"&gt;ngIf&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"userData.company"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;Works at &lt;span class="o"&gt;{{&lt;/span&gt; userData.company &lt;span class="o"&gt;}}&lt;/span&gt;&amp;lt;/p&amp;gt;
  &amp;lt;p &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="nv"&gt;ngIf&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"userData.location"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;📍 &lt;span class="o"&gt;{{&lt;/span&gt; userData.location &lt;span class="o"&gt;}}&lt;/span&gt;&amp;lt;/p&amp;gt;
  &amp;lt;p &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="nv"&gt;ngIf&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"userData.websiteUrl"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &amp;lt;a &lt;span class="o"&gt;[&lt;/span&gt;href]&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"userData.websiteUrl"&lt;/span&gt; &lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"_blank"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;{{&lt;/span&gt;
      userData.websiteUrl
    &lt;span class="o"&gt;}}&lt;/span&gt;&amp;lt;/a&amp;gt;
  &amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;h3&amp;gt;Recent Repositories&amp;lt;/h3&amp;gt;
&amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"repositories"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"repo-card"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    @for &lt;span class="o"&gt;(&lt;/span&gt;repo of userData.repositories.nodes&lt;span class="p"&gt;;&lt;/span&gt; track repo.name&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &amp;lt;h4&amp;gt;
      &amp;lt;a &lt;span class="o"&gt;[&lt;/span&gt;href]&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"repo.url"&lt;/span&gt; &lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"_blank"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;{{&lt;/span&gt; repo.name &lt;span class="o"&gt;}}&lt;/span&gt;&amp;lt;/a&amp;gt;
      @if &lt;span class="o"&gt;(&lt;/span&gt;repo.isPrivate&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &amp;lt;span &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"private-badge"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;Private&amp;lt;/span&amp;gt;
      &lt;span class="o"&gt;}&lt;/span&gt;
    &amp;lt;/h4&amp;gt;

    @if &lt;span class="o"&gt;(&lt;/span&gt;repo.description&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &amp;lt;p&amp;gt;&lt;span class="o"&gt;{{&lt;/span&gt; repo.description &lt;span class="o"&gt;}}&lt;/span&gt;&amp;lt;/p&amp;gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"repo-meta"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &amp;lt;span&amp;gt;Updated &lt;span class="o"&gt;{{&lt;/span&gt; repo.updatedAt | &lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt;&amp;lt;/span&amp;gt;
    &amp;lt;/div&amp;gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After implementing these components, our Angular application now successfully:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authenticates with GitHub's GraphQL API
&lt;/li&gt;
&lt;li&gt;Fetches protected user data
&lt;/li&gt;
&lt;li&gt;Displays user profile with repository information
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's how the final output looks when everything is working correctly:&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%2Fb98mxu96hapb1tnyosfg.jpg" 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%2Fb98mxu96hapb1tnyosfg.jpg" alt="Authenticated GitHub Profile Display" width="800" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The authenticated view showing user profile and recent repositories&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Takeaways&lt;/strong&gt;: &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;No Auth Setup&lt;/th&gt;
&lt;th&gt;With Auth Setup&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Configuration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Simple &lt;code&gt;HttpLink&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Auth middleware + error handling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;State Management&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;signal store&lt;/code&gt; with token persistence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Error Handling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Basic console logging&lt;/td&gt;
&lt;td&gt;Automatic token cleanup + user feedback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data Freshness&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;cache-first&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;network-only&lt;/code&gt; for sensitive data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Public API only&lt;/td&gt;
&lt;td&gt;Token in headers + localStorage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Persistence&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No token storage&lt;/td&gt;
&lt;td&gt;Automatic token rehydration on app start&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;UI Integration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Simple data display&lt;/td&gt;
&lt;td&gt;Loading states + error messages&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;In this tutorial, we learned how to setup and make use of GraphQL public apis and private apis(requires authentication) in an angular application.&lt;/p&gt;

&lt;p&gt;By understanding this setup, the same patterns can be adapted to work with any GraphQL API in Angular.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explore the complete project&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
🔗 &lt;a href="https://github.com/KingsleyAmankwah/angular-graphql-demo" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Connect with me&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
💼 &lt;a href="https://www.linkedin.com/in/kingsleyamankwah/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;br&gt;&lt;br&gt;
🐦 &lt;a href="https://x.com/IAmKingsley001" rel="noopener noreferrer"&gt;X (Twitter)&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;Happy coding! 🚀&lt;/p&gt;

</description>
      <category>angular</category>
      <category>graphql</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>A Comprehensive Guide to React Hooks: Simplifying State and Side Effects</title>
      <dc:creator>Kingsley Amankwah</dc:creator>
      <pubDate>Wed, 14 Jun 2023 04:30:56 +0000</pubDate>
      <link>https://dev.to/kingsley/a-comprehensive-guide-to-react-hooks-simplifying-state-and-side-effects-39f3</link>
      <guid>https://dev.to/kingsley/a-comprehensive-guide-to-react-hooks-simplifying-state-and-side-effects-39f3</guid>
      <description>&lt;h1&gt;
  
  
  Introduction to React Hooks:
&lt;/h1&gt;

&lt;p&gt;React Hooks have revolutionized the way we write React components by providing a simpler and more elegant approach to managing state and handling side effects. In this article, we will explore the core hooks in React and dive into custom hooks, advanced hook patterns, and best practices. Let's get started!&lt;/p&gt;

&lt;h1&gt;
  
  
  Benefits of using Hooks over class components
&lt;/h1&gt;

&lt;p&gt;Before the introduction of React Hooks, managing state and side effects in functional components was challenging. Class components required complex lifecycle methods and often led to verbose and convoluted code. React Hooks solve these problems by offering a more intuitive and functional approach. With Hooks, we can write cleaner, more readable code and enjoy benefits such as improved reusability, code organization, and performance optimizations.&lt;/p&gt;

&lt;h1&gt;
  
  
  Understanding the Core Hooks:
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. useState Hook:
&lt;/h2&gt;

&lt;p&gt;The useState hook allows us to introduce stateful logic into functional components. It takes an initial state value as an argument and returns an array with the current state value and a function to update the state. Let's see an example of creating a counter component using useState:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;Count: {count}&amp;lt;/p&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setCount(count + 1)}&amp;gt;Increment&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code, we initialize the count state to &lt;code&gt;0&lt;/code&gt; using useState. The count value is displayed, and the &lt;code&gt;setCount&lt;/code&gt; function is used to update the count when the button is clicked.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. useEffect Hook
&lt;/h2&gt;

&lt;p&gt;The useEffect hook enables us to perform side effects in functional components, such as fetching data from an API, subscribing to events, or manipulating the DOM. It accepts a callback function and an optional dependency array to control when the effect runs. Let's see an example of fetching data from an API using useEffect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState, useEffect } from 'react';

function DataFetcher() {
  const [data, setData] = useState([]);

  useEffect(() =&amp;gt; {
    fetch('https://api.example.com/data')
      .then(response =&amp;gt; response.json())
      .then(data =&amp;gt; setData(data));
  }, []);

  return (
    &amp;lt;div&amp;gt;
      {data.map(item =&amp;gt; (
        &amp;lt;p key={item.id}&amp;gt;{item.name}&amp;lt;/p&amp;gt;
      ))}
    &amp;lt;/div&amp;gt;
  );
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code, we use &lt;code&gt;useEffect&lt;/code&gt; to fetch data from an API when the component mounts. The fetched data is stored in the state using the &lt;code&gt;setData&lt;/code&gt; function, and it is rendered in the component.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. useContext Hook
&lt;/h2&gt;

&lt;p&gt;The useContext hook provides a way to access shared state or data without &lt;a href="https://dev.to/kingsley/react-props-in-action-building-flexible-and-reusable-components-4c2l"&gt;prop drilling&lt;/a&gt; . It allows us to create a context and consume it in any component within the context provider. Let's see an example of creating a theme-switching component using useContext:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useContext } from 'react';

const ThemeContext = React.createContext('light');

function ThemeSwitcher() {
  const theme = useContext(ThemeContext);

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;Current theme: {theme}&amp;lt;/p&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; console.log('Switch theme')}&amp;gt;Switch Theme&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, we create a ThemeContext using &lt;code&gt;React.createContext&lt;/code&gt; and provide a default value of &lt;code&gt;'light'&lt;/code&gt;. The useContext hook is used in the ThemeSwitcher component to access the current theme value. When the button is clicked, it triggers a theme switch action.&lt;/p&gt;

&lt;h1&gt;
  
  
  Custom Hooks: Reusability and Abstraction:
&lt;/h1&gt;

&lt;p&gt;Custom hooks are a powerful concept in React that allows us to extract and share stateful and reusable logic across multiple components. They provide a way to abstract complex logic into reusable functions. By creating custom hooks, we can enhance code reusability and make our components more modular and maintainable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a form validation hook:
&lt;/h2&gt;

&lt;p&gt;Let's build a custom hook for a form validation. The hook will handle the validation logic and return the validation state and functions to update the form values and trigger validation.&lt;/p&gt;

&lt;h3&gt;
  
  
  useFormValidation Custom Hook
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState } from 'react';

function useFormValidation(initialState, validate) {
  const [values, setValues] = useState(initialState);
  const [errors, setErrors] = useState({});
  const [isSubmitting, setSubmitting] = useState(false);

  const handleChange = event =&amp;gt; {
    setValues({
      ...values,
      [event.target.name]: event.target.value
    });
  };

  const handleSubmit = event =&amp;gt; {
    event.preventDefault();
    setErrors(validate(values));
    setSubmitting(true);
  };

  return { values, errors, isSubmitting, handleChange, handleSubmit };
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explanation:&lt;br&gt;
The &lt;code&gt;useFormValidation&lt;/code&gt; custom hook handles the state and logic for form validation. It takes in &lt;code&gt;initialState&lt;/code&gt;, which is an object representing the initial form values, and validate, which is a function for validating the form values. It returns an object with &lt;code&gt;values&lt;/code&gt;, &lt;code&gt;errors&lt;/code&gt;, &lt;code&gt;isSubmitting&lt;/code&gt;, &lt;code&gt;handleChange&lt;/code&gt;, and &lt;code&gt;handleSubmit&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;values:&lt;/code&gt;&lt;/strong&gt; represents the current form values.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;errors:&lt;/code&gt;&lt;/strong&gt; holds any validation errors for the form.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;isSubmitting:&lt;/code&gt;&lt;/strong&gt; indicates whether the form is being submitted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;handleChange:&lt;/code&gt;&lt;/strong&gt; is a function that updates the form values as the user types.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;handleSubmit:&lt;/code&gt;&lt;/strong&gt; is a function that handles the form submission, triggers validation, and sets the errors and submitting state.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  LoginForm Component
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
function validateLoginForm(values) {
  let errors = {};

    if (!values.email) {
    errors.email = 'Email is required';
  }

    if (!values.password) {
    errors.password = 'Password is required';
  } else if (values.password.length &amp;lt; 6) {
    errors.password = 'Password must be at least 6 characters long';
  }

  return errors;
}

function LoginForm() {
  const { values, errors, isSubmitting, handleChange, handleSubmit } = useFormValidation(
    { email: '', password: '' },
    validateLoginForm
  );

  return (
    &amp;lt;form onSubmit={handleSubmit}&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;label htmlFor="email"&amp;gt;Email&amp;lt;/label&amp;gt;
        &amp;lt;input
          type="email"
          id="email"
          name="email"
          value={values.email}
          onChange={handleChange}
        /&amp;gt;
        {errors.email &amp;amp;&amp;amp; &amp;lt;span&amp;gt;{errors.email}&amp;lt;/span&amp;gt;}
      &amp;lt;/div&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;label htmlFor="password"&amp;gt;Password&amp;lt;/label&amp;gt;
        &amp;lt;input
          type="password"
          id="password"
          name="password"
          value={values.password}
          onChange={handleChange}
        /&amp;gt;
        {errors.password &amp;amp;&amp;amp; &amp;lt;span&amp;gt;{errors.password}&amp;lt;/span&amp;gt;}
      &amp;lt;/div&amp;gt;
      &amp;lt;button type="submit" disabled={isSubmitting}&amp;gt;
        Submit
      &amp;lt;/button&amp;gt;
    &amp;lt;/form&amp;gt;
  );
}

export default LoginForm;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Explanation:&lt;br&gt;
The &lt;code&gt;LoginForm&lt;/code&gt; component utilizes the &lt;code&gt;useFormValidation&lt;/code&gt; custom hook to handle the form's state and validation. It also includes an example validation function, &lt;code&gt;validateLoginForm&lt;/code&gt;, which validates the email and password fields.&lt;/p&gt;

&lt;p&gt;Inside the component, we destructure the values, errors, isSubmitting, handleChange, and handleSubmit from the &lt;code&gt;useFormValidation&lt;/code&gt; hook. These values and functions are then used within the JSX to render the form.&lt;/p&gt;
&lt;h1&gt;
  
  
  Advanced Hook Patterns:
&lt;/h1&gt;
&lt;h2&gt;
  
  
  1. useReducer Hook
&lt;/h2&gt;

&lt;p&gt;The useReducer hook is an alternative to useState when managing more complex state that involves multiple actions. It follows the Redux pattern of managing state with reducers and actions. Let's see an example of implementing a todo list using useReducer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useReducer } from 'react';

function todoReducer(state, action) {
  switch (action.type) {
    case 'ADD_TODO':
      return [...state, { id: Date.now(), text: action.payload, completed: false }];
    case 'TOGGLE_TODO':
      return state.map(todo =&amp;gt; (todo.id === action.payload ? { ...todo, completed: !todo.completed } : todo));
    case 'REMOVE_TODO':
      return state.filter(todo =&amp;gt; todo.id !== action.payload);
    default:
      return state;
  }
}

function TodoList() {
  const [todos, dispatch] = useReducer(todoReducer, []);

  const handleAddTodo = () =&amp;gt; {
    const todoText = // Get todo text from input field
    dispatch({ type: 'ADD_TODO', payload: todoText });
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;input type="text" placeholder="Enter todo" /&amp;gt;
      &amp;lt;button onClick={handleAddTodo}&amp;gt;Add Todo&amp;lt;/button&amp;gt;

      &amp;lt;ul&amp;gt;
        {todos.map(todo =&amp;gt; (
          &amp;lt;li key={todo.id}&amp;gt;
            &amp;lt;span&amp;gt;{todo.text}&amp;lt;/span&amp;gt;
            &amp;lt;button onClick={() =&amp;gt; dispatch({ type: 'TOGGLE_TODO', payload: todo.id })}&amp;gt;
              {todo.completed ? 'Mark Incomplete' : 'Mark Complete'}
            &amp;lt;/button&amp;gt;
            &amp;lt;button onClick={() =&amp;gt; dispatch({ type: 'REMOVE_TODO', payload: todo.id })}&amp;gt;Remove&amp;lt;/button&amp;gt;
          &amp;lt;/li&amp;gt;
        ))}
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we have a &lt;code&gt;todoReducer&lt;/code&gt; function that takes in the current state and an action, and based on the action type, it performs the necessary updates to the state. The reducer function handles three types of actions: adding a new todo, toggling the completion status of a todo, and removing a todo.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;TodoList&lt;/code&gt; component utilizes the &lt;code&gt;useReducer&lt;/code&gt; hook by calling it with the &lt;code&gt;todoReducer&lt;/code&gt; function and an initial state of an empty array &lt;code&gt;[]&lt;/code&gt;. The hook returns the current state (&lt;code&gt;todos&lt;/code&gt;) and a &lt;code&gt;dispatch&lt;/code&gt; function that we use to send actions to the reducer.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;handleAddTodo&lt;/code&gt; function is called when the "Add Todo" button is clicked. It retrieves the todo text from an input field (which is not included in this code snippet) and dispatches an action of type '&lt;code&gt;ADD_TODO&lt;/code&gt;' with the payload as the todo text. The reducer function then adds a new todo object to the state array, including an auto-generated ID, the todo text, and a default completion status of &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;TodoList&lt;/code&gt; component renders an input field and a button for adding new todos. Below that, it renders a list of todos using the &lt;code&gt;todos.map&lt;/code&gt; function. Each todo is rendered as an &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt; element with its text displayed. Additionally, there are two buttons for each todo: one for toggling the completion status and another for removing the todo. When these buttons are clicked, corresponding actions are dispatched to the reducer to update the state accordingly.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. useRef Hook
&lt;/h2&gt;

&lt;p&gt;Accessing and persisting values across renders:&lt;br&gt;
The useRef hook provides a way to persist values across renders without triggering a re-render. It can also be used to access DOM elements directly. Let's see an example of implementing an input field with useRef:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useRef } from 'react';

function InputWithFocus() {
  const inputRef = useRef(null);

  const handleClick = () =&amp;gt; {
    inputRef.current.focus();
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;input ref={inputRef} type="text" /&amp;gt;
      &amp;lt;button onClick={handleClick}&amp;gt;Focus Input&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code, the &lt;code&gt;inputRef&lt;/code&gt; is created using &lt;code&gt;useRef&lt;/code&gt; and assigned to the input element's ref attribute. When the button is clicked, the &lt;code&gt;handleClick&lt;/code&gt; function is triggered, which focuses the input element using the ref's current property.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;React Hooks have transformed the way we write React components, offering a more streamlined and functional approach to managing state and handling side effects. By leveraging core hooks like useState, useEffect, and useContext, we can simplify our code and enhance reusability. Additionally, custom hooks and advanced hook patterns like useReducer and useRef provide powerful tools for building complex and optimized components.&lt;/p&gt;

&lt;p&gt;As you embark on your React journey, I encourage you to explore and experiment with React Hooks in your projects. Their flexibility, simplicity, and performance benefits will undoubtedly elevate your development experience. Happy coding!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>react</category>
    </item>
    <item>
      <title>React Props In Action: Building Flexible and Reusable Components...</title>
      <dc:creator>Kingsley Amankwah</dc:creator>
      <pubDate>Mon, 15 May 2023 08:19:48 +0000</pubDate>
      <link>https://dev.to/kingsley/react-props-in-action-building-flexible-and-reusable-components-4c2l</link>
      <guid>https://dev.to/kingsley/react-props-in-action-building-flexible-and-reusable-components-4c2l</guid>
      <description>&lt;p&gt;React props play a crucial role in building reusable and flexible components. They allow you to pass data from a parent component to its child components, making it easier to configure and customize them according to specific requirements. In this article, we'll dive into the world of React props, exploring how to pass and use props effectively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to React Props
&lt;/h2&gt;

&lt;p&gt;At its core, React is a component-based library that encourages the composition of reusable UI elements. Props, short for "properties," enable you to pass data and functions between components. By using props, you can create dynamic and interactive components that can be easily reused in different parts of your application.&lt;/p&gt;

&lt;p&gt;It's important to note that props are read-only, meaning they cannot be modified within the child component. This immutability ensures data consistency and helps maintain a unidirectional data flow in React.&lt;/p&gt;

&lt;h2&gt;
  
  
  Passing Props
&lt;/h2&gt;

&lt;p&gt;Passing props from a parent component to a child component is straightforward. In JSX, you can provide props as attributes when rendering a component. Let's consider a simple example where we pass a prop called &lt;code&gt;name&lt;/code&gt; to a child component called &lt;code&gt;Greeting&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ParentComponent.js
import React from 'react';
import Greeting from './Greeting';

const ParentComponent = () =&amp;gt; {
  const name = 'Alice';

  return &amp;lt;Greeting name={name} /&amp;gt;;
};

export default ParentComponent;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;ParentComponent&lt;/code&gt;, we define the &lt;code&gt;name&lt;/code&gt; variable and pass it as the &lt;code&gt;name&lt;/code&gt; prop to the &lt;code&gt;Greeting&lt;/code&gt; component. The child component can now access this prop and utilize its value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accessing Props
&lt;/h2&gt;

&lt;p&gt;To access props within a child component, you can use the props object in functional components or this.props in class components. Let's update the Greeting component to display the received prop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Greeting.js
import React from 'react';

const Greeting = (props) =&amp;gt; {
  return &amp;lt;h1&amp;gt;Hello, {props.name}!&amp;lt;/h1&amp;gt;;
};

export default Greeting;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;Greeting&lt;/code&gt; component, we access the &lt;code&gt;name&lt;/code&gt; prop using &lt;code&gt;props.name&lt;/code&gt; and display it within an &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; element. The output will be "Hello, Alice!" based on the prop value passed from the parent component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Default Props
&lt;/h2&gt;

&lt;p&gt;Sometimes, you may want to set default values for props in case they are not explicitly provided by the parent component. This ensures that your component can gracefully handle missing or undefined props. To define default props, you can utilize the &lt;code&gt;defaultProps&lt;/code&gt; property in functional or class components. Consider the following example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Greeting.js
import React from 'react';

const Greeting = (props) =&amp;gt; {
  return &amp;lt;h1&amp;gt;Hello, {props.name}!&amp;lt;/h1&amp;gt;;
};

Greeting.defaultProps = {
  name: 'Stranger',
};

export default Greeting;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we've defined a default prop &lt;code&gt;name&lt;/code&gt; with the value "Stranger" for the &lt;code&gt;Greeting&lt;/code&gt; component. If the parent component doesn't provide the &lt;code&gt;name&lt;/code&gt; prop, the Greeting component will display "Hello, Stranger!" by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prop Types
&lt;/h2&gt;

&lt;p&gt;While React itself doesn't enforce strict prop types, it's good practice to specify the expected types of props for validation and documentation purposes. The &lt;code&gt;prop-types&lt;/code&gt; library provides an easy way to define prop types. Let's enhance our &lt;code&gt;Greeting&lt;/code&gt; component with prop types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Greeting.js
import React from 'react';
import PropTypes from 'prop-types';

const Greeting = (props) =&amp;gt; {
  return &amp;lt;h1&amp;gt;Hello, {props.name}!&amp;lt;/h1&amp;gt;;
};

Greeting.propTypes = {
  name: PropTypes.string.isRequired,
};

export default Greeting;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this updated code, we import &lt;code&gt;PropTypes&lt;/code&gt; from the &lt;code&gt;prop-types&lt;/code&gt; library. By setting &lt;code&gt;Greeting.propTypes&lt;/code&gt;, we specify that the &lt;code&gt;name&lt;/code&gt; prop should be a required string. If the parent component fails to provide the &lt;code&gt;name&lt;/code&gt; prop or if it's not a string, React will issue a warning in the browser console.&lt;/p&gt;

&lt;p&gt;Using prop types helps catch bugs early on and provides documentation for other developers who use or maintain your components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prop Drilling and Context API
&lt;/h2&gt;

&lt;p&gt;As your React application grows, you might encounter a situation called &lt;code&gt;prop drilling&lt;/code&gt;. Prop drilling occurs when you need to pass props through multiple levels of components, even if some intermediate components don't actually use those props. This can lead to verbose and less maintainable code.&lt;/p&gt;

&lt;p&gt;To avoid prop drilling, you can use the Context API, which provides a way to create a centralized data store accessible to all components within a specified context. By utilizing the Context API, you can access and update the data without passing props explicitly.&lt;/p&gt;

&lt;p&gt;While discussing the Context API in detail is beyond the scope of this article, it's worth mentioning that it's particularly useful for global state management in larger applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices and Considerations
&lt;/h2&gt;

&lt;p&gt;When working with React props, it's essential to follow some best practices for better code organization and maintainability:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep props minimal and focused: Pass only the necessary props to components, keeping them focused on their specific responsibilities.&lt;/li&gt;
&lt;li&gt;Avoid unnecessary nesting: Try to avoid excessive levels of component nesting, as it can lead to prop drilling and make the code harder to maintain.&lt;/li&gt;
&lt;li&gt;Use default props: Set default values for props using &lt;code&gt;defaultProps&lt;/code&gt; to ensure your component behaves gracefully when certain props are not provided.&lt;/li&gt;
&lt;li&gt;Define prop types: Specify prop types using &lt;code&gt;PropTypes&lt;/code&gt; to validate the expected types of props and catch potential errors early on.&lt;/li&gt;
&lt;li&gt;Proper prop naming: Choose meaningful names for your props that accurately describe their purpose and make your code more readable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By following these practices, you can write more maintainable, reusable, and understandable React components.&lt;/p&gt;

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

&lt;p&gt;React props are a powerful tool for passing and using data between components. They enable you to build flexible and reusable UI components that can be easily configured and customized according to different requirements. By understanding how to pass and access props, set default values, define prop types, and consider best practices, you can leverage the full potential of React props in your applications.&lt;/p&gt;

&lt;p&gt;Remember to keep your components focused, use default props and prop types for better code maintainability, and consider leveraging the Context API to avoid prop drilling. With these skills and practices in your toolkit, you'll be well-equipped to create robust and efficient React applications.&lt;/p&gt;

&lt;p&gt;Happy coding with React props!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>react</category>
      <category>programming</category>
    </item>
    <item>
      <title>MLOps: Best Practices for Deploying Machine Learning Models</title>
      <dc:creator>Kingsley Amankwah</dc:creator>
      <pubDate>Sat, 22 Apr 2023 16:08:43 +0000</pubDate>
      <link>https://dev.to/kingsley/mlops-best-practices-for-deploying-machine-learning-models-4lcc</link>
      <guid>https://dev.to/kingsley/mlops-best-practices-for-deploying-machine-learning-models-4lcc</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;Machine learning models have been widely adopted in various industries to automate processes and improve decision-making. However, deploying machine learning models can be a challenging task, especially when it comes to integrating them into existing software systems. This is where MLOps comes in.&lt;/p&gt;

&lt;p&gt;MLOps is a set of best practices that aims to streamline the deployment and management of machine learning models throughout their lifecycle. It combines the best practices of software development and data science to ensure that machine learning models are deployed and managed efficiently and effectively.&lt;/p&gt;

&lt;p&gt;In this blog post, we will discuss some of the best practices for deploying machine learning models.&lt;/p&gt;

&lt;h2&gt;
  
  
  Continuous Integration and Continuous Deployment (CI/CD)
&lt;/h2&gt;

&lt;p&gt;Continuous Integration and Continuous Deployment (CI/CD) is a set of practices that automate the process of building, testing, and deploying software changes. CI/CD is widely used in software development, and it can also be applied to machine learning model deployment. The goal of CI/CD is to ensure that changes to the machine learning model are thoroughly tested and integrated into the production environment as quickly and safely as possible.&lt;/p&gt;

&lt;p&gt;This can be achieved by using tools such as Git for version control, Jenkins for continuous integration, and Kubernetes for container orchestration. By automating the process of building, testing, and deploying machine learning models, CI/CD reduces the risk of errors and ensures that the models are deployed efficiently and effectively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring and Logging
&lt;/h2&gt;

&lt;p&gt;Monitoring and logging are critical components of MLOps. Monitoring allows you to track the performance of the machine learning model in production and detect any issues that may arise. Logging, on the other hand, allows you to record important events and data about the machine learning model, such as input/output data, errors, and performance metrics.&lt;/p&gt;

&lt;p&gt;By monitoring and logging the machine learning model, you can quickly identify and resolve any issues that may arise in production. This can be achieved by using tools such as Prometheus for monitoring and ELK stack for logging. By monitoring and logging machine learning models, you can ensure that they are performing optimally and that any issues are detected and resolved quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Model Versioning
&lt;/h2&gt;

&lt;p&gt;Model versioning is another important aspect of MLOps. Machine learning models are constantly evolving, and it's crucial to keep track of the changes made to the model over time. Model versioning allows you to keep a record of all the changes made to the machine learning model and the data used to train the model.&lt;/p&gt;

&lt;p&gt;This can be achieved by using tools such as GitHub for version control and DVC for data versioning. By keeping track of the changes made to machine learning models, you can ensure that they are reproducible and that any changes made to the model can be tracked and reverted if necessary.&lt;/p&gt;

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

&lt;p&gt;Deploying machine learning models can be challenging, but MLOps provides a set of best practices to streamline the deployment and management of machine learning models throughout their lifecycle. In this blog post, we discussed some of the best practices for deploying machine learning models, including continuous integration and continuous deployment, monitoring and logging, and model versioning.&lt;/p&gt;

&lt;p&gt;By following these best practices, you can ensure that your machine learning models are deployed and managed efficiently and effectively, reducing the risk of errors and ensuring that they are performing optimally in production. If you want to improve your machine learning models and get the most out of them, adopting MLOps is the way to go.&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>devops</category>
    </item>
    <item>
      <title>Building a Real-Time Chat App with Node.js and Socket.io</title>
      <dc:creator>Kingsley Amankwah</dc:creator>
      <pubDate>Thu, 13 Apr 2023 08:43:18 +0000</pubDate>
      <link>https://dev.to/kingsley/building-a-real-time-chat-app-with-nodejs-and-socketio-320n</link>
      <guid>https://dev.to/kingsley/building-a-real-time-chat-app-with-nodejs-and-socketio-320n</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;Chat applications are one of the most popular ways to communicate. If you are interested in building a chat application, you are in the right place. In this tutorial, we will build a real-time chat app using Node.js and &lt;a href="http://socket.io/" rel="noopener noreferrer"&gt;Socket.io&lt;/a&gt;. We will explain the basic concepts of Node.js and Socket.io and guide you through the process of building this application from scratch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Node.js
&lt;/h2&gt;

&lt;p&gt;Node.js is an open-source, cross-platform, server-side JavaScript runtime environment built on Chrome's V8 JavaScript engine. It allows developers to run JavaScript on the server side, which means that you can use the same language for both the client-side and server-side of your application. Node.js is lightweight and fast, making it an ideal choice for building real-time applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="http://socket.io/" rel="noopener noreferrer"&gt;Socket.io&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Socket.io is a JavaScript library that enables real-time, bidirectional, and event-based communication between the client and the server. It is built on top of the WebSockets API and provides a simple and easy-to-use interface for building real-time applications. Socket.io supports multiple transport protocols, including WebSocket, HTTP long-polling, and HTTP streaming, which makes it a reliable and robust solution for real-time communication.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step-by-Step Guide
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Set up the Node.js environment on your machine.
&lt;/h3&gt;

&lt;p&gt;First, you need to install Node.js on your machine. You can download the latest version of Node.js from the official website. Once you have downloaded and installed Node.js, you can verify the installation by running the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node -v

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command should return the version number of Node.js that you have installed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Create a new Node.js project and initialize a package.json file using npm.
&lt;/h3&gt;

&lt;p&gt;Now let's create a new Node.js project and initialize a package.json file using npm. A package.json file is a file that contains metadata about your project, such as the name, version, description, dependencies, and scripts.&lt;/p&gt;

&lt;p&gt;To create a new Node.js project, run the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir chat-app
cd chat-app
npm init -y

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;mkdir&lt;/code&gt; command creates a new directory called &lt;code&gt;chat-app&lt;/code&gt;, and the &lt;code&gt;cd&lt;/code&gt; command changes your current working directory to the &lt;code&gt;chat-app&lt;/code&gt; directory. The &lt;code&gt;npm init&lt;/code&gt; command initializes a new package.json file with default values. The &lt;code&gt;-y&lt;/code&gt; flag skips the interactive prompts and uses default values for all fields.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Install the Socket.io library using npm.
&lt;/h3&gt;

&lt;p&gt;Next, you need to install the &lt;a href="http://socket.io/" rel="noopener noreferrer"&gt;Socket.io&lt;/a&gt; library using npm (Node Package Manager). npm is a package manager for Node.js that allows you to install and manage third-party packages and libraries.&lt;/p&gt;

&lt;p&gt;To install the Socket.io library, run the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install socket.io

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Create an index.js file and set up the server using the Express framework.
&lt;/h3&gt;

&lt;p&gt;Create an &lt;code&gt;index.js&lt;/code&gt; file and set up the server using the Express framework. Express is a popular Node.js web framework that provides a simple and easy-to-use interface for building web applications.&lt;/p&gt;

&lt;p&gt;To install express framework run the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install express
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, open the &lt;code&gt;index.js&lt;/code&gt; file in your favourite text editor and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);

app.get('/', (req, res) =&amp;gt; {
  res.send('&amp;lt;h1&amp;gt;Hello world&amp;lt;/h1&amp;gt;');
});

server.listen(3000, () =&amp;gt; {
  console.log('listening on *:3000');
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Express initializes app to be a function handler that you can supply to an HTTP server (as seen in line 4).&lt;/li&gt;
&lt;li&gt;We define a route handler &lt;code&gt;/&lt;/code&gt; that gets called when we hit our website home.&lt;/li&gt;
&lt;li&gt;We make the http server listen on port 3000.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 5: Create a client-side HTML file, which will contain the chat interface.
&lt;/h3&gt;

&lt;p&gt;Next, you need to create a client-side HTML file, which will contain the chat interface. &lt;/p&gt;

&lt;p&gt;In Unix and Unix-like operating systems (such as Linux and macOS), run the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch index.html

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Windows, you can create a new &lt;code&gt;index.html&lt;/code&gt;file in your terminal by running the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;New-Item -ItemType File index.html

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command creates a new index.html file in your current working directory. Next, open the index.html file in your favourite text editor and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;Real-Time Chat App&amp;lt;/title&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Real-Time Chat App&amp;lt;/h1&amp;gt;
    &amp;lt;ul id="messages"&amp;gt;&amp;lt;/ul&amp;gt;
    &amp;lt;form id="message-form"&amp;gt;
      &amp;lt;input type="text" name="message" placeholder="Type your message here..."&amp;gt;
      &amp;lt;button&amp;gt;Send&amp;lt;/button&amp;gt;
    &amp;lt;/form&amp;gt;
    &amp;lt;script src="/socket.io/socket.io.js"&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code creates a simple HTML page with a heading, a list of messages, a text input field, and a send button. It also includes the Socket.io client library.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Write the client-side JavaScript code to connect to the server using Socket.io to send and receive messages.
&lt;/h3&gt;

&lt;p&gt;Next, you need to write the client-side JavaScript code to connect to the server using Socket.io. To do this, you need make a &lt;code&gt;&amp;lt;script&amp;gt; &amp;lt;/script&amp;gt;&lt;/code&gt; in the html file and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const socket = io();

const messageForm = document.getElementById('message-form');
const messageInput = document.querySelector('input[name="message"]');
const messageList = document.getElementById('messages');

messageForm.addEventListener('submit', (e) =&amp;gt; {
  e.preventDefault();

  const message = messageInput.value;

  if (message.trim() === '') {
    return;
  }

  socket.emit('message', message);

  messageInput.value = '';
  messageInput.focus();
});

socket.on('message', (message) =&amp;gt; {
  const li = document.createElement('li');
  li.textContent = message;
  messageList.appendChild(li);
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code creates a new Socket.io instance, selects the message form, input field, and message list from the HTML page, and adds event listeners for form submission and incoming messages. When the user submits a message, the code retrieves the message from the input field, emits a &lt;code&gt;message&lt;/code&gt; event to the server with the message as the payload, clears the input field, and focuses on the input field. When the client receives a &lt;code&gt;message&lt;/code&gt; event from the server, the code creates a new list item element, sets its text content to the message, and appends it to the message list.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 7: Write the server-side JavaScript code to handle connections, disconnections, and incoming messages.
&lt;/h3&gt;

&lt;p&gt;Finally, you need to write the server-side JavaScript code to handle connections, disconnections, and incoming messages. To do this, you need to add the following code to the &lt;code&gt;index.js&lt;/code&gt;file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const io = require('socket.io')(http);

io.on('connection', (socket) =&amp;gt; {
  console.log('User is online.');

  socket.on('message', (message) =&amp;gt; {
    console.log(`Received message: ${message}`);
    io.emit('message', message);
  });

  socket.on('disconnect', () =&amp;gt; {
    console.log('User is offline.');
  });
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code creates a new &lt;a href="http://socket.io/" rel="noopener noreferrer"&gt;Socket.io&lt;/a&gt; instance with the http server, listens for incoming connections, and adds event listeners for incoming messages and disconnections. When a new user connects, the code logs a message to the console. When the server receives a &lt;code&gt;message&lt;/code&gt; event from a client, the code logs the message to the console and emits a &lt;code&gt;message&lt;/code&gt; event to all connected clients with the message as the payload. When a user disconnects, the code logs a message to the console.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start the app by running&lt;/strong&gt; &lt;code&gt;node index.js&lt;/code&gt; &lt;strong&gt;in the terminal&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Picture of &lt;code&gt;index.html&lt;/code&gt; code&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%2Fh1z2thrn1cpjsp5uiv30.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%2Fh1z2thrn1cpjsp5uiv30.png" alt="Client code" width="800" height="1156"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Picture of &lt;code&gt;index.js&lt;/code&gt;code&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%2Firv80mrjlhekwse412vk.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%2Firv80mrjlhekwse412vk.png" alt="Server code" width="800" height="1035"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/KingsleyAmankwah/Real-time-chat-app" rel="noopener noreferrer"&gt;Full Project On GitHub&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Finally, In this tutorial we have learnt how to build a real-time chat application using Node.js and Socket.io. We have explained the basic concepts of Node.js and Socket.io and provided a step-by-step guide for building a chat application from scratch. With this knowledge, you can now create your own real-time applications and take your development skills to the next level. Happy coding!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Building a RESTful API with Node.js and Express</title>
      <dc:creator>Kingsley Amankwah</dc:creator>
      <pubDate>Sat, 08 Apr 2023 07:42:43 +0000</pubDate>
      <link>https://dev.to/kingsley/building-a-restful-api-with-nodejs-and-express-2pp8</link>
      <guid>https://dev.to/kingsley/building-a-restful-api-with-nodejs-and-express-2pp8</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;Building an API is an essential part of developing modern applications. APIs are a way for different applications to communicate with each other, and RESTful APIs are a popular approach to building APIs that are flexible, scalable, and easy to maintain. Node.js and Express.js are two of the most popular technologies used for building RESTful APIs due to their speed, flexibility, and ease of use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Node.js and Express.js
&lt;/h2&gt;

&lt;p&gt;Before getting started, make sure Node.js and npm are installed on your machine. You can download these from the official Node.js website (&lt;a href="https://nodejs.org" rel="noopener noreferrer"&gt;https://nodejs.org&lt;/a&gt;). Then, create a new directory for your project and run &lt;code&gt;npm init&lt;/code&gt; to create a new &lt;code&gt;package.json&lt;/code&gt; file. This file will contain information about your project and its dependencies.&lt;/p&gt;

&lt;p&gt;Next, install Express.js by running &lt;code&gt;npm install express&lt;/code&gt; in your project directory. This will install the latest version of Express.js and its dependencies. After this, create a new file called &lt;code&gt;index.js&lt;/code&gt; and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) =&amp;gt; {
  res.send('Hello World!');
});

app.listen(port, () =&amp;gt; {
  console.log(`Server listening on port ${port}.`);
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code sets up a basic Express.js server that listens on port 3000 and responds with "Hello World!" when a GET request is made to the root endpoint. You can test this by running the &lt;code&gt;node index.js&lt;/code&gt; command in your terminal and opening &lt;code&gt;http://localhost:3000&lt;/code&gt;in your browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  Defining Routes and Handling Requests
&lt;/h2&gt;

&lt;p&gt;To define additional routes and handle requests, add the following code to &lt;code&gt;index.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.get('/api/users', (req, res) =&amp;gt; {
  // Return a list of users
});

app.post('/api/users', (req, res) =&amp;gt; {
  // Create a new user
});

app.put('/api/users/:id', (req, res) =&amp;gt; {
  // Update a user by ID
});

app.delete('/api/users/:id', (req, res) =&amp;gt; {
  // Delete a user by ID
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These routes handle GET, POST, PUT, and DELETE requests to the /api/users endpoint. The :id parameter in the PUT and DELETE routes allows for updating and deleting specific users by ID. You can add more routes to your API as needed, and use middleware to handle authentication, logging, and other tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting to a Database
&lt;/h2&gt;

&lt;p&gt;To store and retrieve data for your API, you'll need to connect to a database. MongoDB is a popular choice for Node.js applications, and Mongoose is a popular library for working with MongoDB. To connect to a MongoDB database using Mongoose, add the following code to &lt;code&gt;index.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/myapp');

const userSchema = new mongoose.Schema({
  name: String,
  email: String,
  password: String
});

const User = mongoose.model('User', userSchema);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code connects to a local MongoDB database called "myapp" and defines a user schema and model using Mongoose. You can use the User model to create, read, update, and delete users from your database.&lt;/p&gt;

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

&lt;p&gt;Node.js and Express.js provide a powerful and flexible platform for building RESTful APIs. With the ability to define routes, handle requests, and connect to a database, building a scalable and maintainable API is easier than ever. However, building a robust API requires careful planning, testing, and documentation. You should consider factors such as security, performance, and usability when designing your API, and follow best practices such as versioning, error handling, and caching. So, what are you waiting for? Start building your own RESTful API with Node.js and Express.js today!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>SQL Server Performance Tuning</title>
      <dc:creator>Kingsley Amankwah</dc:creator>
      <pubDate>Mon, 27 Mar 2023 17:37:24 +0000</pubDate>
      <link>https://dev.to/kingsley/sql-server-performance-tuning-5bne</link>
      <guid>https://dev.to/kingsley/sql-server-performance-tuning-5bne</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;SQL Server is a widely used database management system that helps organizations store and retrieve data. However, as the amount of data grows, the performance of the system may start to degrade. This is where performance tuning comes in. In this blog post, we will discuss SQL Server performance tuning and how it can help organizations achieve faster and more efficient data management.&lt;/p&gt;

&lt;h2&gt;
  
  
  Importance of SQL Server Performance Tuning
&lt;/h2&gt;

&lt;p&gt;SQL Server performance tuning is crucial for organizations to ensure that their database systems are running optimally. Poorly performing systems can lead to slow response times, data loss, and even system crashes. By tuning the performance of SQL Server, organizations can improve system response times, reduce downtime, and improve overall system efficiency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Techniques for SQL Server Performance Tuning
&lt;/h2&gt;

&lt;p&gt;There are several techniques that organizations can use to tune the performance of their SQL Server systems. These include:&lt;/p&gt;

&lt;h3&gt;
  
  
  Index Optimization
&lt;/h3&gt;

&lt;p&gt;Indexes are used to speed up data retrieval from SQL Server. However, poorly designed indexes can slow down the system. By optimizing the indexes, organizations can improve the performance of their SQL Server systems. This involves analyzing the existing indexes, identifying redundant or unused indexes, and creating new indexes as needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Query Optimization
&lt;/h3&gt;

&lt;p&gt;Queries are used to retrieve data from SQL Server. However, poorly written queries can lead to slow response times and degraded system performance. By optimizing the queries, organizations can improve the performance of their SQL Server systems. This involves analyzing the existing queries, identifying poorly performing queries, and rewriting or optimizing them as needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Server Configuration Optimization
&lt;/h3&gt;

&lt;p&gt;SQL Server configuration can also impact system performance. By optimizing the server configuration, organizations can improve the performance of their SQL Server systems. This involves analyzing the existing configuration, identifying configuration issues, and making changes as needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Memory Management
&lt;/h3&gt;

&lt;p&gt;SQL Server performance can be improved by managing the amount of memory used by the system. By allocating memory to the most frequently used data and processes, organizations can improve the overall performance of their SQL Server systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  CPU Optimization
&lt;/h3&gt;

&lt;p&gt;Optimizing CPU usage can improve the overall performance of SQL Server systems. This involves identifying processes that use the most CPU resources and optimizing them to reduce CPU usage. Additionally, using multiple CPUs can improve the performance of SQL Server systems by allowing for parallel processing of data and queries.&lt;/p&gt;

&lt;h3&gt;
  
  
  Disk Optimization
&lt;/h3&gt;

&lt;p&gt;Disk optimization is another important aspect of SQL Server performance tuning. By optimizing disk usage, organizations can improve the performance of their SQL Server systems. This involves analyzing the existing disk configuration, identifying disk bottlenecks, and making changes as needed.&lt;/p&gt;

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

&lt;p&gt;SQL Server performance tuning is essential for organizations to ensure that their database systems are running optimally. By optimizing the indexes, queries, server configuration, memory management, CPU usage, and disk usage, organizations can improve system response times, reduce downtime, and improve overall system efficiency. It is important to regularly monitor and tune the performance of SQL Server systems to achieve the best results.&lt;/p&gt;

</description>
      <category>performance</category>
      <category>sql</category>
      <category>community</category>
      <category>beginners</category>
    </item>
    <item>
      <title>MERN Stack Project Structure: Best Practices</title>
      <dc:creator>Kingsley Amankwah</dc:creator>
      <pubDate>Mon, 27 Mar 2023 10:34:23 +0000</pubDate>
      <link>https://dev.to/kingsley/mern-stack-project-structure-best-practices-2adk</link>
      <guid>https://dev.to/kingsley/mern-stack-project-structure-best-practices-2adk</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;MERN stack is a popular web development technology stack that includes MongoDB, Express.js, React.js, and Node.js. It is a very powerful stack that allows developers to build scalable and robust web applications. In this tutorial, we'll discuss the MERN stack project structure and how it can help you build better web applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  MERN Stack Project Structure
&lt;/h2&gt;

&lt;p&gt;The MERN stack project structure is organized in a way that separates the backend and frontend code. It follows the MVC (Model-View-Controller) architecture pattern. This pattern allows developers to separate the concerns of the application into three main components.&lt;/p&gt;

&lt;h3&gt;
  
  
  Model
&lt;/h3&gt;

&lt;p&gt;The Model component is responsible for managing the data and the business logic of the application. In the MERN stack, MongoDB is used as the database, which stores the data used in the application. The model's directory contains the database schema and the functions that interact with the database.&lt;/p&gt;

&lt;h3&gt;
  
  
  View
&lt;/h3&gt;

&lt;p&gt;The View component is responsible for displaying the data to the users. In the MERN stack, React.js is used as the frontend framework. The components directory contains the React components that are responsible for rendering the user interface.&lt;/p&gt;

&lt;h3&gt;
  
  
  Controller
&lt;/h3&gt;

&lt;p&gt;The Controller component is responsible for handling the user input and updating the Model and View components accordingly. In the MERN stack, the backend code is built using Node.js and Express.js. The controller's directory contains the functions that handle the HTTP requests and responses.&lt;/p&gt;

&lt;h3&gt;
  
  
  Server Directory
&lt;/h3&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%2Faqcorrxj1etrgkt0xzzo.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%2Faqcorrxj1etrgkt0xzzo.png" alt="Server Directory Image" width="221" height="227"&gt;&lt;/a&gt;&lt;br&gt;
The server directory contains the backend code of the web application. The backend code is built using Node.js and Express.js. The server directory contains the following directories and files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;config directory:&lt;/strong&gt; This directory contains the configuration files of the backend application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;controllers directory:&lt;/strong&gt; This directory contains the controllers of the application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;models directory:&lt;/strong&gt; This directory contains the models of the application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;routes directory:&lt;/strong&gt; This directory contains the routes of the application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;server.js file:&lt;/strong&gt; This file is the entry point of the backend application.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Client Directory
&lt;/h3&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%2Fknrb219pq3ut222kkvg2.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%2Fknrb219pq3ut222kkvg2.png" alt="Client Directory Image" width="198" height="337"&gt;&lt;/a&gt;&lt;br&gt;
The client directory contains the front-end code of the web application. The frontend code is built using React.js. The client directory contains the following directories and files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;public directory:&lt;/strong&gt; This directory contains the HTML file that is displayed in the browser.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;src directory:&lt;/strong&gt; This directory contains the source code of the frontend application. The src directory contains the following directories and files:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;components directory:&lt;/strong&gt; This directory contains the React components of the application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;App.js file:&lt;/strong&gt; This file is the main file of the frontend application that renders the components.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;index.js file:&lt;/strong&gt; This file is the entry point of the front-end application.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

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

&lt;p&gt;In conclusion, the MERN stack project structure is organized in a way that separates the backend and frontend code. It also follows the MVC architecture pattern. The client directory contains the frontend code, and the server directory contains the backend code. The MERN stack project structure helps in building scalable and robust web applications. By separating the concerns of the application, the codebase becomes more manageable and easier to maintain. If you're looking to build a web application using the MERN stack, it's highly recommended that you follow this project structure.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>programming</category>
      <category>react</category>
    </item>
    <item>
      <title>A Beginner's Guide to Coding Patterns</title>
      <dc:creator>Kingsley Amankwah</dc:creator>
      <pubDate>Sat, 25 Mar 2023 17:29:46 +0000</pubDate>
      <link>https://dev.to/kingsley/a-beginners-guide-to-coding-patterns-5b2f</link>
      <guid>https://dev.to/kingsley/a-beginners-guide-to-coding-patterns-5b2f</guid>
      <description>&lt;h2&gt;
  
  
  1. Overview
&lt;/h2&gt;

&lt;p&gt;Coding patterns are an essential tool for software developers to write efficient, organized, and easy-to-maintain code. They are reusable solutions to common programming problems that can help developers streamline their code, reduce bugs, and improve the quality of their work. If you're new to coding patterns, this article will provide you with a beginner-friendly introduction to what they are, why they matter, and how to use them.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. What are Coding Patterns?
&lt;/h2&gt;

&lt;p&gt;Coding patterns are templates or blueprints for solving common programming problems. They are based on proven best practices and are designed to be reusable across multiple projects. By using coding patterns, developers can save time and effort by not having to reinvent the wheel each time they encounter a problem. Instead, they can leverage existing patterns to solve problems quickly and efficiently.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Why are Coding Patterns Important?
&lt;/h2&gt;

&lt;p&gt;Coding patterns are essential for several reasons. First, they can help improve the quality of your code. By following established patterns, you can reduce the likelihood of introducing bugs into your code, making it easier to maintain over time. Additionally, coding patterns can make your code more readable and easier to understand for other developers, leading to better collaboration and more efficient teamwork.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Types of Coding Patterns
&lt;/h2&gt;

&lt;p&gt;There are many different types of coding patterns, but some of the most commonly used include:&lt;/p&gt;

&lt;h3&gt;
  
  
  4.1. Singleton Pattern
&lt;/h3&gt;

&lt;p&gt;This pattern ensures that a class has only one instance and provides a global point of access to that instance.The Singleton pattern is commonly used in &lt;code&gt;database connection management&lt;/code&gt;. For example, in a web application, you may only need one database connection throughout the entire application, and the Singleton pattern can ensure that only one instance of the connection object is created and used.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.2. Factory Pattern
&lt;/h3&gt;

&lt;p&gt;This pattern creates objects without exposing the creation logic to the client and refers to the newly created object using a common interface.The Factory pattern is widely used in many software frameworks and libraries to create objects. For example, in the Java programming language, the &lt;code&gt;java.util.Calendar&lt;/code&gt; class uses the Factory pattern to create instances of the &lt;code&gt;Calendar&lt;/code&gt; class.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.3. Adapter Pattern
&lt;/h3&gt;

&lt;p&gt;This pattern allows objects with incompatible interfaces to work together by creating an intermediate adapter object.The Adapter pattern is often used in graphical user interface (GUI) development to allow objects with incompatible interfaces to work together. For example, in the Java Swing library, the &lt;code&gt;JList&lt;/code&gt; component uses the Adapter pattern to display a list of objects with different data types.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.4. Decorator Pattern
&lt;/h3&gt;

&lt;p&gt;This pattern allows behavior to be added to an individual object, either statically or dynamically, without affecting the behavior of other objects from the same class.The Decorator pattern is commonly used in web development frameworks to add behavior to existing objects. For example, in the Django web framework for Python, you can use the Decorator pattern to add &lt;code&gt;authentication and authorization&lt;/code&gt; to views.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.5. Observer Pattern
&lt;/h3&gt;

&lt;p&gt;This pattern defines a one-to-many dependency between objects, so that when one object changes state, all its dependents are notified and updated automatically.The Observer pattern is used extensively in event-driven programming and GUI development to notify objects of changes in state. For example, in the React JavaScript library, the &lt;code&gt;useState&lt;/code&gt; hook uses the Observer pattern to notify components of changes in state.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.6. Command Pattern
&lt;/h3&gt;

&lt;p&gt;This pattern encapsulates a request as an object, thereby allowing you to parameterize clients with different requests, queue or log requests, and support undoable operations.The Command pattern is used in many software applications to encapsulate requests as objects. For example, in the Git version control system, commands such as &lt;code&gt;git commit&lt;/code&gt; and &lt;code&gt;git push&lt;/code&gt; are implemented using the Command pattern.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.7. Iterator Pattern
&lt;/h3&gt;

&lt;p&gt;This pattern provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation.The Iterator pattern is commonly used in many programming languages to access elements in &lt;code&gt;collections and arrays&lt;/code&gt;. For example, in the Python programming language, you can use the Iterator pattern to loop over elements in a list or dictionary.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Implementing Coding Patterns
&lt;/h2&gt;

&lt;p&gt;To implement coding patterns, you first need to identify the problem you are trying to solve. Once you have identified the problem, you can choose the appropriate pattern to use. Next, you need to understand the structure and behavior of the pattern and how to apply it to your code. Finally, you can implement the pattern in your code and test it to ensure that it works correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Real-World Examples of Coding Patterns
&lt;/h2&gt;

&lt;p&gt;Coding patterns are used extensively in software development, and there are many real-world examples of their use. For example, the Singleton pattern is commonly used in database connection management, while the Observer pattern is used in graphical user interface (GUI) development. Many popular software frameworks and libraries, such as React and Redux, use coding patterns extensively to provide powerful and flexible APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Conclusion
&lt;/h2&gt;

&lt;p&gt;In conclusion, coding patterns are a powerful tool for software developers that can help improve the quality, readability, and maintainability of their code. By using established patterns to solve common problems, developers can save time and effort and reduce the likelihood of introducing bugs into their code. As a beginner, learning about coding patterns can be intimidating, but with practice and experience, you will find that they are an essential tool in your software development toolkit.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>tutorial</category>
      <category>programming</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
