<?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>Forem: Leo Antony</title>
    <description>The latest articles on Forem by Leo Antony (@leoantony72).</description>
    <link>https://forem.com/leoantony72</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%2F801807%2F7ef784d6-1f16-4c15-8b0d-a38ed6321db7.jpg</url>
      <title>Forem: Leo Antony</title>
      <link>https://forem.com/leoantony72</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/leoantony72"/>
    <language>en</language>
    <item>
      <title>CLIP-Powered Multi-Modal Search with Redis Vector Index and Graph</title>
      <dc:creator>Leo Antony</dc:creator>
      <pubDate>Sat, 09 Aug 2025 17:11:16 +0000</pubDate>
      <link>https://forem.com/leoantony72/clip-powered-multi-modal-search-with-redis-vector-index-and-graph-4ple</link>
      <guid>https://forem.com/leoantony72/clip-powered-multi-modal-search-with-redis-vector-index-and-graph-4ple</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/redis-2025-07-23"&gt;Redis AI Challenge&lt;/a&gt;: Real-Time AI Innovators&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I built a real-time, multi‑modal semantic search system that combines vector similarity search with graph‑based context expansion. Text and images are embedded locally using CLIP (openai/clip-vit-base-patch16, 512‑dim). Redis 8 powers the vector index (cosine distance) and fast KNN lookups, and also serves as a cache for query results. On top of the nearest neighbors, I construct and traverse a semantic graph using NetworkX in Python to discover related items beyond the initial top‑K—enabling richer, more explainable retrieval.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Local CLIP embeddings for text and images&lt;/li&gt;
&lt;li&gt;Redis 8 vector index with cosine similarity + KNN search&lt;/li&gt;
&lt;li&gt;Result caching in Redis for low latency and reduced recompute&lt;/li&gt;
&lt;li&gt;NetworkX semantic graph to link and rank related items across searches&lt;/li&gt;
&lt;li&gt;Duplicate prevention via SHA‑256 content hashing&lt;/li&gt;
&lt;li&gt;Endpoints for submit (ingest) and search.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/xBj5ApjNUuA"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Screenshots:&lt;/em&gt;&lt;/strong&gt;&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%2Fpzxeol95xjuvbuqzie8r.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%2Fpzxeol95xjuvbuqzie8r.png" alt="Home Page"&gt;&lt;/a&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%2Fnuyugjbkoaub8u75gxax.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%2Fnuyugjbkoaub8u75gxax.png" alt="Search_with_image"&gt;&lt;/a&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%2Fz4mz6z62xhg4zj41p3l2.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%2Fz4mz6z62xhg4zj41p3l2.png" alt="Graph View"&gt;&lt;/a&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%2Fzhvru6f6ouhhaqf6offp.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%2Fzhvru6f6ouhhaqf6offp.png" alt="grpah_view_image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How to try:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Submit text or an image.&lt;/li&gt;
&lt;li&gt;The system embeds the input, stores/updates it, and runs a KNN search.&lt;/li&gt;
&lt;li&gt;Results are cached in Redis; a NetworkX graph expands context to suggest related items.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How I Used Redis 8
&lt;/h2&gt;

&lt;p&gt;I used Redis 8 as the real-time data layer for indexing, search, and caching:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Vector Index (RediSearch)&lt;/strong&gt;: I created a VECTOR HNSW index on a hash field named embedding (DIM=512, DISTANCE_METRIC=COSINE). All embeddings are stored as raw float32 bytes. KNN queries use FT.SEARCH with PARAMS to pass the query vector and SORTBY vector_score.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Semantic Caching&lt;/strong&gt;: I cache search responses keyed by a normalized query hash (e.g., sha256 of lowercased text). Hot queries return instantly from Redis without re‑embedding or re‑searching, with a short TTL to ensure freshness.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Metadata and Documents&lt;/strong&gt;: Each item is stored as a Redis hash with fields like embedding (bytes), type (text/image), content or URL, and submit_count. This allows quick retrieval for UI assembly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Deduplication:&lt;/strong&gt; Before storing, I normalize and hash the input content. If the key exists, I update usage stats instead of duplicating vectors or nodes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Performance&lt;/strong&gt;: Redis delivers sub‑millisecond lookups on cached results and fast vector KNN even at scale thanks to HNSW. Caching also reduces load on the local embedding server and keeps latency predictable.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;solo Project by: &lt;a class="mentioned-user" href="https://dev.to/leoantony72"&gt;@leoantony72&lt;/a&gt; &lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/leoantony72" rel="noopener noreferrer"&gt;
        leoantony72
      &lt;/a&gt; / &lt;a href="https://github.com/leoantony72/multi_model_vectorSearch" rel="noopener noreferrer"&gt;
        multi_model_vectorSearch
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Multi Model vector search with Redis
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Real-Time Multi-Modal Semantic Search System&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;This project is a &lt;strong&gt;real-time, multi-modal semantic search system&lt;/strong&gt; that combines &lt;strong&gt;vector similarity search&lt;/strong&gt; with &lt;strong&gt;graph-based context expansion&lt;/strong&gt;.&lt;br&gt;
It supports both &lt;strong&gt;text&lt;/strong&gt; and &lt;strong&gt;image&lt;/strong&gt; search using locally computed &lt;strong&gt;CLIP embeddings&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;📜 What I Built&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local CLIP embeddings&lt;/strong&gt; for text and images (&lt;code&gt;openai/clip-vit-base-patch16&lt;/code&gt;, 512-dim)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redis 8 vector index&lt;/strong&gt; with cosine similarity and KNN search&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Result caching&lt;/strong&gt; in Redis for low latency and reduced recompute&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NetworkX semantic graph&lt;/strong&gt; to link and rank related items beyond the initial top-K
→ enables richer, more explainable retrieval&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Duplicate prevention&lt;/strong&gt; using SHA-256 content hashing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Endpoints&lt;/strong&gt; for
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;submit&lt;/code&gt; (ingest)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;search&lt;/code&gt; (retrieve)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🛠 Architecture Overview&lt;/h2&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Embed&lt;/strong&gt;: Text and images embedded locally via CLIP&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Index&lt;/strong&gt;: Vectors stored in Redis 8 (cosine similarity)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Search&lt;/strong&gt;: Fast KNN lookups in Redis&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expand&lt;/strong&gt;: Related items discovered via semantic graph traversal in NetworkX&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache&lt;/strong&gt;: Query results cached in Redis&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serve&lt;/strong&gt;…&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/leoantony72/multi_model_vectorSearch" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  Suggestions
&lt;/h3&gt;

