<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Rostyslav Pidburachynskyi</title><link>https://blog.rpidburachynskyi.dev/</link><description>Recent content on Rostyslav Pidburachynskyi</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Fri, 05 Apr 2024 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.rpidburachynskyi.dev/index.xml" rel="self" type="application/rss+xml"/><item><title>Never sort by yourself</title><link>https://blog.rpidburachynskyi.dev/p/never-sort-by-yourself/</link><pubDate>Fri, 05 Apr 2024 00:00:00 +0000</pubDate><guid>https://blog.rpidburachynskyi.dev/p/never-sort-by-yourself/</guid><description>&lt;img src="https://blog.rpidburachynskyi.dev/p/never-sort-by-yourself/cover.webp" alt="Featured image of post Never sort by yourself" />&lt;h1 id="never-sort-by-yourself">Never sort by yourself&lt;/h1>
&lt;h2 id="preamble">Preamble&lt;/h2>
&lt;p>Sorting is a staple action in coding. The demand to organize data in either ascending or descending order is frequent, and often, we are faced with the challenge of morphing the same data to match different sorting needs before displaying it to the user.&lt;/p>
&lt;p>Sorting becomes more complicated when dealing with massive volumes of data; however, we can&amp;rsquo;t do this client-side. So, we must resort to performing this action server-side. But is it something we should be handling on our own?&lt;/p>
&lt;p>Let&amp;rsquo;s explore it further.&lt;/p>
&lt;h2 id="the-problem">The problem&lt;/h2>
&lt;p>Imagine this scenario, you have a basic REST endpoint that return a list of users:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;John&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;age&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">20&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;email&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;john.doe@gmail.com&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Jane&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;age&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">25&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;email&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;jane.doe@gmail.com&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Bob&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;age&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">30&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;email&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;bob.doe@gmail.com&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>You&amp;rsquo;ve also got client software that utilizes this endpoint to show the user list. The issue? This list has to be sorted by the &lt;code>name&lt;/code> field in ascending order. So you&amp;rsquo;ve got two choices:&lt;/p>
&lt;ul>
&lt;li>Sort data on the client side.&lt;/li>
&lt;li>Sort data on the server side.&lt;/li>
&lt;/ul>
&lt;p>The first approach is relatively straightforward, but it carries a significant disadvantage:&lt;/p>
&lt;ul>
&lt;li>Sorting on the client side can be extremely slow or even impossible when dealing with large datasets.&lt;/li>
&lt;/ul>
&lt;p>The second option may appear ideal, but carries its own shortcomings:&lt;/p>
&lt;ul>
&lt;li>Additional endpoints are necessary for every unique client application view.&lt;/li>
&lt;li>New endpoints will be needed for every field/order sorting requirement.&lt;/li>
&lt;/ul>
&lt;h2 id="the-solution">The solution&lt;/h2>
&lt;p>The solution revolves around the utilization of a query parameter that allows us to indicate the preferred sorting field and order. Let&amp;rsquo;s denote this as &lt;code>sort&lt;/code>. The request might then appear like:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">GET /users?sort&lt;span class="o">=&lt;/span>name:asc
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Or if you need to sort by &lt;code>age&lt;/code> field in descending order:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">GET /users?sort&lt;span class="o">=&lt;/span>age:desc
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>By adopting this approach, you can sort data server-side and deliver sorted data to the client without the need for creating new endpoints for every field/order sort.&lt;/p>
&lt;h3 id="what-about-multiple-field-sorting">What about multiple-field sorting?&lt;/h3>
&lt;p>For multi-field sorting, you may consider the following format:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">GET /users?sort&lt;span class="o">=&lt;/span>name:asc,age:desc
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="alternate-query-parameter-representations">Alternate Query Parameter Representations&lt;/h2>
&lt;p>There exist differing yet commonly adopted methods to represent sorting in query parameters:&lt;/p>
&lt;ul>
&lt;li>&lt;code>sort=name:asc,age:desc&lt;/code> - This is undoubtedly the most comprehensible and highly adopted method, offering flexibility in adding more order directions (like &lt;code>asc-null-first&lt;/code>, &lt;code>desc-null-last&lt;/code>, etc.). You can choose any delimiter in place of &lt;code>:&lt;/code>.&lt;/li>
&lt;li>&lt;code>sort=name,-age&lt;/code> - Although this method is also well-liked, it offers less flexibility in adding more order directions. Nonetheless, it&amp;rsquo;s compact and quite readable, with the &lt;code>-&lt;/code> sign, optionally replaceable with &lt;code>&amp;lt;&lt;/code> or &lt;code>&amp;gt;&lt;/code> signs. The &lt;code>+&lt;/code> sign is always redundant.&lt;/li>
&lt;/ul>
&lt;h2 id="conclusion">Conclusion&lt;/h2>
&lt;p>Sorting data is a staple action in coding, but it can pose challenges when dealing with large volumes of data, especially when different client-side applications require different sorting needs.&lt;/p>
&lt;p>Sorting data on the client-side can be slow or even impossible with large datasets, and server-side sorting often necessitates the creation of additional endpoints for unique client-side views.&lt;/p>
&lt;p>However, the use of a query parameter for indicating the preferred sorting field and order can offer a solution. By using this approach, data can be sorted server-side and delivered sorted to the client without the need to create new endpoints for every field/order sort. This provides a flexible, efficient, and scalable solution for sorting data in coding.&lt;/p></description></item><item><title>The Importance of Unique Sorting in Databases</title><link>https://blog.rpidburachynskyi.dev/p/the-importance-of-unique-sorting-in-databases/</link><pubDate>Wed, 20 Dec 2023 00:00:00 +0000</pubDate><guid>https://blog.rpidburachynskyi.dev/p/the-importance-of-unique-sorting-in-databases/</guid><description>&lt;img src="https://blog.rpidburachynskyi.dev/p/the-importance-of-unique-sorting-in-databases/cover.png" alt="Featured image of post The Importance of Unique Sorting in Databases" />&lt;h1 id="the-importance-of-unique-sorting-in-databases">The Importance of Unique Sorting in Databases&lt;/h1>
&lt;h2 id="introduction">Introduction&lt;/h2>
&lt;p>In the fast-evolving world of information technology, data has become the lifeblood of businesses. Databases have emerged as a critical component in the information architecture of any organization, enabling optimization and effective management of this data. Two prominent types of databases that have found widespread use are SQL and NoSQL databases.&lt;/p>
&lt;p>While SQL and NoSQL have proved to be powerful tools, they are not without their challenges. A common and potentially troublesome issue that many developers have faced is the inconsistent ordering of records despite using the same offset and limit. This problem can be particularly vexing when sorting records by a factor that includes duplicates, such as names - where people with the same names can appear in a different order in different instances.&lt;/p>
&lt;p>This discrepancy may seem minor, but it can have wide-ranging implications for the predictability and reliability of any data-driven operations, leading to potential complications in multiple processes such as data analysis, record keeping, and the most import - &lt;strong>user experience&lt;/strong>.&lt;/p>
&lt;p>In the ensuing sections of this article, we will delve into this issue in more detail, understanding its causes and exploring potential solutions to ensure consistency in your databases and boost the overall efficacy of your data management.&lt;/p>
&lt;h2 id="concept-of-sorting-offset-and-limit">Concept of Sorting, Offset, and Limit&lt;/h2>
&lt;p>Sorting, offset, and limit are crucial concepts in database management that allow developers to organize and retrieve data effectively.&lt;/p>
&lt;p>Sorting is the arrangement of data in a particular order based on certain criteria. In SQL and NoSQL databases, you can sort data in ascending or descending order based on columns like names, IDs, or any other attribute. For example, if you sort by name, the database will arrange records alphabetically.&lt;/p>
&lt;p>Offset and limit, on the other hand, are fundamental components for handling database pagination. The limit dictates how many records we aim to retrieve from the database, while the offset instructs the database where to start the retrieval. For instance, an offset of &lt;code>10&lt;/code> and a limit of &lt;code>5&lt;/code> means start from the 11th record and fetch five records.&lt;/p>
&lt;p>Example of a SQL query that incorporates sorting, offset, and limit:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="cl">&lt;span class="k">SELECT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">FROM&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">employees&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">ORDER&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">BY&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">lastname&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">ASC&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">-- Sorting in ascending order
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">LIMIT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">-- Limiting the result to 5 records
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">OFFSET&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">-- Starting from the 11th record
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Both offset and limit come in handy when working with large sets of data, as returning everything at once can be inefficient and resource-taxing. However, issues can arise where the same offset and limit do not always result in fetching records in the same order which can lead to data inconsistency. The subsequent sections will delve deeper into this problem.&lt;/p>
&lt;h2 id="different-data-despite-identical-offset-limit-and-sort-criteria">Different Data Despite Identical Offset, Limit and Sort Criteria&lt;/h2>
&lt;p>That&amp;rsquo;s issue this article is aimed at.&lt;/p>
&lt;p>A perplexing anomaly that developers often encounter when dealing with databases involves retrieving different sets of data even when using the same offset, limit, and sort criteria.&lt;/p>
&lt;p>This inconsistency primarily arises when sorting involves a column with duplicate values, such as names. For instance, if you require records sorted by &lt;code>name&lt;/code>, and your database contains multiple entries with the same name, repeated fetch requests may yield variations in the order of returned results. SQL and NoSQL databases don&amp;rsquo;t guarantee a fixed sequence of items with identical sorting values, leading to unexpected variations in the record sequence. More to say, the database will return them in the order which is the most efficient for the database.&lt;/p>
&lt;p>Let&amp;rsquo;s consider an example. Suppose you have a table of employees with the following records:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>ID&lt;/th>
&lt;th>Name&lt;/th>
&lt;th>Age&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>1&lt;/td>
&lt;td>John&lt;/td>
&lt;td>20&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>2&lt;/td>
&lt;td>Jane&lt;/td>
&lt;td>25&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>3&lt;/td>
&lt;td>Bob&lt;/td>
&lt;td>30&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>4&lt;/td>
&lt;td>John&lt;/td>
&lt;td>35&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>5&lt;/td>
&lt;td>Jane&lt;/td>
&lt;td>40&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>6&lt;/td>
&lt;td>Bob&lt;/td>
&lt;td>45&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>If query this table with the following SQL query:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="cl">&lt;span class="k">SELECT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">FROM&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">employees&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">ORDER&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">BY&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">ASC&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">LIMIT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">OFFSET&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>We will get the following result:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>ID&lt;/th>
&lt;th>Name&lt;/th>
&lt;th>Age&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>3&lt;/td>
&lt;td>Bob&lt;/td>
&lt;td>30&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>6&lt;/td>
&lt;td>Bob&lt;/td>
&lt;td>45&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>2&lt;/td>
&lt;td>Jane&lt;/td>
&lt;td>25&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Or&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>ID&lt;/th>
&lt;th>Name&lt;/th>
&lt;th>Age&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>3&lt;/td>
&lt;td>Bob&lt;/td>
&lt;td>30&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>6&lt;/td>
&lt;td>Bob&lt;/td>
&lt;td>45&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>5&lt;/td>
&lt;td>Jane&lt;/td>
&lt;td>40&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Or even more, running the same query multiple times can yield get each time either of the above results.&lt;/p>
&lt;p>Such inconsistency can become problematic, especially where the sequence of data is important, such as in pagination, data comparison, or maintaining data synchronization in real-time applications.&lt;/p>
&lt;p>Consider a scenario in which you have a table spread across several pages. You might notice that the same records appear on both the 2nd and 3rd pages. This repetition can push needed records out of view, causing them to go missing on these pages. So, instead of seeing new records as you turn the pages, you&amp;rsquo;re presented with duplicated entries, and some expected records are nowhere to be found.&lt;/p>
&lt;h2 id="the-impact-of-this-problem">The Impact of this Problem&lt;/h2>
&lt;p>The consequence of retrieving fluctuating orders of records, despite having the same offset, limit, and sort criteria, can significantly affect the reliability and predictability of data-related operations. Below are a few specific areas where this inconsistency can cause complications:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Data Analysis&lt;/strong>: For data scientists and analysts, consistency is key. Inconsistent order of delivery of data can lead to distorted analysis results, impacting their capability to make informed decisions.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>User Experience&lt;/strong>: In customer-facing applications, this inconsistency can lead to poor user experience. For example, in an e-commerce platform using pagination, customers might see products in a different order each time they visit the same page.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Data Synchronization&lt;/strong>: In real-time applications, it&amp;rsquo;s crucial to maintain synchronized data across different platforms. Inconsistent ordering can disrupt this synchronization, leading to discrepancies.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Record Keeping&lt;/strong>: Consistency is also vital in maintaining organized and reliable records, especially for activities such as audit trails.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>Addressing this issue of inconsistency, therefore, is not only about improving database operations but impacts the full system. The following section will explore potential solutions to this problem and ways to ensure database consistency.&lt;/p>
&lt;h2 id="solutions-to-the-problem">Solutions to the Problem&lt;/h2>
&lt;p>While there are numerous potential solutions to deal with data inconsistency, such as implementing a standardized algorithm or manipulating indexes, they may not always be feasible. The roots of this issue lie in the database structure and its inherent features, which often can&amp;rsquo;t be changed without complexity. Therefore, a reliable and straightforward way to address this problem is presented here.&lt;/p>
&lt;p>The recommended solution is to always incorporate a secondary sorting criterion aimed at enhancing the &lt;code>uniqueness&lt;/code> of the sorting process. For example, when sorting by a common field like names, which tend not to be unique, it&amp;rsquo;s beneficial to add an additional field. This additional field could vary from second names, year of birth, or even their department, making the resultant order increasingly unique.&lt;/p>
&lt;p>Nevertheless, the quest for unique sorting can be challenging, and there could still be instances of inconsistency. In such cases, adding sorting at the end by a universally unique field, which is always present in SQL and NoSQL databases - the &lt;code>ID&lt;/code>, can help. IDs are always unique, hence sorting by IDs will ensure a consistent order, regardless of how many times you run the query.&lt;/p>
&lt;p>Example of a SQL query that incorporates secondary sorting criteria:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="cl">&lt;span class="k">SELECT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">FROM&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">employees&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">ORDER&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">BY&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">ASC&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">age&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DESC&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">employee_id&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">ASC&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">LIMIT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">OFFSET&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>In the above example, we have three sorting criteria - &lt;code>name&lt;/code>, &lt;code>age&lt;/code>, and &lt;code>employee_id&lt;/code>. The first two criteria potentially can have duplicate values, while the third one is always unique. This ensures that the sorting process is increasingly unique, and the resultant order is consistent.&lt;/p>
&lt;p>Furthermore, you can add timestamp fields, such as &lt;code>date created&lt;/code> or &lt;code>date updated&lt;/code>, to the sorting criteria, aligning it more with user experience. However, it&amp;rsquo;s important to note that this might still leave a small room for inconsistency. If your records encompass a compound unique value, sorting via this compound value could be the most foolproof way to ensure database consistency.&lt;/p>
&lt;h2 id="performance-impact">Performance Impact&lt;/h2>
&lt;p>When mitigating the inconsistency problem with additional sorting criteria, a common concern might be the potential impact on database performance. It&amp;rsquo;s important to clarify that these additional measures for ensuring a unique sort order offer a balance between consistency and operational efficiency.&lt;/p>
&lt;p>SQL and NoSQL databases are generally equipped to handle multiple sorting criteria efficiently. They use indexing strategies to optimize the sorting of records, ensuring that any performance overhead caused by introducing additional fields into the sorting mix is usually minimal.&lt;/p>
&lt;p>When considering database performance, the impact of additional sorting criteria becomes relatively inconsequential when dealing with low records of duplicate values. If the majority of your data is unique or if you&amp;rsquo;re operating with minimal duplicate values, the database does not have an extensive sorting task to carry out.&lt;/p>
&lt;p>Given this circumstance, the process of sorting primarily runs through unique records, requiring less computational effort. As a result, the database performance remains almost unaffected, ensuring smooth and efficient operations alongside better data consistency and reliability. Thus, even with additional sorting criteria, databases with fewer duplicates continue to maintain optimal performance while ensuring constant order in record retrieval.&lt;/p>
&lt;h2 id="conclusion">Conclusion&lt;/h2>
&lt;p>In this article, we delved into a common, yet perplexing issue that developers often encounter - the inconsistency of record order despite maintaining the same offset, limit, and sort criteria. This challenge, mainly when dealing with duplicate values during the sorting process, can cause hiccups in database and application reliability.&lt;/p>
&lt;p>A proposed solution to this problem emphasizes enhancing the &amp;lsquo;uniqueness&amp;rsquo; of the sorting operation. Incorporating secondary sorting criteria or utilizing unique identifiers and compound fields are recommended strategies to constantly ensure a predictable and consistent sorting order.&lt;/p>
&lt;p>While it is important to consider potential performance implications, the effect on modern database systems is typically marginal, especially when dealing with low-duplicate datasets.&lt;/p>
&lt;p>In conclusion, to reinforce data consistency and avoid potential bugs, it&amp;rsquo;s strongly recommended to implement these additional sorting measures as a standard practice in your database operations. It not only eliminates uncertainties but adds robustness to your data management endeavors.&lt;/p></description></item><item><title>The Art of Assertive Programming</title><link>https://blog.rpidburachynskyi.dev/p/the-art-of-assertive-programming/</link><pubDate>Sun, 10 Dec 2023 00:00:00 +0000</pubDate><guid>https://blog.rpidburachynskyi.dev/p/the-art-of-assertive-programming/</guid><description>&lt;img src="https://blog.rpidburachynskyi.dev/p/the-art-of-assertive-programming/cover.png" alt="Featured image of post The Art of Assertive Programming" />&lt;h1 id="cannot-read-property-of-null-or-the-art-of-assertive-programming">Cannot read property of null or The Art of Assertive Programming&lt;/h1>
&lt;h2 id="introduction">Introduction&lt;/h2>
&lt;p>Imagine yourself orchestrating a large family meal. Numerous dishes are simmering on the stove and roasting in the oven, each requiring your undivided attention. It&amp;rsquo;s not just about stirring the pot or monitoring the oven timer, it&amp;rsquo;s about making sure the soup has the right hint of salt or that the roast isn&amp;rsquo;t charring into a burnt mess. Your vigilance is needed - you can&amp;rsquo;t afford to wait until each dish is cooked to confirm it&amp;rsquo;s done right. Real-time checks are vital, ensuring any errors are caught immediately, not after the fact. In essence, this culinary roller-coaster demands nothing less than your &lt;code>assertive&lt;/code> attention.&lt;/p>
&lt;h2 id="the-problem">The problem&lt;/h2>
&lt;p>In our journey as programmers, it&amp;rsquo;s quite common to work with variables that we trust to always be appropriately defined - we assume they come equipped with a preset value, a specific type, a well-structured form, or even particular restrictions, such as being either positive or negative. But what if our expectations aren&amp;rsquo;t met?&lt;/p>
&lt;p>What happens if, instead of receiving an expected value, we get null? What if a string shows up where we expected a number? What becomes of our computations when we encounter zero in our division operations? Or what if we attempt to access array properties from a string, especially when that string also happens to have a property of the same name? Suddenly, we grapple with what we term &lt;code>undefined behavior&lt;/code>, an unpredictable state of our program which seems to diverge all established norms.&lt;/p>
&lt;p>Sure, employing a typed language can help alleviate some of these issues, particularly where incorrect types are in play. But how about the other challenges? Realistically, we can&amp;rsquo;t completely ward off such occurrences since the future remains unpredictable. However, this article isn&amp;rsquo;t focused on preventing these scenarios, but rather, seeks to address the ideal way to manage them when they arise.&lt;/p>
&lt;p>You might be led to think occasional errors are acceptable, given you can always debug the program later. However, what if you had tools to simplify your debugging process? Consider a typical error like &lt;code>Cannot read property 'name' of null&lt;/code>. The origin of this error is usually easy to pinpoint through the stack trace, as with most errors of a similar nature. But what about a scenario where the function completes without throwing an error, albeit yielding an incorrect result? Identifying the source of such a problem could prove more difficult and require more time to debug.&lt;/p>
&lt;p>Let&amp;rsquo;s take a look at some cases to illustrate the problem, to help understand across many languages, the cases are expressed as pseudo-code.&lt;/p>
&lt;h3 id="case-1">Case 1&lt;/h3>
&lt;p>Suppose we have a function that accepts a number and returns its power of two.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="k">function&lt;/span> square_root x
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> x * x
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>If we were to call this function with a string, we would get an error.&lt;/p>
&lt;h3 id="case-2">Case 2&lt;/h3>
&lt;p>Now, let&amp;rsquo;s consider another example. Suppose we have a function that accepts two numbers and returns their sum.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="k">function&lt;/span> add x, y
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> x + y
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>If we were to call this function with a string and/or number, we would get a successful result as most languages will coerce the number to a string and concatenate the two values.&lt;/p>
&lt;h3 id="case-3">Case 3&lt;/h3>
&lt;p>Now, let&amp;rsquo;s consider another example. Suppose we have a function that accepts a number and returns its square root.&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>In reality square root of a negative number exists.&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="k">function&lt;/span> square_root x
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> sqrt&lt;span class="o">(&lt;/span>x&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>If we were to call this function with a negative number, we would get an error.&lt;/p>
&lt;h2 id="the-solution">The solution&lt;/h2>
&lt;p>The solution to this predicament lies in actively monitoring and validating your variables and input arguments. When a function receives an input or an argument, you can establish checks to confirm that it meets your criteria. Should it fall short, your program could respond by immediately throwing an error.&lt;/p>
&lt;p>This technique is often referred to as an &lt;code>assertion&lt;/code>. An assertion serves as a powerful instrument to bolster the robustness, security, and efficiency of your code. This systematic scrutiny of variables and arguments allows for proactive error detection, making your code not only more resistant to unpredictable behaviour but also simpler to debug and maintain.&lt;/p>
&lt;h3 id="what-is-assertion">What is assertion?&lt;/h3>
&lt;p>An &lt;code>assertion&lt;/code> is a statement that evaluates to either true or false. It&amp;rsquo;s a way of expressing a condition that must be true at a particular point in your program. If the condition is false, an error is thrown.&lt;/p>
&lt;p>The pseudo-code below illustrates the concept of an assertion.&lt;/p>
&lt;h3 id="examples">Examples&lt;/h3>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">assert &amp;lt;condition&amp;gt; &amp;lt;message?&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>The &lt;code>condition&lt;/code> is the expression that must evaluate to true. If it evaluates to false, the &lt;code>message&lt;/code> is thrown as an error. The &lt;code>message&lt;/code> is optional, but it&amp;rsquo;s a good practice to include it, as it provides additional context to the error.&lt;/p>
&lt;p>Let&amp;rsquo;s look at a simple example:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">a&lt;/span> &lt;span class="o">=&lt;/span> random&lt;span class="o">(&lt;/span>1, 10&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">assert a &amp;gt; 5, &lt;span class="s2">&amp;#34;a must be greater than 5&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>In this example, we generate a random number between 1 and 10 and assign it to the variable &lt;code>a&lt;/code>. We then assert that &lt;code>a&lt;/code> must be greater than 5. If &lt;code>a&lt;/code> is less than or equal to 5, an error is thrown with the message &amp;ldquo;a must be greater than 5&amp;rdquo;. This example does not make sense in real program, but it illustrates the concept of an assertion.&lt;/p>
&lt;p>Here is a better example:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="k">function&lt;/span> divide a, b
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> assert b !&lt;span class="o">=&lt;/span> 0, &lt;span class="s2">&amp;#34;b must not be zero&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> a / b
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>In this example, we assert that &lt;code>b&lt;/code> must not be zero. If &lt;code>b&lt;/code> is zero, an error is thrown with the message &amp;ldquo;b must not be zero&amp;rdquo;. This assertion prevents the function from dividing by zero, which would otherwise result in another error unhandled error.&lt;/p>
&lt;p>And the last example:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="k">function&lt;/span> add a, b
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> assert typeof &lt;span class="nv">a&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;number&amp;#34;&lt;/span>, &lt;span class="s2">&amp;#34;a must be a number&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> assert typeof &lt;span class="nv">b&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;number&amp;#34;&lt;/span>, &lt;span class="s2">&amp;#34;b must be a number&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> a + b
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>In this example, we assert that &lt;code>a&lt;/code> and &lt;code>b&lt;/code> must be numbers. If either &lt;code>a&lt;/code> or &lt;code>b&lt;/code> is not a number, an error is thrown with the message &amp;ldquo;a must be a number&amp;rdquo; or &amp;ldquo;b must be a number&amp;rdquo;. This assertion prevents the function from adding non-numbers, which would otherwise execute successfully but yield an incorrect result.&lt;/p>
&lt;h3 id="when-to-use-assertion">When to use assertion?&lt;/h3>
&lt;p>Assertions are best used to validate input arguments and variables that come from an external source which are used for internal purposes. For example, the following is a correct use of assertion:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="k">function&lt;/span> check_user_verified_email user_id
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># user_id comes from an arguments&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> assert typeof &lt;span class="nv">user_id&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;string&amp;#34;&lt;/span>, &lt;span class="s2">&amp;#34;user_id must be a string&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># call to a database is an external source&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">user&lt;/span> &lt;span class="o">=&lt;/span> db.find_one&lt;span class="o">(&lt;/span>&lt;span class="s2">&amp;#34;users&amp;#34;&lt;/span>, &lt;span class="o">{&lt;/span> email: email &lt;span class="o">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> assert user.email !&lt;span class="o">=&lt;/span> null, &lt;span class="s2">&amp;#34;user email must not be null&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> assert user.email !&lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>, &lt;span class="s2">&amp;#34;user must have an email&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> user.email.starts_with&lt;span class="o">(&lt;/span>&lt;span class="s2">&amp;#34;verified&amp;#34;&lt;/span>&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>In this example, we assert that &lt;code>user_id&lt;/code> is actually a non-empty string. We then assert that the user must have an email because the function is not supposed to be called for user without email. These assertions prevent the function from executing with invalid input arguments or variables.&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>Note: We check user.email only because the function expected to be called only for users with email, if it was expected to be called for users without email, we should not check it.&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>&lt;em>Note: Also we can check if we suppose that email should be present in user object.&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;p>Why did we use assertion for checking user email? Read more about it in the next section.&lt;/p>
&lt;h4 id="should-i-use-assertion-for-external-data-grabbing">Should I use assertion for external data grabbing?&lt;/h4>
&lt;p>Short answer - yes, long answer - it depends. Here is a real example you can better understand it with.&lt;/p>
&lt;p>Consider a scenario where you possess an &lt;code>orders&lt;/code> table in your database comprising standard fields, such as &lt;code>order_id&lt;/code>, &lt;code>customer_id&lt;/code>, &lt;code>order_date&lt;/code>, &lt;code>product_id&lt;/code>, and &lt;code>quantity&lt;/code>. You are in need to introduce a new field named &lt;code>status&lt;/code>, an enum accommodating the values &lt;code>pending&lt;/code>, &lt;code>shipped&lt;/code>, or &lt;code>delivered&lt;/code>. You would set this field, by default, as &lt;code>pending&lt;/code> for all new orders. A certain department has assured you that they would assign the &lt;code>status&lt;/code> to the existing orders. Meanwhile, there&amp;rsquo;s a function that currently runs fine, calling upon each order daily to perform specific operations. Now, your task is to adjust this code to make use of the status for some corresponding logic. Here is that method:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="k">function&lt;/span> process_order order_id
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">order&lt;/span> &lt;span class="o">=&lt;/span> db.find_one&lt;span class="o">(&lt;/span>&lt;span class="s2">&amp;#34;orders&amp;#34;&lt;/span>, &lt;span class="o">{&lt;/span> order_id: order_id &lt;span class="o">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># do some logic&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># new added logic&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> order.status !&lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;delivered&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># order.status now can be &amp;#39;pending&amp;#39;, &amp;#39;shipped&amp;#39; or null&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> send_email_to_customer_about_order_status&lt;span class="o">(&lt;/span>order_id, order.status&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Essentially, the existing code aligns with the older logic and is likely to function smoothly since it doesn&amp;rsquo;t utilize the new status field. Post incorporating the new logic, we aim to email customers about all order statuses with the exception of the &lt;code>delivered&lt;/code> ones. However, we could potentially face an issue if the status field isn&amp;rsquo;t defined. Even though assurances have been received stating this wouldn&amp;rsquo;t happen, we must prepare for the possibility.&lt;/p>
&lt;p>Directly sending a null value to the function isn&amp;rsquo;t feasible, as it would result in undefined behaviour. Similarly, neglecting it ain&amp;rsquo;t an option as it would leave the order unprocessed. In this complex situation, the most suitable alternative is to throw an exception and inspect that particular order to understand why it lacks a status.&lt;/p>
&lt;p>Indeed, we could insert an if statement to perform the respective action. Yet, if we envision a function with numerous if statements, it could make the code convoluted and challenging to maintain.&lt;/p>
&lt;p>In contrast, using assertions can effectively condense each statement to a single code line, as shown below:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">function&lt;/span> process_order order_id
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">order&lt;/span> &lt;span class="o">=&lt;/span> db.find_one&lt;span class="o">(&lt;/span>&lt;span class="s2">&amp;#34;orders&amp;#34;&lt;/span>, &lt;span class="o">{&lt;/span> order_id: order_id &lt;span class="o">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># do some logic&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># it checks if the status is not null&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># else it throws an exception with appropriate message&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> assert order.status !&lt;span class="o">=&lt;/span> null, &lt;span class="s2">&amp;#34;order status must not be null&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> order.status !&lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;delivered&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> send_email_to_customer_about_order_status&lt;span class="o">(&lt;/span>order_id, order.status&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="when-not-to-use-assertion">When not to use assertion?&lt;/h3>
&lt;h4 id="for-control-flowhttpsenwikipediaorgwikicontrol_flow">For &lt;a class="link" href="https://en.wikipedia.org/wiki/Control_flow" target="_blank" rel="noopener"
>control flow&lt;/a>&lt;/h4>
&lt;p>Assertions are not meant to be used for control flow. For example, the following is an incorrect use of assertion:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="k">function&lt;/span> add a, b
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> assert typeof &lt;span class="nv">a&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;number&amp;#34;&lt;/span>, &lt;span class="s2">&amp;#34;a must be a number&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> assert typeof &lt;span class="nv">b&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;number&amp;#34;&lt;/span>, &lt;span class="s2">&amp;#34;b must be a number&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> a &amp;lt; &lt;span class="m">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> assert b &amp;lt; 0, &lt;span class="s2">&amp;#34;b must be negative&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> a + b
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>In this example, we assert that &lt;code>a&lt;/code> and &lt;code>b&lt;/code> must be numbers. We then assert that &lt;code>b&lt;/code> must be negative if &lt;code>a&lt;/code> is negative. This is an incorrect use of assertion because it&amp;rsquo;s being used for control flow. Instead, we should use a conditional statement:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="k">function&lt;/span> add a, b
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> assert typeof &lt;span class="nv">a&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;number&amp;#34;&lt;/span>, &lt;span class="s2">&amp;#34;a must be a number&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> assert typeof &lt;span class="nv">b&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;number&amp;#34;&lt;/span>, &lt;span class="s2">&amp;#34;b must be a number&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> a &amp;lt; &lt;span class="m">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> b &amp;gt;&lt;span class="o">=&lt;/span> &lt;span class="m">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> throw &lt;span class="s2">&amp;#34;b must be negative&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> a + b
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>In this example, we assert that &lt;code>a&lt;/code> and &lt;code>b&lt;/code> must be numbers. We then check if &lt;code>a&lt;/code> is negative. If &lt;code>a&lt;/code> is negative, we check if &lt;code>b&lt;/code> is negative. If &lt;code>b&lt;/code> is not negative, we throw an error. This is a correct use of assertion because it&amp;rsquo;s not being used for control flow.&lt;/p>
&lt;p>The example provides an explanation of what control flow is within the context of a method, but what are the actual disadvantages of employing assertions for managing control flow?&lt;/p>
&lt;h4 id="drawbacks-of-using-assertions-for-control-flow">Drawbacks of using assertions for control flow&lt;/h4>
&lt;ul>
&lt;li>&lt;code>Assertions can be disabled globally&lt;/code> - it&amp;rsquo;s very popular behaviour, so you can&amp;rsquo;t rely on them with real data.&lt;/li>
&lt;li>&lt;code>Poor handling of errors&lt;/code> - usually you can&amp;rsquo;t handle assertion errors properly so you just log them to debug later, and you won&amp;rsquo;t be able to notify client about the error.&lt;/li>
&lt;li>&lt;code>Bad user experience&lt;/code> - you can&amp;rsquo;t validate user input with assertions, because it&amp;rsquo;s always difficult to make a parsable error message for the user.&lt;/li>
&lt;/ul>
&lt;h4 id="for-types-in-statically-typed-languages">For types in statically typed languages&lt;/h4>
&lt;p>If you use a statically typed language, you don&amp;rsquo;t need to use assertions for types, because the compiler will catch type errors for you.&lt;/p>
&lt;h4 id="for-fulfilling-non-critical-failing">For fulfilling non-critical failing&lt;/h4>
&lt;p>When you have an opportunity to introduce an assertion into a statement, but also want execution to persist even if the assertion fails, you should use a conditional statement instead of an assertion, then you can manage the situation is other way rather than using an assertion.&lt;/p>
&lt;h2 id="when-does-this-turn-into-a-solution-for-us">When does this turn into a solution for us?&lt;/h2>
&lt;p>When a programmer works on a program alone, he can easily track the state of the program and prevent it from entering into an invalid state. But when multiple programmers work on the same program, it becomes difficult to track the state of the program as the program grows, the functions are called from different places with different arguments, different parts of the program change and the behaviour not always is as expected. This is where assertions come into play. You&amp;rsquo;re lucky if you have time to write tests for your code, to check edge cases, but even thought it takes a lot of time to cover every edge case.&lt;/p>
&lt;h3 id="assertions-slow-down-the-program">Assertions slow down the program?&lt;/h3>
&lt;p>Assertion underhood is just a simple if statement, so it doesn&amp;rsquo;t slow down the program, even though if you think it&amp;rsquo;s a problem for you and you expect to be the fastest program in the world, you can disable assertions in production, so many errors will be caught in testing environment.&lt;/p>
&lt;h3 id="assertions-replace-tests">Assertions replace tests?&lt;/h3>
&lt;p>Partially yes, but not completely. Assertions are used to check the state of the program, but tests are used to check the behaviour of the program.&lt;/p>
&lt;p>At the same time the principle is similar to typings. If you say your function accepts number you don&amp;rsquo;t have to write tests to check if the argument is a number, that&amp;rsquo;s the responsibility of the caller to pass a number, not a string, in that case you are not testing the behaviour. The same with assertions, if you say your function accepts a number and you write assert to check if the argument is not zero, you don&amp;rsquo;t have to write tests to check if the argument is not zero, because you already know the result of that execution, it will throw an error, so you don&amp;rsquo;t have to test it.&lt;/p>
&lt;h3 id="how-to-handle-errors-produced-by-assertions">How to handle errors produced by assertions?&lt;/h3>
&lt;p>You can handle errors produced by assertions the same way you handle errors produced by your code. You can catch them and handle them in a specific way, or you can let them bubble up to the caller.&lt;/p>
&lt;p>For a backend application you can just log the error and return a 500 status code, for a frontend application you can show a message to the user and let him know that something went wrong (same applies to a mobile application or any other ui application).&lt;/p>
&lt;h2 id="rules-of-thumb">Rules of thumb&lt;/h2>
&lt;p>Here is the list of rules for using assertions:&lt;/p>
&lt;ul>
&lt;li>Use assertions to check for things that are very unlikely to happen, but if they do happen, they indicate a bug in your program.&lt;/li>
&lt;li>Use assertions to document assumptions made in the code, making it more readable and maintainable.&lt;/li>
&lt;li>Use assertions to check the state of a program and ensure it is behaving as expected.&lt;/li>
&lt;li>Don&amp;rsquo;t use assertions for predictable error conditions (like invalid user input or file not found).&lt;/li>
&lt;li>Don&amp;rsquo;t use assertions to handle or rectify errors. Their purpose is to highlight errors for easier debugging.&lt;/li>
&lt;/ul>
&lt;h2 id="personal-opinion">Personal opinion&lt;/h2>
&lt;p>Assertions is easy to use and very powerful tool, it helps to write more readable and maintainable code, it helps to prevent unexpected behaviour of the program. All the recommendations are very reasonable and I agree with them, but if you feel like you want to add an assertion which breaks the rules - just do it, the more you use them the better you understand their usage, it&amp;rsquo;s always better to add assertion to the place where it should be rather than not to add it at all.&lt;/p>
&lt;h2 id="conclusion">Conclusion&lt;/h2>
&lt;p>In conclusion, &lt;code>assertive programming&lt;/code> enables us to write robust, secure and efficient code by actively checking and validating state of a program. It&amp;rsquo;s about setting conditions that must be true at a certain point in our program and throwing an error if they are not. When used properly and responsibly, assertions can enhance the clarity and comprehensibility of our code, reduce debugging and maintenance time, and increase the overall quality of our software.&lt;/p>
&lt;p>However, as with most tools, assertive programming has its limits. It&amp;rsquo;s not a replacement for well-thought-out control flow, validation of user input, or perceptive exception handling in general. Nor is it a replacement for a comprehensive test suite, as assertions and tests have their distinct roles.&lt;/p>
&lt;p>Rather than seeing assertions as the panacea for our code quality, we should view them as an additional layer of defense, a form of &amp;ldquo;active documentation&amp;rdquo; that declares and enforces our assumptions about how functions are intended to behave. They complement other good coding practices, providing a more assertive and proactive approach to crafting reliable and maintainable software, and should be an important part of any developer&amp;rsquo;s toolkit.&lt;/p>
&lt;p>Just like in the kitchen, &amp;ldquo;assertive&amp;rdquo; attention to detail can make all the difference between a successful meal-or a successful application-and a disastrous one. Happy assertive coding!&lt;/p></description></item><item><title>You don't need GraphQL to query less data</title><link>https://blog.rpidburachynskyi.dev/p/partial-response/</link><pubDate>Fri, 24 Nov 2023 00:00:00 +0000</pubDate><guid>https://blog.rpidburachynskyi.dev/p/partial-response/</guid><description>&lt;img src="https://blog.rpidburachynskyi.dev/p/partial-response/cover.webp" alt="Featured image of post You don't need GraphQL to query less data" />&lt;h1 id="you-dont-need-graphql-to-query-less-data">You don&amp;rsquo;t need GraphQL to query less data&lt;/h1>
&lt;h2 id="introduction">Introduction&lt;/h2>
&lt;p>Imagine you&amp;rsquo;ve been working on the application for a long time. You&amp;rsquo;ve created many REST endpoints which are working fine, but you begin to notice that your queries are slowing down. You suspect it&amp;rsquo;s because you&amp;rsquo;re retrieving too much data from the server. You&amp;rsquo;ve heard about GraphQL and its way to query less data, but changing whole application structure to GraphQL is not best idea at that time, so you decide to remove redundant fields from the response, or create different endpoints for different client application view, yeah, it works, but it takes additional time to do that, it increases the number of bugs as you can forget to add some fields to some endpoints and so on. But is it really the only way? Let&amp;rsquo;s find out.&lt;/p>
&lt;h2 id="the-problem">The problem&lt;/h2>
&lt;p>Let&amp;rsquo;s imagine that we have a simple REST endpoint which returns a list of users:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;John&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;age&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">20&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;email&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;john@mail.com&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Jane&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;age&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">25&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;email&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;jane@mail.com&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Bob&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;age&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">30&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;email&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;bob@mail.com&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>And we have a client application which uses this endpoint to display a list of users. The problem is that we don&amp;rsquo;t need all the fields from the response, we need only &lt;code>id&lt;/code>, &lt;code>name&lt;/code>, and &lt;code>email&lt;/code>. So we have two options:&lt;/p>
&lt;ol>
&lt;li>Remove redundant fields from the response.&lt;/li>
&lt;li>Create a new endpoint which will return only the fields we need.&lt;/li>
&lt;/ol>
&lt;p>First way is the easiest one, but there is one big disadvantage:&lt;/p>
&lt;ul>
&lt;li>At some point of the application you may need to grab &lt;code>age&lt;/code> field was well as other fields.&lt;/li>
&lt;/ul>
&lt;p>Second way is a little harder, but it&amp;rsquo;s more flexible, but it also has a disadvantage:&lt;/p>
&lt;ul>
&lt;li>You need to create a new endpoint for every view of the client application.&lt;/li>
&lt;li>Once you add a new field to the user you need to add that to all endpoints where this field should be used.&lt;/li>
&lt;li>Usually the team who works on the client application is different from the team who works on the server, so you need to communicate with them to add new fields to the endpoints.&lt;/li>
&lt;/ul>
&lt;p>Is there another way to resolve this issue without these disadvantages? Certainly, let&amp;rsquo;s look into it.&lt;/p>
&lt;h2 id="the-solution">The solution&lt;/h2>
&lt;p>The solution is to use a query parameter which allows us to specify which fields we want to get from the server. Let&amp;rsquo;s call it &lt;code>fields&lt;/code>, so now the request will look like:&lt;/p>
&lt;ol>
&lt;li>For one view:&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">GET /users?fields&lt;span class="o">=&lt;/span>id,name,email
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;ol start="2">
&lt;li>For another view:&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">GET /users?fields&lt;span class="o">=&lt;/span>id,name,age
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Let&amp;rsquo;s define some rules and convention for that.&lt;/p>
&lt;h2 id="the-rules">The rules&lt;/h2>
&lt;p>Here is the list of rules which, I believe, should be used for this approach:&lt;/p>
&lt;ol>
&lt;li>If the &lt;code>fields&lt;/code> parameter is not specified, return all fields.&lt;/li>
&lt;li>If the &lt;code>fields&lt;/code> parameter is specified, return only the fields which are specified in the parameter.&lt;/li>
&lt;li>If the &lt;code>fields&lt;/code> parameter is specified and the field is not found, just ignore that (do not throw an error or return value for that).&lt;/li>
&lt;li>If the &lt;code>fields&lt;/code> parameter consists only of fields which are not found, return an empty object.&lt;/li>
&lt;li>If the &lt;code>fields&lt;/code> parameter includes nested fields which are not found, but the parent field is found, return the parent field with an empty object as a value.&lt;/li>
&lt;li>If the &lt;code>fields&lt;/code> parameter includes nested fields but the actual value is not an object or array, do not return anything for that field (see &lt;a class="link" href="#example-5" >example #5&lt;/a>).&lt;/li>
&lt;/ol>
&lt;h2 id="the-convention">The convention&lt;/h2>
&lt;p>The last thing we need to think about is the convention for the &lt;code>fields&lt;/code> parameter. I think that the best way is to have the &lt;code>fields&lt;/code> parameter a string with comma-separated fields.&lt;/p>
&lt;p>Before we start, let&amp;rsquo;s define the object we will have examples with:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">GET /users?fields&lt;span class="o">=&lt;/span>id,name,email
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Nested fields should be represented in the same way, but inside the parentheses, for example:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">GET /users?fields&lt;span class="o">=&lt;/span>id,name,email,country&lt;span class="o">(&lt;/span>name&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>The same logic applied to the arrays, for example:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">GET /users?fields&lt;span class="o">=&lt;/span>id,name,email,phones&lt;span class="o">(&lt;/span>number&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="real-examples">Real examples&lt;/h2>
&lt;p>Let&amp;rsquo;s define the object we will have examples with:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;firstName&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;John&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;lastName&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Doe&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;username&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;jdoe&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;email&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;john.doe@mail.com&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;address&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;street&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;123 Main St.&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;city&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;New York&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;state&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;NY&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;zip&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">10001&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;dateOfBirth&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;1980-01-02T00:00:00.000Z&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;registered&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;country&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;United States&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;code&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;US&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;information&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;capital&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Washington, D.C.&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;population&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">320000000&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;emergencyContacts&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;firstName&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Jane&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;lastName&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Doe&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;phone&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;212-555-1234&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;firstName&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;John&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;lastName&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Smith&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;phone&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;212-555-1234&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;firstName&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;James&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;lastName&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Johnson&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;phone&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;212-555-1234&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;roles&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;user&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;admin&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="example-1">Example 1&lt;/h3>
&lt;p>Pick root fields:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">GET /users?fields&lt;span class="o">=&lt;/span>id,firstName,lastName
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Response:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;firstName&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;John&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;lastName&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Doe&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="example-2">Example 2&lt;/h3>
&lt;p>Pick nested fields:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">GET /users?fields&lt;span class="o">=&lt;/span>id,country&lt;span class="o">(&lt;/span>name&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Response:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;country&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;United States&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="example-3">Example 3&lt;/h3>
&lt;p>Pick primitive fields from the array:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">GET /users?fields&lt;span class="o">=&lt;/span>id,roles
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Response:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;roles&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;user&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;admin&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="example-4">Example 4&lt;/h3>
&lt;p>Pick nested fields from the array:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">GET /users?fields&lt;span class="o">=&lt;/span>id,emergencyContacts&lt;span class="o">(&lt;/span>firstName,lastName&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Response:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;emergencyContacts&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;firstName&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Jane&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;lastName&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Doe&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;firstName&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;John&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;lastName&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Smith&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;firstName&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;James&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;lastName&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Johnson&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="example-5">Example 5&lt;/h3>
&lt;p>Pick nested fields from the primitive field:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">GET /users?fields&lt;span class="o">=&lt;/span>id&lt;span class="o">(&lt;/span>value&lt;span class="o">)&lt;/span>, roles
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Response:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// id is not present in the response
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nt">&amp;#34;roles&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;user&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;admin&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="extending-the-pattern">Extending the pattern&lt;/h2>
&lt;p>The rules for the pattern described above covers 99.9% of all cases, but there can be cases where you need to extend the pattern.
Here is the list of possible extensions:&lt;/p>
&lt;ol>
&lt;li>Regular expressions. For example, you want to get all fields which start with &lt;code>name&lt;/code> or something like that. It&amp;rsquo;s not the best practice as it can be time-consuming as regular expressions are not the fastest thing in the world, but it can be useful in some cases.&lt;/li>
&lt;li>Getting only the first (or last) N elements from the array. For example, you want to get only the first 5 elements from the array. It can be useful when you have a huge array and you want to get only the first elements to reduce the response size.&lt;/li>
&lt;li>Get the defined list of fields of all objects inside some field (kind of &lt;code>instruments(*(id, name))&lt;/code>).&lt;/li>
&lt;li>Filtering by some condition (like &lt;code>order(*[ &amp;gt; 5])&lt;/code>), but it&amp;rsquo;s rare case as it&amp;rsquo;s better to add that filter option right to the API.&lt;/li>
&lt;/ol>
&lt;h2 id="useful-libraries">Useful Libraries&lt;/h2>
&lt;h3 id="nodejs">Node.js&lt;/h3>
&lt;p>The library &lt;a class="link" href="https://www.npmjs.com/package/json-mask" target="_blank" rel="noopener"
>json-mask&lt;/a> is a good choice for Node.js applications, it fully covers all the rules and conventions described above (except extended cases).&lt;/p>
&lt;p>The library &lt;a class="link" href="https://www.npmjs.com/package/express-partial-response" target="_blank" rel="noopener"
>express-partial-response&lt;/a> uses package &lt;a class="link" href="https://www.npmjs.com/package/json-mask" target="_blank" rel="noopener"
>json-mask&lt;/a> under the hood and has prepared middleware for Express.js.&lt;/p>
&lt;h3 id="python">Python&lt;/h3>
&lt;p>The library &lt;a class="link" href="https://pypi.org/project/jsonmask/" target="_blank" rel="noopener"
>jsonmask&lt;/a> is a good choice for Python applications, it fully covers all the rules and conventions described above (except extended cases).&lt;/p>
&lt;p>The library &lt;a class="link" href="https://pypi.org/project/djangorestframework-queryfields/" target="_blank" rel="noopener"
>django-rest-framework-queryfields&lt;/a> has similar functionality, but it is designed for Django REST Framework.&lt;/p></description></item><item><title>Search</title><link>https://blog.rpidburachynskyi.dev/search/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://blog.rpidburachynskyi.dev/search/</guid><description/></item></channel></rss>