<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Sina's blog]]></title><description><![CDATA[Sina's blog]]></description><link>https://sina68.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Fri, 04 Sep 2026 15:44:37 GMT</lastBuildDate><atom:link href="https://sina68.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Building an Instagram clone with GraphQL and Hasura]]></title><description><![CDATA[In this article, our aim is to make a backend that can be used to power an Instagram clone application. We’ll start simple and small in order to build up some core principles of data modeling and how to do so within Hasura.
The beauty of doing GraphQ...]]></description><link>https://sina68.hashnode.dev/building-an-instagram-clone-with-graphql-and-hasura</link><guid isPermaLink="true">https://sina68.hashnode.dev/building-an-instagram-clone-with-graphql-and-hasura</guid><category><![CDATA[Hasura]]></category><category><![CDATA[Hasura Hackathon]]></category><category><![CDATA[GraphQL]]></category><category><![CDATA[instagram]]></category><category><![CDATA[PostgreSQL]]></category><dc:creator><![CDATA[Sina Gharedaghi]]></dc:creator><pubDate>Wed, 23 Mar 2022 19:27:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/_tF3vug2FhQ/upload/v1648063288187/zuWYgMV1z.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this article, our aim is to make a backend that can be used to power an Instagram clone application. We’ll start simple and small in order to build up some core principles of data modeling and how to do so within Hasura.</p>
<p>The beauty of doing GraphQL, more so on the Hasura, is that you can iterate faster. You can get your ideas out there fast, roll out new features, test, and deploy effortlessly. All of this can be done without worrying about configuring the backend infrastructure. This also cuts out common GraphQL implementation tasks like going through the grunt work of setting up GraphQL servers, resolvers, and so on. You spend more time with your ideas and developing your core application. This gives you a pleasant developer experience, and in turn, a robust and pragmatic product cycle.</p>
<h3 id="heading-modeling-data-entities">Modeling data entities</h3>
<p>Our Instagram clone is going to be a fairly stripped-down version with two main data entities: users and photos.</p>
<p>Each user’s feed will contain posts by the users they’re following. Let’s look at such a post and try to pinpoint its different elements:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1648102120831/tkCGXYgSo.jpg" alt="Untitled.jpg" /></p>
<ol>
<li>An image</li>
<li>The username of the user who posted the image</li>
<li>Then an optional description by the user</li>
<li>Comments on the post</li>
<li>Likes on the post</li>
</ol>
<p>We can take the following notes on the basic understanding we have for now on the application data:</p>
<ul>
<li>Users:<ul>
<li>Each user has a username. Like the original Instagram, users can have a real name too, but it’s 
 optional.</li>