&lt;p&gt;As the development of AI increases, getting relations faster is a major step, While I was sad knowing that redis stopped support for redis graph. I encourage the redis Team to bring back support for Graph.&lt;/p&gt;

</description>
      <category>redischallenge</category>
      <category>devchallenge</category>
      <category>database</category>
      <category>ai</category>
    </item>
    <item>
      <title>File Organizer Desktop app with Go🚀</title>
      <dc:creator>Leo Antony</dc:creator>
      <pubDate>Mon, 19 Aug 2024 00:18:08 +0000</pubDate>
      <link>https://forem.com/leoantony72/file-organizer-desktop-app-with-go-2bg0</link>
      <guid>https://forem.com/leoantony72/file-organizer-desktop-app-with-go-2bg0</guid>
      <description>&lt;p&gt;While &lt;strong&gt;Go&lt;/strong&gt; is famous for building APIs and CLI tools, but it's potential for building desktop apps is less commonly discussed😑. Popular languages such as JavaScript/Rust already provide packages to built desktop apps such as &lt;strong&gt;Electron.js&lt;/strong&gt; for JS and &lt;strong&gt;Tauri&lt;/strong&gt; for Rust. &lt;/p&gt;

&lt;p&gt;However Electron.js is criticized consuming lot of memory leading many companies to switch to alternatives like Tauri. &lt;a href="https://docs.hoppscotch.io/documentation/clients/desktop" rel="noopener noreferrer"&gt;Hoppscotch &lt;/a&gt;recently released their desktop app with Tauri, highlighting the growing trend toward more resource-efficient solutions.&lt;/p&gt;

&lt;p&gt;Go is also leading the way in building Desktop apps with &lt;a href="https://wails.io/" rel="noopener noreferrer"&gt;wails&lt;/a&gt;, and with wails and Vue.js I built a File Organizer which sort the files to their respective folders based on the &lt;em&gt;File Type, Year/Month of creation&lt;/em&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Serpico: File Organizing App🚀
&lt;/h4&gt;

&lt;p&gt;Simplify your digital life with &lt;a href="https://github.com/leoantony72/serpico" rel="noopener noreferrer"&gt;Serpico&lt;/a&gt;, the ultimate app for organizing your files with precision and ease. Designed to help you manage and declutter your digital space, Serpico organizes your files by month, year, and file type.&lt;/p&gt;

&lt;h4&gt;
  
  
  Key Features
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Automatic File Organization: Serpico intelligently categorizes your files by month, year, and file type, making it easy to navigate through your digital archive.&lt;/li&gt;
&lt;li&gt;User-Friendly Interface: Enjoy a clean and intuitive interface that makes organizing and accessing your files a breeze🐱‍💻.&lt;/li&gt;
&lt;li&gt;Secure and Reliable: Trust Serpico to handle your files securely, with robust encryption and backup options to keep your data safe.&lt;/li&gt;
&lt;li&gt;With Serpico, managing your digital files has never been easier. Whether you're a professional, a student, or just looking to declutter your personal files, Serpico is your go-to solution for a more organized digital life.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Screenshots
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8gwq39vrowlj2xrzq80c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8gwq39vrowlj2xrzq80c.png" alt="User Interface of Serpico"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Development
&lt;/h3&gt;

&lt;p&gt;To run in live development mode, run &lt;code&gt;wails dev&lt;/code&gt; in the project directory. This will run a *&lt;em&gt;Vite *&lt;/em&gt; development server that will provide very fast hot reload of your frontend changes. If you want to develop in a browser and have access to your Go methods, there is also a dev server that runs on &lt;code&gt;http://localhost:34115&lt;/code&gt;. Connect to this in your browser, and you can call your Go code from devtools.&lt;/p&gt;

&lt;p&gt;To build a redistributable, production mode package, use &lt;code&gt;wails build&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;I encourage you all to try out wails, It's easy to use and they a good documentation if you want that, &lt;a href="https://wails.io/" rel="noopener noreferrer"&gt;wails&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Email: &lt;a href="mailto:leoantony102@gmail.com"&gt;leoantony102@gmail.com&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/leoantony72" rel="noopener noreferrer"&gt;https://github.com/leoantony72&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/leoantony72/serpico" rel="noopener noreferrer"&gt;https://github.com/leoantony72/serpico&lt;/a&gt;&lt;br&gt;
Download Link: &lt;a href="https://github.com/leoantony72/serpico/releases/tag/v1.0" rel="noopener noreferrer"&gt;https://github.com/leoantony72/serpico/releases/tag/v1.0&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>wails</category>
      <category>vue</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Go High-Performance Cache with TTL and Disk Persistence</title>
      <dc:creator>Leo Antony</dc:creator>
      <pubDate>Tue, 13 Aug 2024 15:15:03 +0000</pubDate>
      <link>https://forem.com/leoantony72/go-high-performance-cache-with-ttl-and-disk-persistence-4a4m</link>
      <guid>https://forem.com/leoantony72/go-high-performance-cache-with-ttl-and-disk-persistence-4a4m</guid>
      <description>&lt;h2&gt;
  
  
  1.Introduction
&lt;/h2&gt;

