<?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: Ahmed Ehab</title>
    <description>The latest articles on Forem by Ahmed Ehab (@ahmedehab).</description>
    <link>https://forem.com/ahmedehab</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%2F580910%2Fc8873074-99fc-445a-975c-649aa9f58ef9.jpeg</url>
      <title>Forem: Ahmed Ehab</title>
      <link>https://forem.com/ahmedehab</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ahmedehab"/>
    <language>en</language>
    <item>
      <title>Building and Installing VS Code Extensions in Cursor</title>
      <dc:creator>Ahmed Ehab</dc:creator>
      <pubDate>Tue, 17 Feb 2026 21:11:59 +0000</pubDate>
      <link>https://forem.com/ahmedehab/building-and-installing-vs-code-extensions-in-cursor-5can</link>
      <guid>https://forem.com/ahmedehab/building-and-installing-vs-code-extensions-in-cursor-5can</guid>
      <description>&lt;p&gt;While working with Cursor, I discovered a serious limitation to what Cursor can do.&lt;/p&gt;

&lt;p&gt;Cursor allows the installation of VS Code extensions, but not every extension in VS Code is available directly within Cursor's marketplace.&lt;br&gt;
This is mainly because Cursor was separated from VS Code some time ago, which created compatibility issues with certain extensions.&lt;/p&gt;

&lt;p&gt;Since it was not easily accessible or compatible through standard installation methods, I looked into building the extension from source and installing it manually.&lt;/p&gt;

&lt;p&gt;I faced this problem while trying to install the &lt;code&gt;pgFormatter&lt;/code&gt; extension. Which I will use as an example.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why does this happen?
&lt;/h2&gt;

&lt;p&gt;Cursor is built on the VS Code source code, and subsequently, its extension ecosystem. So, that means it supports the same extension packaging format.&lt;/p&gt;

&lt;p&gt;However, the reality is some extensions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are not listed in Cursor's marketplace&lt;/li&gt;
&lt;li&gt;Depend on APIs or versions that differ from Cursor&lt;/li&gt;
&lt;/ul&gt;


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

&lt;p&gt;VS Code extensions usually are compiled and built as .vsix files. A VSIX file is a packaged bundle that includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compiled extension code.&lt;/li&gt;
&lt;li&gt;Metadata and dependency information.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Building an Extension from Source
&lt;/h2&gt;

&lt;p&gt;The first step is obtaining the extension source code. In this example, the goal was to build the &lt;code&gt;pgFormatter&lt;/code&gt; extension locally.&lt;/p&gt;

&lt;p&gt;After downloading the extension source (mostly it will be on GitHub), the directory structure looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;package.json
src/
tsconfig.json
vsc-extension-quickstart.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 1: Install Dependencies
&lt;/h3&gt;

&lt;p&gt;Go to the extension directory and install the required dependencies by running this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Package the Extension
&lt;/h3&gt;

&lt;p&gt;Once the installation finishes, package the extension into a VSIX file using the VS Code Extension CLI tool.&lt;br&gt;
Run the following command to do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx vsce package
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the process completes successfully, it produces a &lt;code&gt;.vsix&lt;/code&gt; file similar to: &lt;code&gt;pgformatter-1.33.0.vsix&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Installing in Cursor
&lt;/h3&gt;

&lt;p&gt;After generating the VSIX file, the extension can be installed easily into Cursor as follows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Command Palette Installation:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open Cursor&lt;/li&gt;
&lt;li&gt;Open the Command Palette:

&lt;ul&gt;
&lt;li&gt;macOS: &lt;code&gt;Cmd + Shift + P&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Windows/Linux: &lt;code&gt;Ctrl + Shift + P&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Run: &lt;code&gt;Extensions: Install from VSIX...&lt;/code&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%2Fmiebpl6v7pf6c9fse3q9.webp" alt="Extensions: Install from VSIX in VS Code Command Palette" width="593" height="109"&gt;
&lt;/li&gt;
&lt;li&gt;Select the generated &lt;code&gt;.vsix&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;(Optional) If the extension isn't active yet, you can reload Cursor by doing the following action: &lt;code&gt;Developer: Reload Window&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Practical Considerations
&lt;/h2&gt;

&lt;p&gt;While this method works fine, there are a few things to keep in mind:&lt;/p&gt;