<li>An avatar image</li>
<li>An optional “About me” text</li>
<li>An associated email address</li>
<li>Number of followers and followings</li>
<li>Posts</li>
</ul>
</li>
<li>Posts:<ul>
<li>Each post belongs to a single user</li>
<li>Image</li>
<li>An optional text or description accompanying the post or image</li>
<li>Number of likes (for now we’ll consider numbers only)</li>
<li>A post can have zero or more comments</li>
</ul>
</li>
<li>Comment<ul>
<li>Each post can have zero or more comments</li>
<li>The text of the comment</li>
<li>The associated user who made the comment</li>
</ul>
</li>
</ul>
<p>Keeping this functionality in mind, we can now start creating the Database tables. The schema will consist of three types: User, Post, and Comment. These fields will correspond to the observations we’ve just made. We’ll also assume that all the images within the app reside in an external resource.</p>
<p>The following graph diagram can help you better understand the relationships each type has with one another:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1648050803051/OClsbTAUS.png" alt="image.png" /></p>
<h3 id="heading-user-type">User type</h3>
<p>Below is the User table:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1648050839969/YW7zQ6eKV.PNG" alt="userTable.PNG" /></p>
<p>Like in Instagram, the username will act as a unique identifier for each user. </p>
<p>A user can have more than one post, and we’d like to be able to access their data when we’re traversing User nodes in our data graph.</p>
<p>See this <a target="_blank" href="https://hasura.io/docs/latest/graphql/core/schema/table-relationships/create.html#step-1-add-foreign-key-constraint">link</a> for creating relationships through foreign key in hasura. We just need the following relationships.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1648051560090/69EFhM7Rd.png" alt="image.png" /></p>
<h3 id="heading-post-type">Post type</h3>
<p>The post table looks like the following:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1648051278329/sY-QCJ0Ml.PNG" alt="Capture.PNG" /></p>
<p>Conversely, multiple posts can have a single author. In those cases, we’d also like an option of being able to query about their authors too. You can easily see the type of relationship these two types have with each other; we want to define that relationship in our schema and the ability to traverse from both direction.</p>
<p>The same kind of relationship exists between a Post and Comment object. Hence just like users and their posts, we’ve established a bidirectional edge between post and comment objects.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1648051899795/m7ZGtq6pH.png" alt="image.png" /></p>
<h3 id="heading-comment-type">Comment type</h3>
<p>Lastly, the Comment table:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1648051824688/AAvSgANum.png" alt="image.png" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1648051992730/-uZp1Su0U.png" alt="image.png" /></p>
<p>Hasura creates a fully functional GraphQL API that can handle all requests coming in from the client.</p>
<p>We won’t build any UI this time, instead, we’ll use API tab to simulate sending requests from a client to the GraphQL API and see if we can get enough data to render a useful UI. Hasura prepares your server side in mere minutes. From there your efforts can go into building the client with your framework of choice like React, Vue, svelte or any other one. that interacts with the API using a GraphQL client like Apollo or urql.</p>
<h3 id="heading-simulating-various-application-functions">Simulating various application functions</h3>
<p>We can now start exploring application functions that’ll be triggered by different in-app operations.</p>
<p>First, we’ll populate the database with some mock data. This will simulate getting the first couple of users for your application and give us some data to play with. As they start using the app, users start posting photos and comments.</p>
<p>When we create, update, or delete data in GraphQL, we do so by sending a mutation request to the API. The data within the request exactly is then used by the backend to do the operation requested.</p>
<p>For example, consider the following chain of events:</p>
<ul>
<li>A user signs in with the necessary credentials (username, name, email, etc.) and starts using the 
 app.Remember that the User type represents all information regarding a user.<ul>
<li>For each new user, you need to add them to the server by sending a mutation request to the remote 
 API containing those credentials.</li>
</ul>
</li>
<li>The user posts an image with a description.<ul>
<li>It’s a mutation operation corresponding to the Post type that adds it to the database, with some data 
 for the description field.</li>
</ul>
</li>
<li>Someone likes and comments on that post.<ul>
<li>The likes field of that post would be increased by one. This is not adding new data but rather 
  updating or modifying a part of it.</li>
<li>The comment corresponds to the Comment type and there’ll be a mutation request to the API with 
 necessary data adding that comment.</li>