&lt;p&gt;Accelerate your Golang projects without the hassle of setting up a database everytime you begin a new project. Tired of configuring databases from scratch? Only to face new problems? Look no further In this blog we will be looking into Golang caching library with Support for &lt;strong&gt;TTL&lt;/strong&gt;, &lt;strong&gt;disk Persistence&lt;/strong&gt; and &lt;strong&gt;Hash Data type&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/leoantony72/goswift/tree/main" rel="noopener noreferrer"&gt;&lt;strong&gt;GoSwift&lt;/strong&gt;.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2.Prerequisite
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Basic Knowledge of Golang&lt;/li&gt;
&lt;li&gt;Knowledge of how a typical cache works&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3.Features
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Set &amp;amp; Get command&lt;/li&gt;
&lt;li&gt;Update command&lt;/li&gt;
&lt;li&gt;Del command&lt;/li&gt;
&lt;li&gt;Exists command&lt;/li&gt;
&lt;li&gt;Support for TTL&lt;/li&gt;
&lt;li&gt;Support for Disk Save(Snapshots)&lt;/li&gt;
&lt;li&gt;Support Hash Data type (Hset, Hget, HgetAll, HMset)&lt;/li&gt;
&lt;li&gt;Safe Locking&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Set &amp;amp; Get command
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/leoantony72/goswift"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;goswift&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewCache&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// Value 0 indicates no expiry&lt;/span&gt;
    &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&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="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Update command
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Update value&lt;/span&gt;
&lt;span class="c"&gt;// @Update(key string, val interface{}) error&lt;/span&gt;
&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"value2"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Del command &amp;amp;&amp;amp; Exists command
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Delete command&lt;/span&gt;
&lt;span class="c"&gt;// @Del(key string)&lt;/span&gt;
&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Del&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// Exist command&lt;/span&gt;
&lt;span class="c"&gt;// @Exists(key string) bool&lt;/span&gt;
&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// returns false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Support for TTL
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Set Value with Expiry&lt;/span&gt;
&lt;span class="c"&gt;// @Set(key string, val interface{}, exp int)&lt;/span&gt;
&lt;span class="c"&gt;// Here expiry is set to 1sec&lt;/span&gt;
&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// Hset command&lt;/span&gt;
&lt;span class="c"&gt;// @Hset(key, field string, value interface{}, exp int)&lt;/span&gt;
&lt;span class="c"&gt;// in this case the "key" expires in 1sec&lt;/span&gt;
&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Hset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Hset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Support Hash Data type (Hset, Hget, HgetAll, HMset)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;
&lt;span class="c"&gt;// Hset command&lt;/span&gt;
&lt;span class="c"&gt;// @Hset(key, field string, value interface{}, exp int)&lt;/span&gt;
&lt;span class="c"&gt;// in this case the "key" expires in 1sec&lt;/span&gt;
&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Hset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Hset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="c"&gt;// HMset command&lt;/span&gt;
&lt;span class="c"&gt;// @HMset(key string, d interface{}, exp int) error&lt;/span&gt;
&lt;span class="c"&gt;// Set a Hash by passing a Struct/Map&lt;/span&gt;
&lt;span class="c"&gt;// ---by passing a struct---&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;Age&lt;/span&gt;   &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;Place&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;person1&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s"&gt;"bob"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;Age&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;Place&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s"&gt;"NYC"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HMset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;person1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&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="c"&gt;// ---by passing a map---&lt;/span&gt;
&lt;span class="n"&gt;person2&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s"&gt;"john"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;Age&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;Place&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s"&gt;"NYC"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HMset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;person2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&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="c"&gt;// Hget command&lt;/span&gt;
&lt;span class="c"&gt;// @HGet(key, field string) (interface{}, error)&lt;/span&gt;
&lt;span class="c"&gt;// get individual fields in Hash&lt;/span&gt;
&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"field"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&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="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// HgetAll command&lt;/span&gt;
&lt;span class="c"&gt;// @HGetAll(key string) (map[string]interface{}, error)&lt;/span&gt;
&lt;span class="c"&gt;// gets all the fields with value in a hash key&lt;/span&gt;
&lt;span class="c"&gt;// retuns a map[string]interface{}&lt;/span&gt;
&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HGetAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Snapshots
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;opt&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;goswift&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CacheOptions&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;EnableSnapshots&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;SnapshotInterval&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;goswift&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewCache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will take a snapshot of the Data Every 5sec and saves it into a Snapshot.data file. By default Snapshots are disabled and if the SnapshotInterval is not provided default value is 5seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: If the EnableSnapshot is false, Data saved in the file will not imported&lt;/p&gt;

&lt;h3&gt;
  
  
  Error handling
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ErrKeyNotFound&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"key does not Exists"&lt;/span&gt;
    &lt;span class="n"&gt;ErrFieldNotFound&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"field does not Exists"&lt;/span&gt;
    &lt;span class="n"&gt;ErrNotHashvalue&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"not a Hash value/table"&lt;/span&gt;
    &lt;span class="n"&gt;ErrHmsetDataType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"invalid data type, Expected Struct/Map"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are the common Errors that may occur while writing the code. These Varible provide you a clear and easy Error comparison method to determine errors.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;goswift&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrKeyNotFound&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;//do something&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;    
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Inner workings of the cache expiry
&lt;/h2&gt;

&lt;p&gt;Every 3sec the **sweaper **function gets called to clear out the expired values from the hash table. We maintain a min heap which points to the hash map. The top element will be the key with the smallest TTL. we traverse through the tree until TTL is greater then the current time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;I wouldn't advice you to use this in production!!, but feel free to use it in your small side project. Do try it out and if you encounter a bug  do make a issue on GitHub repo.&lt;/p&gt;

&lt;p&gt;Email: &lt;a href="mailto:leoantony102@gmail.com"&gt;leoantony102@gmail.com&lt;/a&gt;&lt;br&gt;
Github: &lt;a href="https://github.com/leoantony72" rel="noopener noreferrer"&gt;https://github.com/leoantony72&lt;/a&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/leoantony72/goswift" rel="noopener noreferrer"&gt;https://github.com/leoantony72/goswift&lt;/a&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>go</category>
      <category>redis</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How I Made Twitter Back-end</title>
      <dc:creator>Leo Antony</dc:creator>
      <pubDate>Sat, 15 Apr 2023 07:35:27 +0000</pubDate>
      <link>https://forem.com/leoantony72/twitter-back-end-design-274b</link>
      <guid>https://forem.com/leoantony72/twitter-back-end-design-274b</guid>
      <description>&lt;h2&gt;
  
  
  1. Introduction
&lt;/h2&gt;

&lt;p&gt;I am designing a back-end for Twitter using a micro-service architecture. This design is based on the implementation by Twitter's engineers, and I had made some slight modifications to enhance scalability and improve performance. I will be coding and implementing this design as I progress. &lt;/p&gt;

&lt;p&gt;GitHub Project Link: &lt;a href="https://github.com/leoantony72/twitter-backend" rel="noopener noreferrer"&gt;Twitter Backend&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2.Prerequisite
&lt;/h2&gt;