&lt;h3&gt;
  
  
  Security Considerations
&lt;/h3&gt;

&lt;p&gt;Installing extensions from source means you are responsible for verifying the code being installed. Reviewing the repository and dependencies is really recommended.&lt;br&gt;
I can't stress this enough, extensions with bad intentions and malicious code can seriously harm or compromise your code base or your system or your users.&lt;/p&gt;

&lt;h3&gt;
  
  
  Maintenance
&lt;/h3&gt;

&lt;p&gt;Manually installed extensions do not automatically update. Doing this process again will be necessary when new versions are released.&lt;/p&gt;

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

&lt;p&gt;Cursor uses the same extension packaging model as VS Code, which means developers can manually compile and install extensions when they can't access the marketplace directly.&lt;/p&gt;

&lt;p&gt;By generating a VSIX file from the extension, and then installing it manually, we can keep using important extensions like pgFormatter without getting stuck due to differences in the ecosystem.&lt;/p&gt;

</description>
      <category>cursor</category>
      <category>productivity</category>
      <category>vscode</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Sync all of your LeetCode solutions to Github using glsync</title>
      <dc:creator>Ahmed Ehab</dc:creator>
      <pubDate>Tue, 18 Feb 2025 00:20:24 +0000</pubDate>
      <link>https://forem.com/ahmedehab/sync-all-of-your-leetcode-solutions-to-github-using-glsync-2jg</link>
      <guid>https://forem.com/ahmedehab/sync-all-of-your-leetcode-solutions-to-github-using-glsync-2jg</guid>
      <description>&lt;p&gt;Hey all,&lt;/p&gt;

&lt;p&gt;I developed &lt;a href="https://github.com/ahmed-e-abdulaziz/glsync" rel="noopener noreferrer"&gt;glsync&lt;/a&gt;, a CLI tool to sync all your LeetCode submissions to Github (and possibly any other Git client). Each solution will be committed based on its submission date on LeetCode.&lt;/p&gt;

&lt;p&gt;You can create a custom repo on GitHub, and glsync will get all of your submissions from LeetCode and push it into this custom repo. It can also work with Gitlab and other Git repos.&lt;/p&gt;

&lt;p&gt;I found a lack of similar tools that sync ALL of your submissions, not one at a time.&lt;/p&gt;

&lt;p&gt;You can view and download it here: &lt;a href="https://github.com/ahmed-e-abdulaziz/glsync" rel="noopener noreferrer"&gt;https://github.com/ahmed-e-abdulaziz/glsync&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I created it because companies judge interviewees by how frequently they commit to Github. This can make time spent in LeetCode feel invisible to them, as it won't be visible on your GitHub profile.&lt;/p&gt;

&lt;p&gt;I did this in about a week, so if you want more features, support other platforms, or encounter bugs, feel free to send me a message.&lt;/p&gt;

</description>
      <category>go</category>
      <category>leetcode</category>
      <category>github</category>
      <category>programming</category>
    </item>
    <item>
      <title>HTTP Idempotency</title>
      <dc:creator>Ahmed Ehab</dc:creator>
      <pubDate>Sun, 02 Jan 2022 18:20:50 +0000</pubDate>
      <link>https://forem.com/ahmedehab/http-idempotency-2gg8</link>
      <guid>https://forem.com/ahmedehab/http-idempotency-2gg8</guid>
      <description>&lt;h2&gt;
  
  
  Idempotency?
&lt;/h2&gt;

&lt;p&gt;Have you accidentally clicked the order button twice on any e-commerce and still ordered a single order? Well, you have idempotency to thank for that (And the developer who implemented it 👨‍💻)!&lt;br&gt;
So what is Idempotency? Although it looks like a complex term, it is a simple concept.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Insanity is doing the same thing over and over and expecting different results. - 'Albert Einstein'&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Client-Server Idempotency
&lt;/h2&gt;

&lt;p&gt;For HTTP API design, you won't run the same operation twice when an idempotent API is called twice with the same data. So if the client/frontend calls a &lt;code&gt;PUT&lt;/code&gt; API twice to update a user's data, the server/backend would recognize it is the same request and update the data only once.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why would I need it?
&lt;/h2&gt;