</ul>
</li>
</ul>
<p>The front-end of your app will have mechanisms set up to track these events (for example when you press the like button on a post), and based on the type of event, it’ll send a suitable GraphQL request to the server.</p>
<h3 id="heading-adding-some-new-users">Adding some new users</h3>
<p>paste the following mutation request:</p>
<pre><code><span class="hljs-selector-tag">mutation</span> <span class="hljs-selector-tag">AddSomeUsers</span>($<span class="hljs-attribute">objects</span>: [user_insert_input!]!) {
  <span class="hljs-selector-tag">insert_user</span>(<span class="hljs-attribute">objects</span>: $objects) {
    <span class="hljs-selector-tag">affected_rows</span>
  }
}
</code></pre><p>With the following JSON as the objects query variable:</p>
<pre><code>{
  <span class="hljs-attr">"objects"</span>: [
    {
        <span class="hljs-attr">"username"</span>: <span class="hljs-string">"kmulbery0"</span>,
        <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Kimberlee Mulbery"</span>,
        <span class="hljs-attr">"email"</span>: <span class="hljs-string">"kmulbery0@rediff.com"</span>,
        <span class="hljs-attr">"about"</span>: <span class="hljs-string">"Art, cinema and books."</span>,
        <span class="hljs-attr">"avatarImageURL"</span>: <span class="hljs-string">"https://robohash.org/voluptatibussapientein.png?size=50x50&amp;set=set1"</span>,
        <span class="hljs-attr">"following"</span>: <span class="hljs-number">41</span>,
          <span class="hljs-attr">"follower"</span>: <span class="hljs-number">20</span>
    },
    {
        <span class="hljs-attr">"username"</span>: <span class="hljs-string">"foakes"</span>,
        <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Francis Oakes"</span>,
        <span class="hljs-attr">"email"</span>: <span class="hljs-string">"foakes@liveinternet.ru"</span>,
        <span class="hljs-attr">"avatarImageURL"</span>: <span class="hljs-string">"https://robohash.org/namilloipsam.png?size=50x50&amp;set=set1"</span>,
        <span class="hljs-attr">"following"</span>: <span class="hljs-number">69</span>,
          <span class="hljs-attr">"follower"</span>: <span class="hljs-number">40</span>
    },
    {
        <span class="hljs-attr">"username"</span>: <span class="hljs-string">"docahill2"</span>,
        <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Danny O'Cahill"</span>,
        <span class="hljs-attr">"email"</span>: <span class="hljs-string">"docahill2@prweb.com"</span>,
        <span class="hljs-attr">"about"</span>: <span class="hljs-string">"Welcome to my digital album!"</span>,
        <span class="hljs-attr">"avatarImageURL"</span>: <span class="hljs-string">"https://robohash.org/quiofficiispraesentium.png?size=50x50&amp;set=set1"</span>,
        <span class="hljs-attr">"following"</span>: <span class="hljs-number">4</span>,
          <span class="hljs-attr">"follower"</span>: <span class="hljs-number">10</span>
    },
    {
        <span class="hljs-attr">"username"</span>: <span class="hljs-string">"karen"</span>,
        <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Karen Gillian"</span>,
        <span class="hljs-attr">"email"</span>: <span class="hljs-string">"karen@cnn.com"</span>,
        <span class="hljs-attr">"about"</span>: <span class="hljs-string">"21st century polymath"</span>,
        <span class="hljs-attr">"avatarImageURL"</span>: <span class="hljs-string">"https://robohash.org/fugitetautem.png?size=50x50&amp;set=set1"</span>,
        <span class="hljs-attr">"following"</span>: <span class="hljs-number">60</span>,
          <span class="hljs-attr">"follower"</span>: <span class="hljs-number">22</span>
    },
    {
        <span class="hljs-attr">"username"</span>: <span class="hljs-string">"adury4"</span>,
        <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Anna-diane Dury"</span>,
        <span class="hljs-attr">"email"</span>: <span class="hljs-string">"adury4@businessweek.com"</span>,
        <span class="hljs-attr">"avatarImageURL"</span>: <span class="hljs-string">"https://robohash.org/impediteaet.png?size=50x50&amp;set=set1"</span>,
        <span class="hljs-attr">"following"</span>: <span class="hljs-number">41</span>,
          <span class="hljs-attr">"follower"</span>: <span class="hljs-number">100</span>
    },
    {
        <span class="hljs-attr">"username"</span>: <span class="hljs-string">"rkemwall5"</span>,
        <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Killian Rourke"</span>,
        <span class="hljs-attr">"email"</span>: <span class="hljs-string">"rkemwall5@wired.com"</span>,
        <span class="hljs-attr">"avatarImageURL"</span>: <span class="hljs-string">"https://robohash.org/etenimdeleniti.png?size=50x50&amp;set=set1"</span>,
        <span class="hljs-attr">"following"</span>: <span class="hljs-number">67</span>,
          <span class="hljs-attr">"follower"</span>: <span class="hljs-number">180</span>
    },
    {
        <span class="hljs-attr">"username"</span>: <span class="hljs-string">"cparramore6"</span>,
        <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Cirilo Parramore"</span>,
        <span class="hljs-attr">"email"</span>: <span class="hljs-string">"cparramore6@biglobe.ne.jp"</span>,
        <span class="hljs-attr">"about"</span>: <span class="hljs-string">"Food lover and critique."</span>,
        <span class="hljs-attr">"avatarImageURL"</span>: <span class="hljs-string">"https://robohash.org/inventorefacilisfugiat.png?size=50x50&amp;set=set1"</span>,
        <span class="hljs-attr">"following"</span>: <span class="hljs-number">75</span>,
          <span class="hljs-attr">"follower"</span>: <span class="hljs-number">100</span>
    },
    {
        <span class="hljs-attr">"username"</span>: <span class="hljs-string">"ff8"</span>,
        <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Raymond Ferdinand"</span>,
        <span class="hljs-attr">"email"</span>: <span class="hljs-string">"ray@gmail.com"</span>,
        <span class="hljs-attr">"about"</span>: <span class="hljs-string">"Freelance artist"</span>,
        <span class="hljs-attr">"avatarImageURL"</span>: <span class="hljs-string">"https://robohash.org/ipsambeataeest.png?size=50x50&amp;set=set1"</span>,
        <span class="hljs-attr">"following"</span>: <span class="hljs-number">1022</span>,
          <span class="hljs-attr">"follower"</span>: <span class="hljs-number">13000</span>
    },
    {
        <span class="hljs-attr">"username"</span>: <span class="hljs-string">"shaw"</span>,
        <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Sebastian Shaw"</span>,
        <span class="hljs-attr">"email"</span>: <span class="hljs-string">"sshaw8@mail.ru"</span>,
        <span class="hljs-attr">"about"</span>: <span class="hljs-string">"Writer of useless things."</span>,
        <span class="hljs-attr">"avatarImageURL"</span>: <span class="hljs-string">"https://robohash.org/illumsintvoluptas.png?size=50x50&amp;set=set1"</span>,
        <span class="hljs-attr">"following"</span>: <span class="hljs-number">6</span>,
          <span class="hljs-attr">"follower"</span>: <span class="hljs-number">11</span>
    }
  ]
}
</code></pre><p>Here we’re sending an insert_user mutation to invoke the operation. We optionally have named it AddSomeUser, but you can exclude that if you want. It’s good practice to separate the mutation data into a query variable when the data is large, as we’ve done here with the objects variable. It keeps the main query body clear and readable.</p>
<h3 id="heading-posting-some-pictures-on-your-instaclone-app">Posting some pictures on your InstaClone app</h3>
<p>So some users have installed the app on their devices and they’re likely to start posting. So let’s simulate that! As you can probably guess, it’s going to an insert_post type mutation:</p>
<pre><code><span class="hljs-selector-tag">mutation</span> <span class="hljs-selector-tag">AddSomePosts</span>($<span class="hljs-attribute">objects</span>: [post_insert_input!]!) {
  <span class="hljs-selector-tag">insert_post</span>(<span class="hljs-attribute">objects</span>: $objects) {
    <span class="hljs-selector-tag">affected_rows</span>
  }
}
</code></pre><p>With query variable as:</p>
<pre><code>{
  <span class="hljs-attr">"objects"</span>: [
    {
            <span class="hljs-attr">"username"</span>: <span class="hljs-string">"karen"</span>,
            <span class="hljs-attr">"description"</span>: <span class="hljs-string">"A new antique book I just collected!"</span>,
            <span class="hljs-attr">"likes"</span>: <span class="hljs-number">0</span>,
            <span class="hljs-attr">"imageURL"</span>: <span class="hljs-string">"http://dummyimage.com/107x100.png/ff4444/ffffff"</span>
        },
        {
            <span class="hljs-attr">"username"</span>: <span class="hljs-string">"kmulbery0"</span>,
            <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Some amazing shots from the film Drive (2011)"</span>,
            <span class="hljs-attr">"likes"</span>: <span class="hljs-number">0</span>,
            <span class="hljs-attr">"imageURL"</span>: <span class="hljs-string">"http://dummyimage.com/138x100.png/5fa2dd/ffffff"</span>
        },
        {
            <span class="hljs-attr">"username"</span>: <span class="hljs-string">"foakes"</span>,
            <span class="hljs-attr">"description"</span>: <span class="hljs-string">"We went on a hike!"</span>,
            <span class="hljs-attr">"likes"</span>: <span class="hljs-number">0</span>,
            <span class="hljs-attr">"imageURL"</span>: <span class="hljs-string">"http://dummyimage.com/103x100.png/ff4444/ffffff"</span>
        },
        {
            <span class="hljs-attr">"username"</span>: <span class="hljs-string">"docahill2"</span>,
            <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Minnie likes the sunny day today. Just look at her!"</span>,
            <span class="hljs-attr">"likes"</span>: <span class="hljs-number">0</span>,
            <span class="hljs-attr">"imageURL"</span>: <span class="hljs-string">"http://dummyimage.com/247x100.png/5fa2dd/ffffff"</span>
        },
        {
            <span class="hljs-attr">"username"</span>: <span class="hljs-string">"adury4"</span>,
            <span class="hljs-attr">"likes"</span>: <span class="hljs-number">0</span>,
            <span class="hljs-attr">"imageURL"</span>: <span class="hljs-string">"http://dummyimage.com/107x100.png/cc0000/ffffff"</span>
        },
        {
            <span class="hljs-attr">"username"</span>: <span class="hljs-string">"rkemwall5"</span>,
            <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Workout time..."</span>,
            <span class="hljs-attr">"likes"</span>: <span class="hljs-number">0</span>,
            <span class="hljs-attr">"imageURL"</span>: <span class="hljs-string">"http://dummyimage.com/194x100.png/5fa2dd/ffffff"</span>
        },
        {
            <span class="hljs-attr">"username"</span>: <span class="hljs-string">"cparramore6"</span>,
            <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Will come back here just for this burger."</span>,
            <span class="hljs-attr">"likes"</span>: <span class="hljs-number">0</span>,
            <span class="hljs-attr">"imageURL"</span>: <span class="hljs-string">"http://dummyimage.com/161x100.png/cc0000/ffffff"</span>
        },
        {
            <span class="hljs-attr">"username"</span>: <span class="hljs-string">"ff8"</span>,
            <span class="hljs-attr">"description"</span>: <span class="hljs-string">"My new concept art. Please share!"</span>,
            <span class="hljs-attr">"likes"</span>: <span class="hljs-number">0</span>,
            <span class="hljs-attr">"imageURL"</span>: <span class="hljs-string">"http://dummyimage.com/179x100.png/5fa2dd/ffffff"</span>
        },
        {
            <span class="hljs-attr">"username"</span>: <span class="hljs-string">"shaw"</span>,
            <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Cover photo of my book that's hitting the shelves in September!"</span>,
            <span class="hljs-attr">"likes"</span>: <span class="hljs-number">0</span>,
            <span class="hljs-attr">"imageURL"</span>: <span class="hljs-string">"http://dummyimage.com/220x100.png/dddddd/000000"</span>
        }
  ]
}
</code></pre><p>Since they are new posts, all of them have zero likes for now. In the next step let’s simulate other users liking and commenting on them.</p>
<h3 id="heading-adding-comments-on-instaclone-posts">Adding comments on InstaClone posts</h3>
<p>You have to know the IDs of all the posts since you’ll need that to connect a comment with the post via the commentOn field. You also need to know the usernames of existing users for the commentBy field. The following query fetches IDs of existing posts along with usernames of their posters:</p>
<pre><code><span class="hljs-attribute">query</span> queryAllPosts {
  <span class="hljs-section">post</span> {
    <span class="hljs-attribute">id</span>
    postedBy {
      <span class="hljs-attribute">username</span>
    }
  }
}
</code></pre><p>It gives the following response:</p>
<pre><code>{
  <span class="hljs-attr">"data"</span>: {
    <span class="hljs-attr">"post"</span>: [
      {
        <span class="hljs-attr">"id"</span>: <span class="hljs-string">"a84e5680-1659-44d6-aa38-d0c8658b327f"</span>,
        <span class="hljs-attr">"postedBy"</span>: {
          <span class="hljs-attr">"username"</span>: <span class="hljs-string">"karen"</span>
        }
      },
      {
        <span class="hljs-attr">"id"</span>: <span class="hljs-string">"dae5a80d-7cd4-4641-a6c5-58cb1844b025"</span>,
        <span class="hljs-attr">"postedBy"</span>: {
          <span class="hljs-attr">"username"</span>: <span class="hljs-string">"kmulbery0"</span>
        }
      },
      ...
    ]
  }
}
</code></pre><p>Now we’re ready to do an insert_comment mutation to add some comments:</p>
<pre><code><span class="hljs-selector-tag">mutation</span> <span class="hljs-selector-tag">AddSomePosts</span>($<span class="hljs-attribute">objects</span>: [comment_insert_input!]!) {
  <span class="hljs-selector-tag">insert_comment</span>(<span class="hljs-attribute">objects</span>: $objects) {
    <span class="hljs-selector-tag">affected_rows</span>
  }
}
</code></pre><p>For simplicity, let’s assume that existing users will comment on one another’s posts. The following is the data of the query variable:</p>
<pre><code>{
  <span class="hljs-attr">"objects"</span>: [
    {
      <span class="hljs-attr">"text"</span>: <span class="hljs-string">"This book's a fantastic addition to your other collections"</span>,
      <span class="hljs-attr">"postId"</span>: <span class="hljs-string">"a84e5680-1659-44d6-aa38-d0c8658b327f"</span>,
      <span class="hljs-attr">"username"</span>: <span class="hljs-string">"kmulbery0"</span>
    },
    {
      <span class="hljs-attr">"text"</span>: <span class="hljs-string">"It's soundtrack made me fall in love with synth and electronic music. Nightcall is goat"</span>,
      <span class="hljs-attr">"postId"</span>: <span class="hljs-string">"dae5a80d-7cd4-4641-a6c5-58cb1844b025"</span>,
      <span class="hljs-attr">"username"</span>: <span class="hljs-string">"karen"</span>
    },
    {
      <span class="hljs-attr">"text"</span>: <span class="hljs-string">"Minnie cures my sadness every time for the time being. What a sweetie!"</span>,
      <span class="hljs-attr">"postId"</span>: <span class="hljs-string">"d6602d89-3fe5-4ffa-9ee1-d5aaeb4de329"</span>,
      <span class="hljs-attr">"username"</span>: <span class="hljs-string">"foakes"</span>
    }
  ]
}
</code></pre><h3 id="heading-liking-posts">Liking posts</h3>
<p>Now let’s simulate the event of liking posts. As I mentioned previously, this falls under the update operation category that updates an already existing piece of data or a part of it, like someone gaining a new follower. Let’s see how this works. When someone hits the like button on a post, that event would trigger the associated mechanism and the app would use the id of the post to update its like data. It’ll use the following query to do so:</p>
<pre><code>mutation LikeSomePosts($id: uuid!, $likes: <span class="hljs-keyword">Int</span>!) {
  update_post_by_pk(pk_columns: {id: $id}, _set: {likes: $likes}) {
    id
    likes
  }
}
</code></pre><p>The query variable contains:</p>
<pre><code>{
  <span class="hljs-attr">"id"</span>: <span class="hljs-string">"a84e5680-1659-44d6-aa38-d0c8658b327f"</span>,
  <span class="hljs-attr">"likes"</span>: <span class="hljs-number">12</span>
}
</code></pre><p>In this same way you can also dispatch an update_user request and set its follower field when someone gains (or loses) a follower.</p>
<h3 id="heading-generating-the-application-feed">Generating the application feed</h3>
<p>The application feed would contain posts from the users someone is following. Can you guess how to fetch all the data for that?</p>
<p>Hasura has a robust set of search and filtering tools that you can use in scenarios such as this. Here, the app just needs to send a query post request asking for all the posts from everyone the user is following. Since usernames can uniquely identify each user, the app can use that as a filter. For example, the following fetches data from two users:</p>
<pre><code><span class="hljs-selector-tag">query</span> {
  <span class="hljs-selector-tag">user</span>(<span class="hljs-attribute">where</span>: {<span class="hljs-attribute">username</span>: {<span class="hljs-attribute">_in</span>: [<span class="hljs-string">"kmulbery0"</span>, <span class="hljs-string">"rkemwall5"</span>]}}) {
    <span class="hljs-selector-tag">username</span>
    <span class="hljs-selector-tag">avatarImageURL</span>
    <span class="hljs-selector-tag">posts</span> {
      <span class="hljs-selector-tag">description</span>
      <span class="hljs-selector-tag">imageURL</span>
      <span class="hljs-selector-tag">comments</span> {
        <span class="hljs-selector-tag">text</span>
        <span class="hljs-selector-tag">commentBy</span> {
          <span class="hljs-selector-tag">username</span>
          <span class="hljs-selector-tag">avatarImageURL</span>
        }
      }
    }
  }
}
</code></pre><p>This yields:</p>
<pre><code>{
  <span class="hljs-attr">"data"</span>: {
    <span class="hljs-attr">"user"</span>: [
      {
        <span class="hljs-attr">"username"</span>: <span class="hljs-string">"kmulbery0"</span>,
        <span class="hljs-attr">"avatarImageURL"</span>: <span class="hljs-string">"https://robohash.org/voluptatibussapientein.png?size=50x50&amp;set=set1"</span>,
        <span class="hljs-attr">"posts"</span>: [
          {
            <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Some amazing shots from the film Drive (2011)"</span>,
            <span class="hljs-attr">"imageURL"</span>: <span class="hljs-string">"http://dummyimage.com/138x100.png/5fa2dd/ffffff"</span>,
            <span class="hljs-attr">"comments"</span>: [
              {
                <span class="hljs-attr">"text"</span>: <span class="hljs-string">"It's soundtrack made me fall in love with synth and electronic music. Nightcall is goat"</span>,
                <span class="hljs-attr">"commentBy"</span>: {
                  <span class="hljs-attr">"username"</span>: <span class="hljs-string">"karen"</span>,
                  <span class="hljs-attr">"avatarImageURL"</span>: <span class="hljs-string">"https://robohash.org/fugitetautem.png?size=50x50&amp;set=set1"</span>
                }
              }
            ]
          }
        ]
      },
      {
        <span class="hljs-attr">"username"</span>: <span class="hljs-string">"rkemwall5"</span>,
        <span class="hljs-attr">"avatarImageURL"</span>: <span class="hljs-string">"https://robohash.org/etenimdeleniti.png?size=50x50&amp;set=set1"</span>,
        <span class="hljs-attr">"posts"</span>: [
          {
            <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Workout time..."</span>,
            <span class="hljs-attr">"imageURL"</span>: <span class="hljs-string">"http://dummyimage.com/194x100.png/5fa2dd/ffffff"</span>,
            <span class="hljs-attr">"comments"</span>: []
          }
        ]
      }
    ]
  }
}
</code></pre><p>You have the usernames and their associated avatars, and their posts with images, descriptions and comments. They’re all you need to render the feed.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>In this article, we learned how to use a GraphQL schema to model an application’s data and bring it under an explicit structure defining its various data objects and relationships. Later we saw how to process various requests to fetch and modify data. GraphQL is the perfect tool to use in social media applications where data is highly connected and you need to traverse these graphs to compose satisfactory responses for the request traffic.</p>
<p>Hasura makes GraphQL super-easy like none other by bringing you a production-ready GraphQL API and corresponding database just from a single schema. It gives you a highly scalable way to meet your application’s evolving set of requirements. No need to write API boilerplates, then get distracted in connecting layers and tools to get the server side ready.</p>
]]></content:encoded></item></channel></rss>