&lt;p&gt;Basic system Design concepts like: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Jwt&lt;/li&gt;
&lt;li&gt;Caching&lt;/li&gt;
&lt;li&gt;load balancer&lt;/li&gt;
&lt;li&gt;Message Queue/Bus&lt;/li&gt;
&lt;li&gt;Service Registry&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3.Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;User signup/Login - JWT&lt;/li&gt;
&lt;li&gt;User should be able to tweet.&lt;/li&gt;
&lt;li&gt;User can Delete Tweet&lt;/li&gt;
&lt;li&gt;User can see other user's tweet timeline(with retweets).&lt;/li&gt;
&lt;li&gt;User can get their Home timeline.&lt;/li&gt;
&lt;li&gt;User can follow/unfollow others.&lt;/li&gt;
&lt;li&gt;System should be Scalable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4.Challenges we face
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Twitters high volume of daily tweets can be challenging for scaling the platform. Twitter by nature is a Read Heavy application compared to writes. meaning there are far more users consuming tweets than users actively tweeting. Twitter still produce 5800 tweets per/second btw😬.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Since being a Read Heavy application the database will experience heavy load. We can reduce the heavy load by using a cache like Redis.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When a tweet is tweeted it is send to queue so it might take a bit to show up on user's &lt;strong&gt;Home Page&lt;/strong&gt;, It's okay but we have to make sure not to increase this time gap.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Jwt key sharing among other service for authentication&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5.Database Design
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx2mi4i25hqsqvgbbnmhf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx2mi4i25hqsqvgbbnmhf.png" alt="Twitter database Design"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this &lt;strong&gt;Users&lt;/strong&gt; table have &lt;em&gt;One to Many&lt;/em&gt; relations with Tweets,Likes,Retweets,User_follows.&lt;/p&gt;

&lt;h2&gt;
  
  
  6.Implementation
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Auth Service
&lt;/h2&gt;

&lt;p&gt;Using session would require to make a call to the database every time a request comes in. Since we are following microservice architecture we will be using JWT to reduce database calls. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz2cmfd1tkkitapeb6n83.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz2cmfd1tkkitapeb6n83.png" alt="Symmetric Key sharing"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For Verifying these Jwt token we would have to share the master key to every service which is not the best practice. What's the solutions &lt;strong&gt;Asymmetric Key!&lt;/strong&gt;. Basically Asymmetric key means that we will Encrypt with a key and Decrypt with another key.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw9xz4eblfji52qxgzk6f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw9xz4eblfji52qxgzk6f.png" alt="Asymmetric key Sharing"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The master key will be used to make the tokens and slave key can only be used for verifying these tokens. For Creating Asymmetric token we need to generate a RSA key then we create a private &amp;amp;  public certificate.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="c"&gt;// generate key&lt;/span&gt;
&lt;span class="n"&gt;privatekey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;rsa&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GenerateKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cannot generate RSA key&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;publickey&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;privatekey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PublicKey&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Then we dump this key to &lt;em&gt;&lt;strong&gt;private.pem&lt;/strong&gt;&lt;/em&gt; file for further use in generating jwt tokens&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="c"&gt;// dump private key to file&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;privateKeyBytes&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x509&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarshalPKCS1PrivateKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;privatekey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;privateKeyBlock&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;"RSA PRIVATE KEY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Bytes&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;privateKeyBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;privatePem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"private.pem"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error when create private.pem: %s &lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;do this for the &lt;strong&gt;&lt;em&gt;public.pem&lt;/em&gt;&lt;/strong&gt; certificate, we use this certificate to verify jet token.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="c"&gt;// dump public key to file&lt;/span&gt;
    &lt;span class="n"&gt;publicKeyBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;x509&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarshalPKIXPublicKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;publickey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error when dumping publickey: %s &lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;publicKeyBlock&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;"PUBLIC KEY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Bytes&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;publicKeyBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;publicPem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"../public.pem"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error when create public.pem: %s &lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Code for generating Jwt token with &lt;em&gt;private.pem&lt;/em&gt; cerificate&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;GenerateAccessToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ioutil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"private.pem"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;rsaprivateKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;jwt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseRSAPrivateKeyFromPEM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


    &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;jwt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewWithClaims&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jwt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SigningMethodRS256&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jwt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MapClaims&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"ID"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"exp"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Minute&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unix&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;


    &lt;span class="n"&gt;tokenString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SignedString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rsaprivateKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to create Token"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;tokenString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;We can now verify the jwt token with &lt;strong&gt;&lt;em&gt;public.pem&lt;/em&gt;&lt;/strong&gt; certificate. We can further make a middleware functions to verify jwt token.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;ValidateJwt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signedToken&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;jwt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jwt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MapClaims&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
    &lt;span class="c"&gt;// Load the RSA public key from a file&lt;/span&gt;&lt;br&gt;
    &lt;span class="n"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ioutil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"../public.pem"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;br&gt;
    &lt;span class="n"&gt;rsaPublicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;jwt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseRSAPublicKeyFromPEM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;span class="c"&amp;gt;// Parse the signed JWT and verify it with the RSA public key&amp;lt;/span&amp;gt;