&lt;p&gt;The reason a client would call the server twice might mostly not be because a user clicked a button two times. It is attributed more to network failures. For example, if an acknowledgment response for the update is &lt;strong&gt;NOT&lt;/strong&gt; returned because of a network failure, the client might automatically send the same request again. From its point of view, the update request itself has yet to arrive at the server.&lt;/p&gt;

&lt;p&gt;&lt;a href="/uploads/NonIdempVsIdemp.png" class="article-body-image-wrapper"&gt;&lt;img src="/uploads/NonIdempVsIdemp.png" alt="Non-Idempotent Requests versus Idempotent requests"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Safe vs. Idempotent
&lt;/h2&gt;

&lt;p&gt;Another classification of HTTP methods to consider is safe methods.&lt;br&gt;
Safe methods do not change any resource on the server, i.e., queries.&lt;/p&gt;

&lt;p&gt;The difference is that idempotency concerns that we can call the same response many times and get the same answer.&lt;br&gt;
While safe methods are concerned with keeping the same state of the resources on the servers with the first or the hundredth response as it treats resources in a read-only fashion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Idempotent, Safe and non-idempotent HTTP Method
&lt;/h2&gt;

&lt;p&gt;In the following table, we can see where each commonly-used HTTP methods fall in the previous categorization.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Safe&lt;/th&gt;
&lt;th&gt;Idempotent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HEAD&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;OPTIONS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TRACE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PUT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DELETE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;POST&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PATCH&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This shows that the real difference between Safe and Idempotent concepts is evident when we look at the behavior of the &lt;code&gt;PUT&lt;/code&gt; and &lt;code&gt;DELETE&lt;/code&gt; methods.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;DELETE&lt;/code&gt; method is not safe as it changes the resource/server state by deletion. However, it is idempotent because if we call &lt;code&gt;DELETE&lt;/code&gt; on /user/1, for example, to delete a user with an ID of 1, the server shouldn't go and delete the user with an ID of 2 if it doesn't find it. It will reply with 200/204 as well since although it didn't find it, it's still not a fault to call it twice, as we have seen earlier.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;PUT&lt;/code&gt; method follows the same idea, it replaces a whole object with another entire object or adds a new one, so it will reply with the same response each time, but each time it's doing an update query on the server.&lt;/p&gt;

&lt;h2&gt;
  
  
  How will this matter to me/my team?
&lt;/h2&gt;

&lt;p&gt;From a backend/server-side perspective, you have to respect the HTTP method and use them correctly according to its semantic meaning. Thus, a &lt;code&gt;GET&lt;/code&gt; method, for example, must not change a state as it is safe and must not change the response type it returns as it is idempotent.&lt;/p&gt;

&lt;p&gt;From a frontend/client-side perspective, you can call any idempotent endpoint many times with no fear of misbehavior, given your backend team is following the HTTP specs and semantics correctly.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>computerscience</category>
      <category>codequality</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Richardson Maturity Model</title>
      <dc:creator>Ahmed Ehab</dc:creator>
      <pubDate>Sun, 18 Apr 2021 13:54:11 +0000</pubDate>
      <link>https://forem.com/ahmedehab/richardson-maturity-model-237l</link>
      <guid>https://forem.com/ahmedehab/richardson-maturity-model-237l</guid>
      <description>&lt;h2&gt;
  
  
  Are you RESTful?
&lt;/h2&gt;

&lt;p&gt;So, right now, everyone and their mother is creating REST APIs. However, are all REST APIs created as equals?&lt;br&gt;
As I said in my &lt;a href="https://ahmedehab.com/rest-fundamentals" rel="noopener noreferrer"&gt;rest fundamentals article&lt;/a&gt;, &lt;strong&gt;Roy Fielding&lt;/strong&gt;, the creator of REST, &lt;a href="https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven" rel="noopener noreferrer"&gt;is &lt;em&gt;getting frustrated by the number of people calling any HTTP-based interface a REST API&lt;/em&gt;&lt;/a&gt;.&lt;br&gt;
Even so, a black-or-white scale for whether an API is RESTful can be misleading. Thus, &lt;strong&gt;Leonard Richardson&lt;/strong&gt; designed a way to define how much an API conforms to the RESTful standards, creating the Richardson Maturity Model or RMM.&lt;/p&gt;
&lt;h2&gt;
  
  
  RMM
&lt;/h2&gt;

&lt;p&gt;RMM aims to describe a specific grade for how much an API conforms to the RESTful standards. Maturity here means conformity to RESTful standards. It has four levels of maturity levels from level 0 to level 3.&lt;/p&gt;

&lt;p&gt;The great thing is that it doesn't shun away any API that is not fully RESTful. It has some specific measurements that will allow engineers to quickly assess how scalable their endpoints are according to the RESTful standards and what can be improved to reach a higher level.&lt;/p&gt;

&lt;p&gt;&lt;a href="/uploads/RMM.png" class="article-body-image-wrapper"&gt;&lt;img src="/uploads/RMM.png" alt="RMM Hierarchy"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Level 0 (Swamp of POX)
&lt;/h2&gt;

&lt;p&gt;In this level, a single URI can serve multiple resources and actions, and HTTP verb usage is incorrect (mostly only POST).&lt;/p&gt;

&lt;p&gt;For example, you can have a URI that looks like this &lt;code&gt;/usersManagement&lt;/code&gt;, which will serve to query, update, delete and create users using only the &lt;code&gt;POST&lt;/code&gt; HTTP verb. To differentiate between the various obscure actions that the endpoint can do at this level, the body of the request will have to have the specific requirements of the request.&lt;/p&gt;

&lt;p&gt;This level is not considered RESTful by RMM and mainly exists in the SOAP Web Services world. That's why it's called the Swamp of POX, as POX means Plain Old XML, and the level of coupling and obscurity of the endpoints in this level led to it being called a Swamp.&lt;/p&gt;

&lt;p&gt;I have experienced integrating with SOAP services, and let me tell you that this level is awful and leads to a lot of confusion and mistakes.&lt;/p&gt;
&lt;h2&gt;
  
  
  Level 1 (Resources)
&lt;/h2&gt;

&lt;p&gt;At level 1, we will use different URIs for different resources but still only use one HTTP verb (generally &lt;code&gt;POST&lt;/code&gt; as well), leading to better decoupling in the API.&lt;/p&gt;

&lt;p&gt;So using the previous example, instead of having one &lt;code&gt;/usersManagement&lt;/code&gt; endpoint, we will have &lt;code&gt;/usersCreate&lt;/code&gt;, &lt;code&gt;/usersUpdate&lt;/code&gt;, &lt;code&gt;/usersDelete&lt;/code&gt;, and &lt;code&gt;/usersQuery&lt;/code&gt; while using only &lt;code&gt;POST&lt;/code&gt; HTTP verb for all of them. We won't be using the body to define the action, though.&lt;/p&gt;

&lt;p&gt;Although, level 1 is much better than the previous level. It still isn't considered RESTful enough by RMM. At the start of my career, I worked on a project with an API that would primarily reside at this level, and it was extremely cumbersome to keep creating and integrating with APIs like this. Furthermore, the whole suffix I used in this example needs to be standardized. It was basically whatever the developer would think was correct, which would differ wildly per developer.&lt;/p&gt;

&lt;p&gt;For example, someone would query users with &lt;code&gt;/usersQuery&lt;/code&gt;. Still, for address querying, the endpoint would be &lt;code&gt;/addressRetrieval&lt;/code&gt;, and someone else would retrieve departments using &lt;code&gt;/getDepartments&lt;/code&gt;, leading to a highly fragmented API.&lt;/p&gt;
&lt;h2&gt;
  
  
  Level 2 (HTTP Verbs)
&lt;/h2&gt;

&lt;p&gt;Here we are at a level that is considered RESTful by a lot of RMM advocates. However, Roy Fielding believes it needs to be RESTful more. In my opinion, this level is RESTful and can provide the requirements of a RESTful API.&lt;/p&gt;

&lt;p&gt;Anyway, now we will put HTTP verbs to actual use. Let's use the previous example. Now the users will have the following endpoint &lt;code&gt;/users&lt;/code&gt;. Then to retrieve users, we will create a request with a &lt;code&gt;GET&lt;/code&gt; HTTP verb to the users' endpoint. We will use the &lt;code&gt;DELETE&lt;/code&gt; HTTP verb to delete a user in the request to indicate the action. To update, you can use &lt;code&gt;PUT&lt;/code&gt; or &lt;code&gt;PATCH&lt;/code&gt;. We can use &lt;code&gt;GET&lt;/code&gt;, &lt;code&gt;POST&lt;/code&gt;, &lt;code&gt;PUT&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt;, and more for other endpoints like that address or department.&lt;/p&gt;