&amp;lt;span class="n"&amp;gt;token&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;,&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;err&amp;lt;/span&amp;gt; &amp;lt;span class="o"&amp;gt;:=&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;jwt&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;Parse&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;(&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;signedToken&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;,&amp;lt;/span&amp;gt; &amp;lt;span class="k"&amp;gt;func&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;(&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;token&amp;lt;/span&amp;gt; &amp;lt;span class="o"&amp;gt;*&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;jwt&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;Token&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;)&amp;lt;/span&amp;gt; &amp;lt;span class="p"&amp;gt;(&amp;lt;/span&amp;gt;&amp;lt;span class="k"&amp;gt;interface&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;{},&amp;lt;/span&amp;gt; &amp;lt;span class="kt"&amp;gt;error&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;)&amp;lt;/span&amp;gt; &amp;lt;span class="p"&amp;gt;{&amp;lt;/span&amp;gt;
    &amp;lt;span class="k"&amp;gt;if&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;_&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;,&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;ok&amp;lt;/span&amp;gt; &amp;lt;span class="o"&amp;gt;:=&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;token&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;Method&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;(&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;*&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;jwt&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;SigningMethodRSA&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;);&amp;lt;/span&amp;gt; &amp;lt;span class="o"&amp;gt;!&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;ok&amp;lt;/span&amp;gt; &amp;lt;span class="p"&amp;gt;{&amp;lt;/span&amp;gt;
        &amp;lt;span class="k"&amp;gt;return&amp;lt;/span&amp;gt; &amp;lt;span class="no"&amp;gt;nil&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;,&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;fmt&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;Errorf&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;(&amp;lt;/span&amp;gt;&amp;lt;span class="s"&amp;gt;"unexepcted signing method: %v"&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;,&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;token&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;Header&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;[&amp;lt;/span&amp;gt;&amp;lt;span class="s"&amp;gt;"alg"&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;])&amp;lt;/span&amp;gt;
    &amp;lt;span class="p"&amp;gt;}&amp;lt;/span&amp;gt;
    &amp;lt;span class="k"&amp;gt;return&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;rsaPublicKey&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;,&amp;lt;/span&amp;gt; &amp;lt;span class="no"&amp;gt;nil&amp;lt;/span&amp;gt;
&amp;lt;span class="p"&amp;gt;})&amp;lt;/span&amp;gt;

&amp;lt;span class="n"&amp;gt;claims&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;,&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;ok&amp;lt;/span&amp;gt; &amp;lt;span class="o"&amp;gt;:=&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;token&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;Claims&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;(&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;jwt&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;MapClaims&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;)&amp;lt;/span&amp;gt;
&amp;lt;span class="k"&amp;gt;if&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;ok&amp;lt;/span&amp;gt; &amp;lt;span class="o"&amp;gt;&amp;amp;amp;&amp;amp;amp;&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;token&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;Valid&amp;lt;/span&amp;gt; &amp;lt;span class="p"&amp;gt;{&amp;lt;/span&amp;gt;
    &amp;lt;span class="k"&amp;gt;return&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;token&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;,&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;claims&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;,&amp;lt;/span&amp;gt; &amp;lt;span class="no"&amp;gt;nil&amp;lt;/span&amp;gt;
&amp;lt;span class="p"&amp;gt;}&amp;lt;/span&amp;gt;
&amp;lt;span class="k"&amp;gt;return&amp;lt;/span&amp;gt; &amp;lt;span class="no"&amp;gt;nil&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;,&amp;lt;/span&amp;gt; &amp;lt;span class="no"&amp;gt;nil&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;,&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;err&amp;lt;/span&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Tweet Service&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;The Tweet Service is responsible for posting tweets and pushing them to a message queue for consumption by the timeline service. Additionally, the service is responsible for handling tweet interactions such as retweeting and liking. Retweets are also pushed to the message queue to ensure that followers can see them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxm3xn94nj9pbii47c5yy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxm3xn94nj9pbii47c5yy.png" alt="Twitter Tweet Service"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By utilizing a Message Queue, tweets can be processed efficiently and in real-time. RabbitMq was used as the message queue in the development of this project.&lt;/p&gt;

&lt;p&gt;Prior to sending tweets to the message queue, they are stored in Postgres and Redis. Redis is used to store a copy of the tweet, along with information about users who liked and retweeted the tweet. User tweets are stored in a sorted set with a key format of &lt;strong&gt;"users:${username}:tweets"&lt;/strong&gt;, facilitating efficient data organization and retrieval.&lt;/p&gt;

&lt;h2&gt;
  
  
  Timeline Service
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcvf92ftwkkllcgopgkg2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcvf92ftwkkllcgopgkg2.png" alt="Twitter Timleine service"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Timeline service is tasked with fetching both the user timeline and home timeline. To handle incoming tweets obtained from the MQ, we will utilize a separate goroutine. Our approach will involve iterating through each new message, and if the author's number of followers is below x, we will employ the Push method. Otherwise, we will opt for the Pull method.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Push Method&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhrgbd1veooxg50e11sz4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhrgbd1veooxg50e11sz4.png" alt="Twitter Fanout"&gt;&lt;/a&gt;&lt;br&gt;
In this approach the tweet will be send to every followers of the author. This will be stored in followers timeline in Redis with a key similar to &lt;strong&gt;"users:${username}:timeline"&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is the problem with this approach?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Suppose a tweet author has &lt;em&gt;1,000,000&lt;/em&gt; followers so with this approach timeline service would have to send this tweet to 1million users. Even for the &lt;em&gt;Blazing fast Redis&lt;/em&gt; that will take time to finish. In this scenario we opt for &lt;strong&gt;Pull method&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pull Method&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When the number of followers exceeds x, the Pull method is more efficient, and Twitter uses it for handling tweets from celebrities. If a user requests to load their timeline, we will first check if they follow any celebrities this can be done by maintaining a list of celebrity a user follows. If they do, we will pull the latest tweets from the celebrities and merge them with the user's timeline, returning the resulting tweets. This approach ensures that only active users receive the data, like a request and serve mechanism. In contrast, the Push method pushes tweets to both active and inactive users, resulting in wasted bandwidth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Load Balancer
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqn5dxzoec277ymio0dvu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqn5dxzoec277ymio0dvu.png" alt="Twitter Load Balancer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since we have multiple services we want to a way to direct the request to each service, here comes the load balancer. Haproxy is used as the load Balancer in the development of this project. Haproxy directs the request it gets to appropriate services.&lt;/p&gt;

&lt;h2&gt;
  
  
  Service Registry
&lt;/h2&gt;

&lt;p&gt;Every Service on startup register itself to service register In this case I've used Consul as the service registry. I configured consul in a way that after every 10s it makes a request to particular endpoint if it failed to respond it means our service is down. Consul provides us a Web interface where we can see if the services are online or not.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Web Interface: localhost:8500&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Docker
&lt;/h2&gt;

&lt;p&gt;My Twitter-Backend has been dockerized so you run it with just one command. Docker helped me setup this project easily. For those who don't know docker enables you to run any database, load balancer or cache with just 1-2 commands. You can also dockerize your application to ship it to production.&lt;/p&gt;

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