&lt;p&gt;The majority of Web APIs never pass this level. Mainly, that's okay; this level can provide almost all RESTful requirements. It only needs a self-descriptive API. The API dev delivers the client documentation beforehand. Thus, it will also require documentation to define the necessary endpoints for various actions on the retrieved entity.&lt;/p&gt;
&lt;h2&gt;
  
  
  Level 3 (HATEOAS)
&lt;/h2&gt;

&lt;p&gt;Finally, we arrive at the last level here. The HATEOAS principles reside here.&lt;br&gt;
When we get the users from the &lt;code&gt;/users&lt;/code&gt; endpoint with the &lt;code&gt;GET&lt;/code&gt; HTTP verb, the response for getting a user will look like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ahmed Ehab Abdulaziz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ahmed.ehab5010@gmail.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"links"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"self"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"href"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://ahmedehab.com/user/1"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"update"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"href"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://ahmedehab.com/user/1"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"delete"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"href"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://ahmedehab.com/user/1"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"report"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"href"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://ahmedehab.com/user/1/report/default"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"tax-report"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"href"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://ahmedehab.com/user/1/report/tax"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we don't need the update, delete, report, or tax-report actions to be hard coded in our code.&lt;br&gt;
When we get the users array, we will get the API to do the various actions with the endpoint per user through the response as in the example.&lt;/p&gt;

&lt;p&gt;I want to go over HATEOAS sparingly, as it deserves its article. You can find more about it in &lt;a href="https://ahmedehab.com/hateoas" rel="noopener noreferrer"&gt;my article here&lt;/a&gt;. Lastly, everyone considers this level RESTful, including &lt;strong&gt;Roy Fielding&lt;/strong&gt;, &lt;a href="https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven" rel="noopener noreferrer"&gt;who regards it as a prerequisite to having a RESTful API&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which level should I develop for?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Levels 0 and 1&lt;/strong&gt; are still in use today, and many web applications are developed with levels 0 or 1. However, &lt;strong&gt;level 2&lt;/strong&gt; for greenfield web API today is considered acceptable. Whether calling it a RESTful API or not, it leads to a cleaner API and does not put overhead on the developers or the API architect.&lt;/p&gt;

&lt;p&gt;As for level 3, you need to consider the users' bandwidth. Also, the primary purpose of HATEOAS is to deal with changes in the API efficiently. Changes have never been an issue for internal applications, and the new APIs are adapted to the old ones. The other way around is much harder for this type of project. Besides, many developers don't understand or even know what HATEOAS is. Some training might be required to onboard them.&lt;br&gt;
However, for SaaS-based projects or other projects with an external API exposed to many different systems, HATEOAS and Level 3 can be of immense practicality. You can easily swap out old APIs with new APIs without having to change a line of code in the integrating services.&lt;/p&gt;

&lt;p&gt;P.S. You should read the &lt;strong&gt;Roy Fielding&lt;/strong&gt; article that mentions that REST APIs must be hypertext. The discussions there are fascinating. You can visit it from &lt;a href="https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>rest</category>
      <category>architecture</category>
      <category>webdev</category>
      <category>api</category>
    </item>
    <item>
      <title>WTF is HATEOAS?</title>
      <dc:creator>Ahmed Ehab</dc:creator>
      <pubDate>Tue, 23 Feb 2021 14:37:42 +0000</pubDate>
      <link>https://forem.com/ahmedehab/wtf-is-hateoas-h96</link>
      <guid>https://forem.com/ahmedehab/wtf-is-hateoas-h96</guid>
      <description>&lt;p&gt;&lt;strong&gt;H&lt;/strong&gt;ypermedia &lt;strong&gt;A&lt;/strong&gt;s &lt;strong&gt;T&lt;/strong&gt;he &lt;strong&gt;E&lt;/strong&gt;ngine &lt;strong&gt;O&lt;/strong&gt;f &lt;strong&gt;A&lt;/strong&gt;pplication &lt;strong&gt;S&lt;/strong&gt;tate or HATEOAS is a significant part of REST architecture to provide a Uniform Interface, which is one of the main fundamentals of REST. You can read more about REST fundamentals in &lt;a href="https://ahmedehab.com/rest-fundamentals" rel="noopener noreferrer"&gt;my previous post&lt;/a&gt;. Here I will explain it and why it was created.&lt;/p&gt;