&lt;p&gt;This project was fun to do and I've learned a lot by building this project hope you have learned something new. Do tell me any mistakes I made or how it can be improved. Be sure to check out my project on GitHub (Documentation available) and also check out thread I made on Twitter🙂.&lt;/p&gt;

&lt;p&gt;Github: &lt;a href="https://github.com/leoantony72/twitter-backend" rel="noopener noreferrer"&gt;https://github.com/leoantony72/twitter-backend&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Twitter: &lt;a href="https://twitter.com/serpico_z/status/1605899167439757312" rel="noopener noreferrer"&gt;https://twitter.com/serpico_z/status/1605899167439757312&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>redis</category>
      <category>api</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Intro to common components of System Architecture!</title>
      <dc:creator>Leo Antony</dc:creator>
      <pubDate>Tue, 29 Nov 2022 14:35:16 +0000</pubDate>
      <link>https://forem.com/leoantony72/intro-to-common-components-of-system-architecture-2dd9</link>
      <guid>https://forem.com/leoantony72/intro-to-common-components-of-system-architecture-2dd9</guid>
      <description>&lt;h2&gt;
  
  
  1.Intro
&lt;/h2&gt;

&lt;p&gt;This is a shot blog on most common system design components you will hear. You will be learning Load-balancers, Caching and Monolithic &amp;amp; Microservice Architectecture&lt;/p&gt;

&lt;h2&gt;
  
  
  2.Components
&lt;/h2&gt;

&lt;p&gt;I introduce you to 10 most common terms you will hear if you are learning System Architecture. Below are some of the most important concepts you need to know if you getting into System Architecture.👇&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1.Load Balancer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A single server can't handle millions of requests at a time. So, What's the solution? Add more servers but how do we route the users to them?🤔. Here a load balancer distributes the load among the available servers. Nginx/HaProxy are some popular load balancers.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;2.Caching &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Caching Layer is between the API and the database. When a request to retrieve a piece of data is sent the API checks the cache and if it's available it returns it to the user or else queries the database. Using a caching layer increases the speed of the read operation.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;3.Monolithic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is one large codebase with all the functions of your API tightly linked together. If a part of your system breaks your whole API will be down📉. Most project starts with a monolithic approach and then moves on to microservice architecture depending on their team size.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;4.Microservice &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Independent and contained services with each service having an individual database. For ex: if the timeline service fails it does not affect the tweet service or any other service. There will be a load balancer that routes the request to desired services. Microservice architecture introduces &lt;strong&gt;complexity in deploying&lt;/strong&gt; and &lt;strong&gt;increases network latency&lt;/strong&gt;. Each service can talk to each other using a Message Queue like kafka. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;5.Scaling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Large enterprises have huge amounts of data. with the increasing amount of data each day their server should grow accordingly.&lt;br&gt;
There are two types of scaling horizontal &amp;amp; vertical scaling&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vertical Scaling&lt;/strong&gt; - It means upgrading the current system.upgrading &lt;strong&gt;RAM&lt;/strong&gt;, &lt;strong&gt;CPU’s&lt;/strong&gt; and &lt;strong&gt;hard disk drives&lt;/strong&gt;
but there is always a certain limit on how much we can     upgrade.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Horizontal Scaling&lt;/strong&gt; - It means to add multiple systems to improve the performance of the service. A load balancer is needed to distribute the load to multiple systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yzHCR-ho--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.cloudzero.com/hubfs/blog/horizontal-vs-vertical-scaling.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yzHCR-ho--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.cloudzero.com/hubfs/blog/horizontal-vs-vertical-scaling.webp" alt="Horizontal and Vertical Scaling" width="792" height="612"&gt;&lt;/a&gt; &lt;/p&gt;

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

&lt;p&gt;This was a fairly a short blog, hope you have learned something new in this. next time I am going to be building Twitter back-end clone🔥.&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>architecture</category>
      <category>redis</category>
      <category>nginx</category>
    </item>
    <item>
      <title>Distributed Chat Application</title>
      <dc:creator>Leo Antony</dc:creator>
      <pubDate>Fri, 04 Nov 2022 15:38:35 +0000</pubDate>
      <link>https://forem.com/leoantony72/distributed-chat-application-22oo</link>
      <guid>https://forem.com/leoantony72/distributed-chat-application-22oo</guid>
      <description>&lt;h2&gt;
  
  
  1.Introduction
&lt;/h2&gt;

&lt;p&gt;Building a distributed chat system was one of the things i wanted to build, Designing a chat system like slack or messenger has always been among the top questions asked in interview's. I am self taught developer currently in high school building side projects. In this article, I want to share with you my design of Distributed Chat Application.&lt;/p&gt;

&lt;h2&gt;
  
  
  1.1.Prerequisite
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Basic knowledge of Load balancer&lt;/li&gt;
&lt;li&gt;How Websockets Works&lt;/li&gt;
&lt;li&gt;Understanding Message Queue &lt;/li&gt;
&lt;li&gt;Cassandra&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2.Features
&lt;/h2&gt;

&lt;p&gt;At First we must list out the features that we are going to build as this gives us a better understanding at the project.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One on One message: Two users can chat with each other&lt;/li&gt;
&lt;li&gt;Group Chat: users can send message to a group&lt;/li&gt;
&lt;li&gt;Create Groups: users can create groups&lt;/li&gt;
&lt;li&gt;Join Groups: users can join group with their name&lt;/li&gt;
&lt;li&gt;servers must be able to scale: Multiple web-server instance behind the load balancer.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3.Database Design
&lt;/h2&gt;

&lt;p&gt;We would use NoSQL database such as cassandra. It's easy to scale up and it's very suitable for write-heavy works.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.1 Database Schema
&lt;/h3&gt;

&lt;p&gt;In Cassandra performing JOINS is not possible, That's a feature🐱‍💻&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftiurdfw2eqw3kcqm3bes.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftiurdfw2eqw3kcqm3bes.png" alt="Private Chat Table"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuvca8obqxug35375ix4k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuvca8obqxug35375ix4k.png" alt="Group Chat Table"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In here Timestamp is maintained in each message to retrieve message when user logs in.&lt;/p&gt;

&lt;h2&gt;
  
  
  4.System Design
&lt;/h2&gt;

&lt;p&gt;One of our core feature will be scalability so We will be deploying 3 instance of our API/WebSocket server and with the help of a load balancer like Nginx/haproxy traffic will be distributed to each server. &lt;/p&gt;

&lt;h2&gt;
  
  
  4.1.Private Chat
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What are the complexity that we deal when we spin up more than 1 instance?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Suppose user1 has to send a message to user2 but due to the existence of 3 servers User1 establish a websocket connection with S1 and User2 establish a connection with S3. How the heck am i supposed to send message to User2 now?😵&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyu3z2sk4reha5zbm9huq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyu3z2sk4reha5zbm9huq.png" alt="Problem 1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Introducing distributed servers == Increases Complexity &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My approach to the solution is to keep a Message Queue, you can choose between kafka, RabbitMQ or Redis. I chose Redis because it's less Complexity and sub millisecond write and read speed🚀. Each server will have it's own topic in redis. So when a message needs to be send to other server it will be send to respective server's topic. Each servers will also consume new message from their topic.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How do i know which server the receiver is connected to?
&lt;img src="https://media.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%2Fowcmtnwg1vn8v8m7jeeu.png" alt="User Mapping Table"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will maintain a User Mapping table with columns userID and SeverID. When users connect to the websocket server their userid and serverid is stored in the User Mapping Table in cassandra and when user disconnects their record is deleted or marked disconnected by introducing an additional field status.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7764b2y754vdh3ohdxtp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7764b2y754vdh3ohdxtp.png" alt="System design Private chat"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will be our final solution for private chat below is the data flow of this design👇&lt;br&gt;
Data Flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;User1&lt;/strong&gt; and &lt;strong&gt;User2&lt;/strong&gt; sends request to load-balancer &lt;/li&gt;
&lt;li&gt;load-balancer connects &lt;strong&gt;User1 to S1&lt;/strong&gt; &amp;amp; &lt;strong&gt;User2 to S3&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User1&lt;/strong&gt; wants to send message to &lt;strong&gt;User2&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User1&lt;/strong&gt; sends the message to &lt;strong&gt;S1&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;S1&lt;/strong&gt; retrieve's which server &lt;strong&gt;User2&lt;/strong&gt; is connected to from User Mapping Table&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;S1&lt;/strong&gt; sends the message to &lt;strong&gt;S3 TOPIC&lt;/strong&gt; in redis Queue&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;S3&lt;/strong&gt; retrieve's new message from &lt;strong&gt;S3 TOPIC&lt;/strong&gt; from redis Queue&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;S3&lt;/strong&gt; then sends the message to User2&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  4.2.Group Chat
&lt;/h2&gt;

&lt;p&gt;Although Group chat follows the same design we can make some tweaks in the websocket servers for better performance.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is the performance issue that we are going to encounter in this architecture?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Assume that User1(Connected to S1) needs to send a message to group &lt;strong&gt;X&lt;/strong&gt; with &lt;strong&gt;400&lt;/strong&gt; members, These members are distributed among the other two servers S2 &amp;amp; S3 with &lt;strong&gt;200&lt;/strong&gt; members connected to each server(assuming all the users are active right now).S1 would get the list of members in the group X then loop through each of them and send the message to the server member are connected to. This would send &lt;strong&gt;200 Duplicate message&lt;/strong&gt; to S2 &amp;amp; S3, Therefore this is not an optimal case for us.😕&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2For67tdmptp15broqlrso.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2For67tdmptp15broqlrso.png" alt="scalling group chat"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is how i prevented the sending of duplicate messages, At First we retrieve the group members from cassandra then get the SERVERID of the servers to which they are connected from user mapping table. We then group them according to their SERVERID with SERVERID being the &lt;strong&gt;key&lt;/strong&gt; and array of USERID being the &lt;strong&gt;value&lt;/strong&gt;. We then loop through the keys and send to the respective Topics in Message Queue according to their key with the message.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0tfmy1ij41k0e2n5ctgi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0tfmy1ij41k0e2n5ctgi.png" alt="Group chat message"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;isgroup field is used to check if the message is being sent to a group or not, group_members is an array of members of group X which are connected to server S2 in this case.&lt;/p&gt;

&lt;p&gt;Data Flow: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User1 connects to S1 &lt;/li&gt;
&lt;li&gt;User1 sends a message to group "X"&lt;/li&gt;
&lt;li&gt;S1 fetches the group members of group "X"&lt;/li&gt;
&lt;li&gt;S1 loops through them to get the id of their connected server&lt;/li&gt;
&lt;li&gt;Groups the members based on the server they are connected on&lt;/li&gt;
&lt;li&gt;serverId being the key and array of users being the value&lt;/li&gt;
&lt;li&gt;loops through the keys and sends the message to the Topic in message queue with the same key along with its value (array of members)&lt;/li&gt;
&lt;li&gt;S2 &amp;amp; S3 receives the message with server_id, sender, is_group, group_name, group_members and message&lt;/li&gt;
&lt;li&gt;S2/S3 loops through the group members (users which belong to group X which are connected to S2/S3) and sends the message to them&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is the solution that i came up with and this might not be the perfect solution and lot of other improvements can be made in this. If you have a better suggestion please let me know below I would love to discuss it😁. This was made after i finished making a distributed chat system with golang, redis and cassandra using redis as Message Queue.&lt;/p&gt;

&lt;p&gt;Distributed Chat System: &lt;a href="https://github.com/leoantony72/go-chat2" rel="noopener noreferrer"&gt;https://github.com/leoantony72/go-chat2&lt;/a&gt;&lt;br&gt;
Twitter: &lt;a href="https://twitter.com/serpico_z" rel="noopener noreferrer"&gt;https://twitter.com/serpico_z&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If this post gets good attraction i will do system design of notification system next time🐱‍💻. See you next time👋&lt;/p&gt;

</description>
      <category>go</category>
      <category>distributedsystems</category>
      <category>api</category>
      <category>redis</category>
    </item>
    <item>
      <title>E-Commerce API Made With Node-Js,Typescript,PostgreSQL,Redis And Kafka</title>
      <dc:creator>Leo Antony</dc:creator>
      <pubDate>Wed, 09 Mar 2022 15:18:41 +0000</pubDate>
      <link>https://forem.com/leoantony72/e-commerce-api-made-with-node-jstypescriptpostgresqlredis-and-kafka-4gj2</link>
      <guid>https://forem.com/leoantony72/e-commerce-api-made-with-node-jstypescriptpostgresqlredis-and-kafka-4gj2</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;E-commerce API made with typescript, express ,PostgreSQL,Redis &amp;amp; Kafka with all the basic features and more !!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source Code&lt;/strong&gt; - &lt;a href="https://github.com/leoantony72/E-commerce-Api" rel="noopener noreferrer"&gt;https://github.com/leoantony72/E-commerce-Api&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Environment variables&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PORT = 4000