&lt;h2&gt;
  
  
  In a Perfect World
&lt;/h2&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%2Fuubrerrsdymtjzrvglng.gif" 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%2Fuubrerrsdymtjzrvglng.gif" alt="Perfect!" width="480" height="344"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's say we have a system that needs to expose an API to manage the user entity. That API will do CRUD operations in addition to supporting generating a report of the user billing for the last month; thus, the following endpoints were created in the backend:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get all users: &lt;code&gt;GET https://ahmedehab.com/users/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Get a single user with an ID of 1: &lt;code&gt;GET https://ahmedehab.com/users/1/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create a new user: &lt;code&gt;POST https://ahmedehab.com/users/&lt;/code&gt; (Or PUT for idempotency, more on that in a later post)&lt;/li&gt;
&lt;li&gt;Update a user: &lt;code&gt;PUT https://ahmedehab.com/users/1/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;DELETE a user: &lt;code&gt;DELETE https://ahmedehab.com/users/1/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Retrieve a billing report for a user: &lt;code&gt;GET https://ahmedehab.com/users/1/report&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Now, in a perfect world, these endpoints are and will always be the go-to endpoints to manage a user. We will never need to make a new change here, or will we?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Imperfect World
&lt;/h2&gt;

&lt;p&gt;Realistically, the backend endpoints will change over time for any large project. So for our example, a new architect was hired. He doesn't believe resources (i.e., users in the example) should be in the plural form in the URIs, so instead of &lt;code&gt;/users/1/&lt;/code&gt;, we would have &lt;code&gt;/user/1/&lt;/code&gt; add to that the BA/PO is now requesting a new feature to generate a tax report. So we will have the following endpoints.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get all users: &lt;strong&gt;GET&lt;/strong&gt; &lt;code&gt;https://ahmedehab.com/user/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Get a single user with an ID of 1: &lt;strong&gt;GET&lt;/strong&gt; &lt;code&gt;https://ahmedehab.com/user/1/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Update the user: &lt;strong&gt;PUT&lt;/strong&gt; &lt;code&gt;https://ahmedehab.com/user/1/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Delete the user: &lt;strong&gt;DELETE&lt;/strong&gt; &lt;code&gt;https://ahmedehab.com/user/1/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Get the default billing report for a user: &lt;strong&gt;GET&lt;/strong&gt; &lt;code&gt;https://ahmedehab.com/user/1/report/default&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Get the tax report for a user: &lt;strong&gt;GET&lt;/strong&gt; &lt;code&gt;https://ahmedehab.com/user/1/report/tax&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now for the frontend part, this will be devastating if we roll this update without a coordinated deployment with the frontend to address this.&lt;br&gt;
This means we are not reaping the benefit of REST endpoints which is the evolution of the server and the client independently of each other.&lt;/p&gt;
&lt;h2&gt;
  
  
  HATEOAS for the rescue
&lt;/h2&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%2Fsiy22x6kdszy2rcq58jo.gif" 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%2Fsiy22x6kdszy2rcq58jo.gif" alt="HATEOAS saves the day!" width="480" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Now, HATEOAS was introduced to specifically mitigate this issue, the issue of ever-evolving backend APIs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With HATEOAS, we can keep the front end running as is while quickly changing all these different APIs.&lt;br&gt;
HATEOAS defines actions and their endpoints in the response of any entity. Thus we don't hardcode every API in the front end.&lt;/p&gt;

&lt;p&gt;It is applied by adding a list of actions with their links to the entity so we can get the required link from the response to perform our action.&lt;br&gt;
Initially, the response for &lt;code&gt;GET /users/&lt;/code&gt; to get a list of users would look like this (assuming we have a single user in the backend) with HATEOAS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ahmed Ehab Abdul-Aziz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ahmed.ehab5010@gmail.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"links"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"self"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"href"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://ahmedehab.com/users/1"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"update"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"href"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://ahmedehab.com/users/1"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"delete"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"href"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://ahmedehab.com/users/1"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"report"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"href"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://ahmedehab.com/users/1/report"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;



&lt;p&gt;Now we can change the endpoints from &lt;code&gt;/users/&lt;/code&gt; to &lt;code&gt;/user/&lt;/code&gt; and add a new report like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ahmed Ehab"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ahmed.ehab5010@gmail.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"links"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"self"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"href"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://ahmedehab.com/user/1"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"update"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"href"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://ahmedehab.com/user/1"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"delete"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"href"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://ahmedehab.com/user/1"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"report"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"href"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://ahmedehab.com/user/1/report/default"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"tax-report"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"href"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://ahmedehab.com/user/1/report/tax"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;



&lt;p&gt;Another step we can do is to add the HTTP method used for each link to reduce coupling further. This is different from the REST standards, though.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"self"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"href"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://ahmedehab.com/users/1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That can lead to, for example, changing the PUT for the update action to PATCH without breaking any changes. Nonetheless, that last step is not HATEOAS compliant.&lt;/p&gt;

&lt;p&gt;The recommended way to do this is to keep the older structure where there is only &lt;code&gt;"href"&lt;/code&gt; in action and send an &lt;code&gt;OPTIONS&lt;/code&gt; request before sending the request to get the required HTTP method. Each way has its fans. &lt;strong&gt;Roy T. Fielding&lt;/strong&gt;, the creator of REST &lt;a href="https://lists.w3.org/Archives/Public/ietf-http-wg-old/1997SepDec/0376.html" rel="noopener noreferrer"&gt;was one of the creators of the OPTIONS request&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Some Architects even prefer to keep the HTTP method coupled as they see that the role of HATEOAS is to follow a standard to decouple the URIs since HATEOAS is part of having a Uniform Interface for REST. So we have to get back to the API documentation to recognize the HTTP verb.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Remember that HATEOAS is not a replacement for something like OpenAPI for API documentation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Also, the verb should present the action it is doing. If I am retrieving a user, I will always use a GET whether I change the URI or not. You can find a lot of colliding opinions on the internet, like &lt;a href="https://stackoverflow.com/questions/19959284/where-in-a-hateoas-architecture-do-you-specify-the-http-verbs" rel="noopener noreferrer"&gt;this link on StackOverflow&lt;/a&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>webdev</category>
      <category>rest</category>
      <category>hateoas</category>
    </item>
    <item>
      <title>REST Fundamentals</title>
      <dc:creator>Ahmed Ehab</dc:creator>
      <pubDate>Fri, 19 Feb 2021 16:47:36 +0000</pubDate>
      <link>https://forem.com/ahmedehab/rest-fundamentals-5don</link>
      <guid>https://forem.com/ahmedehab/rest-fundamentals-5don</guid>
      <description>&lt;p&gt;REST has been a cornerstone of backend programming for quite a while now. However, many developers have a vague idea of what REST is or confuse it with HTTP. In this post, I will shed some light on what exactly constitutes REST and how it compares to HTTP.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use REST?
&lt;/h2&gt;

&lt;p&gt;REST enforces a good separation of concerns between clients and servers. The more our REST endpoints are mature, the more we can evolve our client (frontend) or server (backend) with no issues with scalability or coupling.&lt;/p&gt;

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

&lt;p&gt;REST: Stands for &lt;strong&gt;RE&lt;/strong&gt;presentational &lt;strong&gt;S&lt;/strong&gt;tate &lt;strong&gt;T&lt;/strong&gt;ransfer. Firstly defined in the year 2000. It is an architectural style that standardizes communication between web services and systems. To say we have REST web services, we must follow the REST standards (i.e., become RESTful).&lt;/p&gt;

&lt;p&gt;REST became wildly popular as a replacement for SOAP protocols requiring a lengthier set of requirements. However, note that REST &lt;strong&gt;&lt;em&gt;doesn't dictate the data transfer protocol&lt;/em&gt;&lt;/strong&gt;. It focuses instead on the architecture of endpoints and how to name them. Thus, it's a software architecture/pattern, not a protocol. Nonetheless, HTTP is recommended as the go-to protocol to apply REST, but you can use it with other protocols like MQTT.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to apply REST
&lt;/h2&gt;

&lt;p&gt;This is the part of REST that, unfortunately, needs to be fully understood or followed, which leads to calling HTTP APIs REST APIs. However, REST is required to be followed correctly. Just check &lt;strong&gt;Roy T. Fielding&lt;/strong&gt; &lt;a href="https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven" rel="noopener noreferrer"&gt;article&lt;/a&gt; from 2008, where he rants about how he is &lt;em&gt;getting frustrated by the number of people calling any HTTP-based interface a REST API&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I will go over each of the basic fundamentals in the following point that leads to an actual REST endpoint, not just a regular HTTP one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Client and Server Separation
&lt;/h3&gt;