DB_USER = PGUSER
DB_PASSWORD = PGPASSWORD
DB_HOST = postgresdb
DB_PORT = 5432
DB_DATABASE = e_commerce
SESSION_SECRET = Session Secret
SESSION_MAXAGE = 3600000 * 60 * 10
GMAIL_USER = email // eg:(test123)
GMAIL_PASS = Gmail password
STRIPE_PUBLIC_KEY = Stripe public Key
STRIPE_SECRET_KEY = Stripe Private Key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Docker build&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker-compose up // in the root dir
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Setup Postgres,Redis &amp;amp; Kafka&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;⭕*&lt;em&gt;Postgres *&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker exec -it postgresdb psql -U username -W e_commerce
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy and paste db.sql file from &lt;a href="https://github.com/leoantony72/E-commerce-Api/blob/ae8c46d1a279fb14905c6c51a492900789e1ab0d/src/models/dbmodel.sql" rel="noopener noreferrer"&gt;db_model&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⭕*&lt;em&gt;Redis *&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker exec -it redis-e-commerce bash -c redis-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;paste this command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BF.RESERVE usernames 0.00001 10000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⭕&lt;strong&gt;Kafka&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker exec -it broker bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kafka-topics --create --bootstrap-server localhost:9092 --replication-factor 1  --partitions 1  --topic orders
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this our setup is finished , all the Api routes is&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
1. /api/store                       GET     Access the Store
2. /api/auth/register               POST    Register a User
3. /api/auth/login                  POST    Login A user
4. /api/auth/logout                 POST    Logout A User
5. /api/auth/forgotpassword         POST    Req For Password Reset
6. /api/auth/reset-password/        POST    Resets The Password
7. /api/verify                      GET     Verify The Email
8. /api/admin/product               POST    Insert A Product
9. /api/admin/product/:id           PUT     Update Product
10. /api/admin/product/:id          DELETE  Delete A Product
11. /api/admin/stock/:id            PUT     Update Stock
12. /api/admin/discount/:pid        GET     Get Discount of a Product
13. /api/admin/add_discount/:id     POST    Add Discount to a product
14. /api/admin/activate/:id         GET     Activate Discount
15. /api/manager/orders             GET     Gets Order
16. /api/manager/order/:orderid     GET     Get Individual Order Detailes
17. /api/shipper/updateorder/:oid   POST    Sents Confirm Order Request
18. /api/order/confirmdelivery      POST    User Confirms Delivery
19. /api/products                   GET     Get Products
20. /api/products/:pid              GET     Get Individual product
21. /api/checkusername              POST    Checks If Username is Taken
22. /api/ratings/:pid               GET     Get Rating
23. /api/ratings/:pid               POST    Add Rating To Product
24. /api/ratings/:pid               PUT     Update Rating
25. /api/ratings/:pid               DELETE  Delete Rating
26. /api/cart                       GET     Get Cart Items
27. /api/addItem/:pid               POST    Add Item To Cart
28. /api/removeItem/:pid            DELETE  DEL Item In Cart
29. /api/purchase                   POST    Purachse Item
30. /api/userAddress                POST    Add User Address
31. /api/userAddress                DELETE  DEL User Address
32. /api/userAddress                PUT     Update User Address
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More details on the routes are provided in the documentation 👉&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source Code&lt;/strong&gt;: &lt;a href="https://github.com/leoantony72/E-commerce-Api" rel="noopener noreferrer"&gt;https://github.com/leoantony72/E-commerce-Api&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you for your time ...😁&lt;/p&gt;

</description>
      <category>node</category>
      <category>typescript</category>
      <category>postgres</category>
      <category>redis</category>
    </item>
    <item>
      <title>Lava lamps securing the Web?🤷‍♂️</title>
      <dc:creator>Leo Antony</dc:creator>
      <pubDate>Tue, 08 Mar 2022 12:37:22 +0000</pubDate>
      <link>https://forem.com/leoantony72/lava-lamps-securing-the-web-4d20</link>
      <guid>https://forem.com/leoantony72/lava-lamps-securing-the-web-4d20</guid>
      <description>&lt;p&gt;computer generates random number to be used for encryption key, The more random they are the more secure.computer are made to provide predictable output based on given inputs so it isn't suitable for generating encryption key.Nowadays computers have secure lib that provide &lt;strong&gt;CSPRNG&lt;/strong&gt;(Cryptographically-secure pseudorandom number generator) So it's suitable for using as key.&lt;/p&gt;

&lt;p&gt;computers can also be fed with real word random data because events in the physical world are unpredictable and one of the sources of randomness cloudflare uses is &lt;strong&gt;Lava Lamps&lt;/strong&gt;. &lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frxjo3jongpnl4sdy83kq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frxjo3jongpnl4sdy83kq.png" alt="lava lamps encrypt the web" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cloudflare have about 100 lava lamps with camera pointed to them and at regular interval they take pictures and send them to cloudflare servers. Images are stored as series of numbers with each pixel having its value ,So each images becomes a string of &lt;strong&gt;total random numbers&lt;/strong&gt; .This becomes their base to encrypt the internet. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cryptographic seed&lt;/strong&gt; - the data that a CSPRNG program starts with for generating random data. &lt;/p&gt;

&lt;p&gt;*&lt;em&gt;CSPRNG **needs **seed *&lt;/em&gt;(cryptographic seed) as a starting point from which to produce more random data.Clouflare uses a CSPRNG to generate random key with data collected from lava lamps as the seed.&lt;/p&gt;

&lt;p&gt;that's it for this blog , see you next time with more interesting stuff...&lt;/p&gt;

</description>
      <category>cryptography</category>
      <category>security</category>
      <category>hashing</category>
      <category>python</category>
    </item>
  </channel>
</rss>