&lt;p&gt;In REST, the client and server are separated, leading to less coupling between the client and server. Thus we gain flexibility and a stateless server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Statelessness
&lt;/h3&gt;

&lt;p&gt;REST advocates statelessness, meaning that the server doesn't keep the client's state. So the server doesn't keep track of the user's session. This leads to great scalability, as any new server instance is not required to keep track of old sessions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caching
&lt;/h3&gt;

&lt;p&gt;If a request is following REST, the request must detail if it's cacheable or not. Applying caching to client and server requests leads to a significantly reduced number of requests. Or even the elimination of requests altogether over a while.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layers
&lt;/h3&gt;

&lt;p&gt;If a client is connecting to a server and a new layer is introduced (e.g., proxy/load balancer), this must not affect how the client or the server behaves. So we can add proxies, load balancers, firewalls, and more without affecting the system's behavior.&lt;/p&gt;

&lt;h3&gt;
  
  
  Uniform Interface
&lt;/h3&gt;

&lt;p&gt;Having a uniform interface is a must in the REST architectural style. This enables each part (client/server) to change sides over time separately from each other. Four rules must be followed to have a uniform interface between clients and servers.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Resource identification in requests&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Resources (endpoints) should be identified in the request. Such as using URIs. For example, the user resource should be stated in the HTTP URI that the users are what is required here, like this  &lt;code&gt;https://example.com/users/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The resource for the server side is separate from the representations returned to the client. Many resources and entities represent this user endpoint in the backend. This is coupled away from the client/front end.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Resource manipulation through representations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When a client receives a resource (with headers and other metadata), it has enough information to modify or delete. So if the frontend retrieves users from &lt;code&gt;https://example.com/users/&lt;/code&gt;, it can follow a simple structure to manipulate any user in the list without asking the backend how to request a type of this change.&lt;/p&gt;

&lt;p&gt;In HTTP-based REST endpoints, this is achieved by HTTP verbs such as GET to retrieve, POST to create a new resource, PUT to create/update a complete resource, PATCH to modify a part of a resource, DELETE to delete a resource, and so on. This is accompanied by other data that can help in this, for example, returning each user ID.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Self-descriptive messages&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The response message should describe itself with no requirement to go back to the backend to retrieve the message's meaning. For example, an attribute must be attached to explain the file type if a file is returned in a binary format. If the response is in JSON, an attribute must exist to explain it's in JSON.&lt;/p&gt;

&lt;p&gt;In HTTP-based REST APIs, &lt;code&gt;https://example.com/annual-report/&lt;/code&gt;, the response must have a media type header that explains that the returning blob is a pdf like this &lt;code&gt;Content-Type: application/pdf&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Also, in HTTP, the response should have a status code that describes the state of this response, whether it's an error or a successful one, like response 200 (OK) or 400 (BAD REQUEST).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hypermedia as the engine of application state (HATEOAS)&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;HATEOAS requires that when requesting a URI for a REST endpoint, the response should include links provided by the backend to discover all available resources in the response dynamically.&lt;/p&gt;

&lt;p&gt;This leads to a decoupled client from the backend endpoints leading to more freedom in changing the backend structure and endpoints.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ahmed Ehab"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ahmed.ehab5010@gmail.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"_links"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"self"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"href"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://ahmedehab.com/users/1"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"report"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"href"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://ahmedehab.com/users/1/report"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;HATEOES is a big topic; I might write a post discussing it precisely. To keep this post short, I won't be going into HATEOES.&lt;/p&gt;

&lt;h2&gt;
  
  
  Richardson Maturity Model
&lt;/h2&gt;

&lt;p&gt;RMM is a maturity model described by Leonard Richardson in 2008. It tells how much an application adheres to REST specifications and puts it in one of four levels.This model is well suited to show us how much our endpoints conform to the REST architectural style, so it can state that our API is not a fully mature REST API, but partially a REST endpoint.&lt;/p&gt;

</description>
      <category>rest</category>
      <category>architecture</category>
      <category>http</category>
      <category>api</category>
    </item>
  </channel>
</rss>
