<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gabriel</title>
    <description>The latest articles on DEV Community by Gabriel (@gabotechs).</description>
    <link>https://dev.to/gabotechs</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1030555%2F3d680dd4-1b55-439b-a2bd-836561a95d6b.jpeg</url>
      <title>DEV Community: Gabriel</title>
      <link>https://dev.to/gabotechs</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gabotechs"/>
    <language>en</language>
    <item>
      <title>About Software Complexity...</title>
      <dc:creator>Gabriel</dc:creator>
      <pubDate>Sat, 06 Jan 2024 18:40:21 +0000</pubDate>
      <link>https://dev.to/gabotechs/about-software-complexity-569d</link>
      <guid>https://dev.to/gabotechs/about-software-complexity-569d</guid>
      <description>&lt;p&gt;Complexity is the worst enemy of a software developer. It makes organizations slow, businesses unscalable, and developers unhappy.&lt;/p&gt;

&lt;p&gt;When starting a project from scratch, it feels clean, it's easy to reason about, and easy to extend with new features. That's a good feeling; I bet you've been in that situation and have thought: &lt;/p&gt;

&lt;p&gt;"If only the big old boring project I need to maintain at work was like that..."&lt;/p&gt;

&lt;p&gt;And wasn't it like that when it started? It's very likely that it was, then what happened? What made the project a big messy pile of code? Is my new clean and shiny project also destined to be like that if it grows?&lt;/p&gt;

&lt;p&gt;Let's analyze the main sources of complexity in software:&lt;/p&gt;

&lt;h2&gt;
  
  
  Lack of skill/motivation:
&lt;/h2&gt;

&lt;p&gt;Sometimes, developers just want to get paid. They want to solve the problem right in front of them as quickly as possible and collect a paycheck at the end of the month. That's fine, but that mentality naturally pushes developers to ship lazy and sub-optimal solutions as long as they solve the immediate problem. This adds up over time, stacking patches together making a code base exponentially harder to maintain as it grows.&lt;/p&gt;

&lt;h2&gt;
  
  
  RDD (Resume Driven Development):
&lt;/h2&gt;

&lt;p&gt;Other developers just want to try out the new stuff. They are too passionate not to try out every new piece of technology that comes out, or maybe they just want a better resume in order to switch jobs. Simple problems are simple, but RDD is about making them complex by designing a system for 100x the expected scale, introducing every existing OOP pattern just for the sake of trying it out, or rewriting chunks of an app in the new framework just because it's new.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evolving Business:
&lt;/h2&gt;

&lt;p&gt;Here things get tricky. Businesses evolve, and the code in charge of providing features A, B, and C now needs to provide feature D, but it looks like feature D does not quite match with some assumptions made when shipping features A, B, and C. If there's time, a refactor for cleanly holding feature D can be done, but maybe there's not enough time, or maybe D is crazy different. This source of complexity tends to be unavoidable, but it can be greatly mitigated with good management, business vision, and reasonable deadlines.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem is just complex:
&lt;/h2&gt;

&lt;p&gt;Maybe you are building the compiler for the next C++ replacement, or maybe you need to serve millions of requests per second with single-digit milliseconds latency. Some problems are just complex. This might be the only pleasurable source of complexity to have.&lt;/p&gt;

&lt;h1&gt;
  
  
  Visualizing a code base entropy
&lt;/h1&gt;

&lt;p&gt;Imagine a complex code base that you've worked on. Try to imagine it as a whole, with all the files, all the folders, all the modules, all the packages...&lt;/p&gt;

&lt;p&gt;What do you see? &lt;/p&gt;

&lt;p&gt;I welcome you to &lt;a href="https://github.com/gabotechs/dep-tree"&gt;Dep Tree&lt;/a&gt;, a tool that allows you to render the "entropy" of a code base, and visualize its complexity with a 3D force-directed graph.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  3D force-directed graph
&lt;/h2&gt;

&lt;p&gt;A 3D force-directed graph is a way of representing a graph in a three-dimensional space where nodes are placed based on some attraction/repulsion forces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If a node is connected to another one by an edge, an attraction force will pull them together.&lt;/li&gt;
&lt;li&gt;If two nodes are not connected, a repulsion force will try to take them apart.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In &lt;a href="https://github.com/gabotechs/dep-tree"&gt;Dep Tree&lt;/a&gt;, nodes are source files, and if a file is importing another one, then an edge is created between them. If a file is importing another file, they will be rendered close together; otherwise, they will tend to be placed apart.&lt;/p&gt;

&lt;p&gt;Additionally, if two files are in the same folder, an attraction force is created between them even if they are not importing each other, as it's assumed that they are somehow related.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does a clean code base look like?
&lt;/h2&gt;

&lt;p&gt;Clean code bases will be rendered with nodes grouped into clusters, and clusters of nodes clearly separated from each other. Something like this:&lt;/p&gt;

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

&lt;p&gt;Otherwise, code bases that are messier, with no clear separation of modules, will tend to have all the nodes grouped together with no clear sense of clustering:&lt;/p&gt;

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

&lt;h1&gt;
  
  
  Visualize the entropy of well know open source projects
&lt;/h1&gt;

&lt;p&gt;Here's the entropy visualization of some well-known projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dep-tree-explorer.vercel.app/api?repo=https%3A%2F%2Fgithub.com%2Flangchain-ai%2Flangchain&amp;amp;entrypoint=libs%2Flangchain%2Flangchain%2F__init__.py"&gt;langchain&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dep-tree-explorer.vercel.app/api?repo=https%3A%2F%2Fgithub.com%2Ftiangolo%2Ffastapi&amp;amp;entrypoint=fastapi%2F__init__.py"&gt;fastapi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dep-tree-explorer.vercel.app/api?repo=https%3A%2F%2Fgithub.com%2Fnumpy%2Fnumpy&amp;amp;entrypoint=numpy%2F__init__.py"&gt;numpy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dep-tree-explorer.vercel.app/api?repo=https%3A%2F%2Fgithub.com%2Fmicrosoft%2FTypeScript&amp;amp;entrypoint=src%2Ftypescript%2Ftypescript.ts"&gt;typescript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dep-tree-explorer.vercel.app/api?repo=https%3A%2F%2Fgithub.com%2Ffacebook%2Freact&amp;amp;entrypoint=packages%2Freact-dom%2Findex.js"&gt;react&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dep-tree-explorer.vercel.app/api?repo=https%3A%2F%2Fgithub.com%2Fsveltejs%2Fsvelte&amp;amp;entrypoint=packages%2Fsvelte%2Fsrc%2Fcompiler%2Findex.js"&gt;svelte&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dep-tree-explorer.vercel.app/api?repo=https%3A%2F%2Fgithub.com%2Fvuejs%2Fvue&amp;amp;entrypoint=src%2Fcore%2Findex.ts"&gt;vuejs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dep-tree-explorer.vercel.app/api?repo=https%3A%2F%2Fgithub.com%2Fangular%2Fangular&amp;amp;entrypoint=packages%2Fcompiler%2Findex.ts"&gt;angular&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dep-tree-explorer.vercel.app/api?repo=https%3A%2F%2Fgithub.com%2Fstorybookjs%2Fstorybook&amp;amp;entrypoint=code%2Fui%2Fblocks%2Fsrc%2Findex.ts"&gt;storybook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dep-tree-explorer.vercel.app/api?repo=https%3A%2F%2Fgithub.com%2Fmrdoob%2Fthree.js&amp;amp;entrypoint=src%2FThree.js"&gt;three.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(beware of these two, as they are very resource-intensive to render)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dep-tree-explorer.vercel.app/api?repo=https%3A%2F%2Fgithub.com%2Fpytorch%2Fpytorch&amp;amp;entrypoint=torch%2Fnn%2F__init__.py"&gt;pytorch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dep-tree-explorer.vercel.app/api?repo=https%3A%2F%2Fgithub.com%2Ftensorflow%2Ftensorflow&amp;amp;entrypoint=tensorflow%2Fpython%2Fkeras%2Fmodels.py"&gt;tensorflow&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  What's next?
&lt;/h1&gt;

&lt;p&gt;If you like Dep Tree, feel free to stop by the &lt;a href="https://github.com/gabotechs/dep-tree"&gt;GitHub repository&lt;/a&gt; and give it a star. Check out the README and you will find out that Dep Tree is far more than just a cool visualization tool; it can actually help you enforce your code base decoupling!&lt;/p&gt;

&lt;p&gt;Hope you liked it, and see you soon!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Stream OpenAI's ChatGPT responses directly in the browser.</title>
      <dc:creator>Gabriel</dc:creator>
      <pubDate>Tue, 20 Jun 2023 17:40:00 +0000</pubDate>
      <link>https://dev.to/gabotechs/stream-openais-chatgpt-responses-directly-in-the-browser-h35</link>
      <guid>https://dev.to/gabotechs/stream-openais-chatgpt-responses-directly-in-the-browser-h35</guid>
      <description>&lt;p&gt;In this blog post you will learn how to stream OpenAI API responses directly in the browser, without the need for a backend as a middle-man between OpenAI and the browser application and without leaking your OpenAI API key to the world.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stream the response through &lt;a href="https://www.signway.io" rel="noopener noreferrer"&gt;Signway&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Signway is an open source and managed solution for generating pre-signed URLs, like the ones &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/ShareObjectPreSignedURL.html" rel="noopener noreferrer"&gt;AWS S3&lt;/a&gt; uses for sharing objects, but in this case for proxying correctly signed requests to destination APIs, and stream the response back. Its core is open source, so you can also host it yourself &lt;a href="https://github.com/gabotechs/signway" rel="noopener noreferrer"&gt;https://github.com/gabotechs/signway&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  For following this tutorial you will need
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.python.org/downloads/" rel="noopener noreferrer"&gt;Python +3.9&lt;/a&gt; or greater installed in you system&lt;/li&gt;
&lt;li&gt;An &lt;a href="https://platform.openai.com/account/api-keys" rel="noopener noreferrer"&gt;OpenAI Api key&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create a Signway Application
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Go to &lt;a href="https://www.signway.io" rel="noopener noreferrer"&gt;Signway's web page&lt;/a&gt; and log into the console.&lt;/li&gt;
&lt;li&gt;Once you log in you will be prompted to create an Application.&lt;/li&gt;
&lt;li&gt;After giving a nice name to the Application, you will see a pop-up sowing the newly created Application ID and Secret. Copy them and store them in a safe place, we will need them later.&lt;/li&gt;
&lt;li&gt;Once the Application is created, go to "Custom Headers" and add the "Authorization" header that will be sent to OpenAI.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h2&gt;
  
  
  Code a function that generates pre-signed URLs for Signway in Python 🐍
&lt;/h2&gt;

&lt;p&gt;We will be using Python for this, but other languages could be used for generating pre-signed URLs.&lt;/p&gt;

&lt;p&gt;First, create a virtual environment and install the Signway SDK:&lt;/p&gt;

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

python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv
&lt;span class="nb"&gt;source &lt;/span&gt;venv/bin/activate
pip &lt;span class="nb"&gt;install &lt;/span&gt;signway-sdk


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

&lt;/div&gt;

&lt;p&gt;Then create a script that generates pre-signed URLs. We will call this script &lt;code&gt;sign.py&lt;/code&gt;:&lt;/p&gt;

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

&lt;span class="c1"&gt;# sign.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;signway_sdk&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sign_url&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sign_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SW_ID&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="n"&gt;secret&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SW_SECRET&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.signway.io&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;proxy_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.openai.com/v1/completions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;expiry&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;900&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;))&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Export the application secrets saved from the earlier step:&lt;/p&gt;

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

&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SW_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SW_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;


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

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Remember to populate this variables with the Application ID and Application Secret that the Signway page gave you.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Executing this script gives us a URL that looks like this:&lt;/p&gt;

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

&lt;span class="nv"&gt;$ &lt;/span&gt;python3 sign.py

https://api.signway.io/?X-Sw-Algorithm&lt;span class="o"&gt;=&lt;/span&gt;SW1-HMAC-SHA256&amp;amp;X-Sw-Credential&lt;span class="o"&gt;=&lt;/span&gt;app-id%2F20230619&amp;amp;X-Sw-Date&lt;span class="o"&gt;=&lt;/span&gt;20230619T195222Z&amp;amp;X-Sw-Expires&lt;span class="o"&gt;=&lt;/span&gt;300&amp;amp;X-Sw-Proxy&lt;span class="o"&gt;=&lt;/span&gt;https%3A%2F%2Fapi.openai.com%2Fv1%2Fcompletions&amp;amp;X-Sw-SignedHeaders&lt;span class="o"&gt;=&lt;/span&gt;&amp;amp;X-Sw-Body&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&amp;amp;X-Sw-Signature&lt;span class="o"&gt;=&lt;/span&gt;4aa60955f477eeb2bd556c41ecce3508d02b5b83bec9c0c188737998f73c5176


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

&lt;/div&gt;

&lt;p&gt;That is a signed URL, it can be safely transferred to clients  as it does not contain any sensible information. In this case, we have set an expiration time of 15 mins, after that time the URL will be useless.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the frontend code that will stream the response
&lt;/h2&gt;

&lt;p&gt;For this we will use a very simple example without using any framework:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Remeber to execute &lt;code&gt;python3 sign.py&lt;/code&gt; and copy-paste the generated URL in the &lt;code&gt;const URL = ""&lt;/code&gt; variable&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;// Execute 'python3 sign.py' and paste the result URL&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;

    &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-davinci-003&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Say this is a test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#response&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getReader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextDecoder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;decoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"response"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;If you open this file in your browser you will see how the response from Open AI is streamed.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;You can do more things with Signway, like providing extra security by signing more things in the request, like the body or some headers. There is a cool tutorial about this &lt;a href="https://gabotechs.github.io/signway/openai.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The natural thing to do is to generate pre-signed URLs from a trusted source, like your backend, you can use the excellent &lt;a href="https://fastapi.tiangolo.com/lo/" rel="noopener noreferrer"&gt;FastAPI&lt;/a&gt; framework for that.&lt;/li&gt;
&lt;li&gt;Make sure to pass by the &lt;a href="https://github.com/gabotechs/signway" rel="noopener noreferrer"&gt;Github repo&lt;/a&gt; and give it a star if you like it.&lt;/li&gt;
&lt;li&gt;Feel free to play around the free tier of &lt;a href="https://www.signway.io" rel="noopener noreferrer"&gt;Signway Managed&lt;/a&gt;, but join the waitlist if you are willing to take it to the next level.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>openai</category>
      <category>chatgpt</category>
      <category>browser</category>
      <category>api</category>
    </item>
    <item>
      <title>Using pre-signed URLs with OpenAI's API</title>
      <dc:creator>Gabriel</dc:creator>
      <pubDate>Thu, 15 Jun 2023 17:25:47 +0000</pubDate>
      <link>https://dev.to/gabotechs/using-pre-signed-urls-with-openais-api-5ghl</link>
      <guid>https://dev.to/gabotechs/using-pre-signed-urls-with-openais-api-5ghl</guid>
      <description>&lt;p&gt;While making an LLM product using OpenAI's API one of the first questions that arises is:&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is OpenAI's API so slow?
&lt;/h2&gt;

&lt;p&gt;Depending on the question and the prompt, the response can be quite long, and the longer it is, the longer it takes for ChatGPT's API to return the answer.&lt;/p&gt;

&lt;p&gt;If you make a question in ChatGPT's official page, the response comes little by little, chunk by chunk, so even if it takes some time to return the full response, it is not that bad, as you are able to read the answer as it comes.&lt;/p&gt;

&lt;p&gt;This is because ChatGPT's responses are streams of data, instead of just one big blob, so if you see that the response you make in your application is crazy slow, is because you are actually waiting for ChatGPT for generating the full response.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then, how do I stream the response like in OpenAI's official web page?
&lt;/h2&gt;

&lt;p&gt;Typically, you would make the request to OpenAI's API in your &lt;strong&gt;backend&lt;/strong&gt;, as you need to pass your OpenAI API key, which is private to you, but re-streaming the data to the &lt;strong&gt;frontend&lt;/strong&gt; can get really tricky depending on your stack and infra...&lt;/p&gt;

&lt;p&gt;Then why not just make the query directly from the mobile/web app? you could just use &lt;code&gt;fetch&lt;/code&gt; for querying OpenAI directly there. The answer is simple: &lt;strong&gt;because you do not want to leak your API KEY to the world&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But what if there was a way of querying OpenAI's API directly from the browser/mobile app without the need of leaking your API KEY...&lt;/p&gt;

&lt;h2&gt;
  
  
  Meet &lt;a href="https://www.signway.io"&gt;Signway&lt;/a&gt;, a service that brings the power of pre-signed URLs to your apps.
&lt;/h2&gt;

&lt;p&gt;Signway is a high performant gateway that proxies pre-signed requests to the specified destination.&lt;/p&gt;

&lt;p&gt;It uses the same cryptographic trick that &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/ShareObjectPreSignedURL.html"&gt;AWS S3 uses with its pre-signed URLs&lt;/a&gt;, but it redirects requests to specified destinations instead of giving access to S3 objects.&lt;/p&gt;

&lt;p&gt;You can see this more in detail in &lt;a href="https://github.com/gabotechs/signway"&gt;https://github.com/gabotechs/signway&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The idea is the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You configure Signway with an &lt;code&gt;id&lt;/code&gt; and a &lt;code&gt;secret&lt;/code&gt;. The &lt;a href="https://www.signway.io"&gt;managed version&lt;/a&gt; already does this for you, but you could also &lt;a href="https://hub.docker.com/repository/docker/gabotechs/signway"&gt;launch it with docker&lt;/a&gt; and configure it yourself.&lt;/li&gt;
&lt;li&gt;In your backend, instead of querying OpenAI's API, you create a pre-signed url using Signway's &lt;a href="https://github.com/gabotechs/signway-python-sdk"&gt;Python SDK&lt;/a&gt; or &lt;a href="https://github.com/gabotechs/signway-js-sdk"&gt;JavaScript SDK&lt;/a&gt;. For that, you will need to use the same &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;secret&lt;/code&gt; that Signway is configured with.&lt;/li&gt;
&lt;li&gt;You send the generated pre-signed URL back to the frontend, and you make the request using &lt;code&gt;fetch&lt;/code&gt; as if you where querying OpenAI's API but the URL is different (it is the Signway's pre-signed one)&lt;/li&gt;
&lt;li&gt;The request will pass through Signway, who will validate that the request is authentic and has not expired. If everything looks great, you will see OpenAI's response directly in the client app, without any backend in the middle.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Checkout &lt;a href="https://dev.to/gabotechs/stream-openais-chatgpt-responses-directly-in-the-browser-h35"&gt;this post&lt;/a&gt; if you want to learn how to use Signway for streaming ChatGPT responses in the browser.&lt;/li&gt;
&lt;li&gt;There is an example &lt;a href="https://gabotechs.github.io/signway/openai.html"&gt;here&lt;/a&gt; where you can hack around yourself with Signway using &lt;code&gt;python&lt;/code&gt; for generating pre-signed URLs, &lt;code&gt;curl&lt;/code&gt; for making http requests to OpenAI and &lt;code&gt;docker&lt;/code&gt; for launching &lt;code&gt;Signway&lt;/code&gt; in your local machine.&lt;/li&gt;
&lt;li&gt;Check the &lt;a href="https://github.com/gabotechs/signway"&gt;github repo&lt;/a&gt;, as it has more detailed explanation of how this works.&lt;/li&gt;
&lt;li&gt;If you want a fully managed solution, check &lt;a href="https://www.signway.io"&gt;Signway's website&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>openai</category>
      <category>chatgpt</category>
      <category>api</category>
    </item>
    <item>
      <title>Dep Tree - A tool for validating your project's file dependency graph in the CI</title>
      <dc:creator>Gabriel</dc:creator>
      <pubDate>Sun, 07 May 2023 12:14:13 +0000</pubDate>
      <link>https://dev.to/gabotechs/dep-tree-a-tool-for-validating-your-projects-file-dependency-graph-in-the-ci-3b9a</link>
      <guid>https://dev.to/gabotechs/dep-tree-a-tool-for-validating-your-projects-file-dependency-graph-in-the-ci-3b9a</guid>
      <description>&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;Dep Tree is a CLI tool that is meant to be used either in CI systems or in the users local machines. It takes a JavaScript/TypeScript project as an input and validates/renders its file dependency graph.&lt;/p&gt;

&lt;h3&gt;
  
  
  Category Submission:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Maintainer Must-Haves&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Dep Tree was designed to be used in CI systems in projects with a lot of people collaborating.&lt;/p&gt;

&lt;p&gt;It is very common to setup some other static analysis tools like linters for automatically checking that contributors are following some established rules regarding code style.&lt;/p&gt;

&lt;p&gt;Dep Tree does the same, but analything the file dependency graph in the project, failing the CI workflow if a contributor introduces a dependency in the code that couple things that should be decoupled. &lt;/p&gt;

&lt;h3&gt;
  
  
  App Link
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/gabotechs/dep-tree" rel="noopener noreferrer"&gt;https://github.com/gabotechs/dep-tree&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Screenshots
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgj9vycfoz8t93ps611kp.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgj9vycfoz8t93ps611kp.gif" alt="How  raw `dep-tree` endraw 's interactive CLI looks like"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;dep-tree&lt;/code&gt; is a cli tool that allows users to render their file dependency tree in the terminal, or check that it matches some dependency rules in CI systems.&lt;/p&gt;

&lt;p&gt;It works with files, meaning that each file is a node in the dependency tree:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It starts from an entrypoint, which is usually the main executable file in a program or the file that exposes the contents of a library (like src/index.ts).&lt;/li&gt;
&lt;li&gt;It reads its import statements, it makes a parent node out of the main file, and one child node for each imported file.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: it only takes into account local files, not files imported from external libraries.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;That process is repeated recursively with all the child files, until the file dependency tree is formed.&lt;/li&gt;
&lt;li&gt;If rendering the dependency tree in the terminal, the nodes will be placed in a human-readable way, and users can navigate through the graph using the keyboard.&lt;/li&gt;
&lt;li&gt;If validating the dependency tree in a CI system, it will check that the dependencies between files match some boundaries declared in a .dep-tree.yml file.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Link to Source Code
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/gabotechs/dep-tree" rel="noopener noreferrer"&gt;https://github.com/gabotechs/dep-tree&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Permissive License
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/gabotechs/dep-tree/blob/main/LICENSE" rel="noopener noreferrer"&gt;MIT&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Background (What made you decide to build this particular app? What inspired you?)
&lt;/h2&gt;

&lt;p&gt;I work at propeldata.com, and our backend relies heavily on TypeScript.&lt;/p&gt;

&lt;p&gt;As the company evolves, so does the code, and we had no way for ensuring that parts of a project that where initially designed to be decoupled, remain decoupled as more people contribute to the codebase.&lt;/p&gt;

&lt;p&gt;We use &lt;code&gt;dep-tree&lt;/code&gt; not only for better understanding the dependency flow in our applications, but also for validating in CI pipelines that new commits do not break any dependency rule.&lt;/p&gt;

&lt;h3&gt;
  
  
  How I built it (How did you utilize GitHub Actions or GitHub Codespaces? Did you learn something new along the way? Pick up a new skill?)
&lt;/h3&gt;

&lt;p&gt;The project is written in Go, and it ships an executable binary with a CLI interface.&lt;/p&gt;

&lt;p&gt;It's pipelines heavily rely on GitHub Actions for testing, linting and automatically releasing new versions of this binary. Each commit in a PR gets tested and linted, and on a merge to &lt;code&gt;main&lt;/code&gt;, a new tag and a GitHub release is created (&lt;code&gt;homebrew&lt;/code&gt; tap included).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dep-tree&lt;/code&gt; even ships its own GitHub Action &lt;a href="https://github.com/gabotechs/dep-tree-action" rel="noopener noreferrer"&gt;https://github.com/gabotechs/dep-tree-action&lt;/a&gt;, that people can use out-of-the-box in their GitHub Actions pipelines.&lt;/p&gt;

&lt;p&gt;The biggest lesson I got from setting up all this workflows was to be able to ship cross-compiled binaries for all the architectures and packaging them in a &lt;code&gt;homebrew&lt;/code&gt; tap. GitHub Actions combined with &lt;a href="https://goreleaser.com/" rel="noopener noreferrer"&gt;https://goreleaser.com/&lt;/a&gt; made this extremely easy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Additional Resources/Info
&lt;/h3&gt;

&lt;p&gt;I have another blog post here with some sample use cases that have proven to be relevant in our daily workflow: &lt;a href="https://dev.to/gabotechs/dep-tree-a-tool-for-rendering-and-linting-your-projects-dependency-tree-in-the-terminal-25om"&gt;https://dev.to/gabotechs/dep-tree-a-tool-for-rendering-and-linting-your-projects-dependency-tree-in-the-terminal-25om&lt;/a&gt;&lt;/p&gt;

</description>
      <category>githubhack23</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>github</category>
    </item>
    <item>
      <title>GraphQXL: the missing language extension</title>
      <dc:creator>Gabriel</dc:creator>
      <pubDate>Sun, 12 Mar 2023 16:47:57 +0000</pubDate>
      <link>https://dev.to/gabotechs/graphqxl-the-missing-language-extension-4f48</link>
      <guid>https://dev.to/gabotechs/graphqxl-the-missing-language-extension-4f48</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/gabotechs/graphqxl"&gt;https://github.com/gabotechs/graphqxl&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I work at &lt;a href="//www.propeldata.com"&gt;Propel&lt;/a&gt;, a platform for creating serverless analytical data products, and we use GraphQL extensively to enable our customers to communicate with us.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Customers can connect their data with Propel using our API.&lt;/li&gt;
&lt;li&gt;They can execute real-time analytic queries using GraphQL.&lt;/li&gt;
&lt;li&gt;They can manage their account's resources using GraphQL API requests.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;As you may imagine, Propel's GraphQL API is pretty big, and we want to keep it clean, maintainable, and as well-documented as possible. Unfortunately, sometimes GraphQL does not make things easy for us:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Common fields&lt;/strong&gt;: While defining &lt;code&gt;types&lt;/code&gt;, we need to copy-paste all the common fields across a lot of resources, fields like &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;createdAt&lt;/code&gt;, &lt;code&gt;modifiedBy&lt;/code&gt;...&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CRUD inputs&lt;/strong&gt;: When defining &lt;code&gt;inputs&lt;/code&gt; that are meant to create or modify specific resources, there is a lot of repeated code for handling the &lt;code&gt;input&lt;/code&gt; that creates the resource vs the one that modifies it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cursor pagination&lt;/strong&gt;: We follow the &lt;a href="https://relay.dev/graphql/connections.htm"&gt;GraphQL Cursor Connections Specification&lt;/a&gt;, and for each paginated resource, we need to define its own &lt;code&gt;Edge&lt;/code&gt; and &lt;code&gt;Connection&lt;/code&gt; even though all look the same.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation&lt;/strong&gt;: We document every field, and if there is a common field across different &lt;code&gt;types&lt;/code&gt; or &lt;code&gt;inputs&lt;/code&gt;, we need to maintain the documentation individually for each one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All these problems can be boiled down to one: the lack of tools the GraphQL SDL specification provides for reusing code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code-first approach?
&lt;/h2&gt;

&lt;p&gt;Using a code-first approach and auto-generating the GraphQL schema is a very common way to overcome this problem, but it has some disadvantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For customer-facing schemas, it can get tricky to control and review exactly what is being served to the customers, as there is no direct control of the GraphQL schema.&lt;/li&gt;
&lt;li&gt;Ensuring that the documentation is consistent across all the resources is less ergonomic, as the documentation pieces are spread through the code base.&lt;/li&gt;
&lt;li&gt;Non-technical people find it more difficult to contribute to new API features, as they will need to deal with actual code (TypeScript, Python, GoLang...).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But what if there is another way?&lt;/p&gt;

&lt;h2&gt;
  
  
  GraphQXL
&lt;/h2&gt;

&lt;p&gt;GraphQXL is a language built on top of the GraphQL SDL syntax that solves the reusability problems of the original language.&lt;/p&gt;

&lt;p&gt;It is framework-agnostic, as it is just an independent language that compiles down to plain GraphQL, that way it can be used with any programming language that supports it.&lt;/p&gt;

&lt;p&gt;Here are some of GraphQXL’s features:&lt;/p&gt;

&lt;h3&gt;
  
  
  Field inheritance
&lt;/h3&gt;

&lt;p&gt;One common pattern is to have an &lt;code&gt;interface&lt;/code&gt; that defines some common fields that are shared across many types, for example, imagine that we want to reuse the field’s from this &lt;code&gt;interface&lt;/code&gt; across multiple types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;modifiedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;createdBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;modifiedBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In GraphQXL spread operators can be used to solve this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source GraphQXL&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;modifiedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;createdBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;modifiedBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;implements&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="n"&gt;Resource&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;implements&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="n"&gt;Resource&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Compiled GraphQL&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;modifiedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;createdBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;modifiedBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;implements&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;modifiedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;createdBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;modifiedBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;implements&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;modifiedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;createdBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;modifiedBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://graphqxl-explorer.vercel.app/?code=aW50ZXJmYWNlIFJlc291cmNlIHsKICBpZDogSUQhCiAgY3JlYXRlZEF0OiBTdHJpbmchCiAgbW9kaWZpZWRBdDogU3RyaW5nCiAgY3JlYXRlZEJ5OiBTdHJpbmchCiAgbW9kaWZpZWRCeTogU3RyaW5nCn0KCnR5cGUgVXNlciBpbXBsZW1lbnRzIFJlc291cmNlIHsKICAuLi5SZXNvdXJjZQogIHVzZXJuYW1lOiBTdHJpbmchCn0KCnR5cGUgUHJvZHVjdCBpbXBsZW1lbnRzIFJlc291cmNlIHsKICAuLi5SZXNvdXJjZQogIHByaWNlOiBGbG9hdCEKfQ=="&gt;Try it in the GraphQXL explorer!&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Generics
&lt;/h3&gt;

&lt;p&gt;In GraphQL APIs there are usually some &lt;code&gt;types&lt;/code&gt; or &lt;code&gt;inputs&lt;/code&gt; that are very similar, and one clear example is the &lt;a href="https://relay.dev/graphql/connections.htm"&gt;cursor-based pagination&lt;/a&gt;. Generics are really good at handling structures that look almost the same but have a small difference:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source GraphQXL&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;"The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;variables&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="err"&gt;'s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Edge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;pagination"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_Edge&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;${{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;variables&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;}'s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;cursor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;that&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;refers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;current&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;node"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;cursor:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;"The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;variables&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;itself"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;node:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;T&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;"The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Connection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;paginating&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;across&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;variables&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="err"&gt;s"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_Connection&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;Metadata&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;${{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;variables&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;}s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;current&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;page"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;edges:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;[T&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ProductEdge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_Edge&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ProductConnection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_Connection&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ProductEdge&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UserEdge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_Edge&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UserConnection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_Connection&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;UserEdge&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Compiled GraphQL&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;"The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Product's&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Edge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;pagination"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ProductEdge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;that&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;refers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;itself&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;"The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Connection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;paginating&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;across&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ProductEdges"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ProductConnection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;Metadata&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ProductEdges&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ProductEdge&lt;/span&gt;&lt;span class="p"&gt;!]!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;"The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;User's&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Edge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;pagination"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UserEdge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;that&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;refers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;itself&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;"The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Connection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;paginating&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;across&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;UserEdges"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UserConnection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;Metadata&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UserEdges&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;UserEdge&lt;/span&gt;&lt;span class="p"&gt;!]!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://graphqxl-explorer.vercel.app/?code=dHlwZSBQcm9kdWN0IHsKICBwcmljZTogRmxvYXQhCn0KCnR5cGUgVXNlciB7CiAgdXNlcm5hbWU6IFN0cmluZyEKfQoKIlRoZSAke3sgdmFyaWFibGVzLlQgfX0ncyBFZGdlIG9iamVjdCBmb3IgcGFnaW5hdGlvbiIKdHlwZSBfRWRnZTxUPiB7CiAgIlRoZSAke3sgdmFyaWFibGVzLlQgfX0ncyBjdXJzb3IgdGhhdCByZWZlcnMgdG8gdGhlIGN1cnJlbnQgbm9kZSIKICBjdXJzb3I6IFN0cmluZyEKICAiVGhlICR7eyB2YXJpYWJsZXMuVCB9fSBpdHNlbGYiCiAgbm9kZTogVCEKfQoKIlRoZSBDb25uZWN0aW9uIG9iamVjdCBmb3IgcGFnaW5hdGluZyBhY3Jvc3MgdGhlICR7eyB2YXJpYWJsZXMuVCB9fXMiCnR5cGUgX0Nvbm5lY3Rpb248VD4gewogICJNZXRhZGF0YSB3aXRoIHRoZSBjdXJyZW50IHBhZ2UgaW5mbyIKICBtZXRhZGF0YTogU3RyaW5nIQogICJMaXN0IG9mICR7eyB2YXJpYWJsZXMuVCB9fXMgZm9yIHRoZSBjdXJyZW50IHBhZ2UiCiAgZWRnZXM6IFtUIV0hCn0KCnR5cGUgUHJvZHVjdEVkZ2UgPSBfRWRnZTxQcm9kdWN0Pgp0eXBlIFByb2R1Y3RDb25uZWN0aW9uID0gX0Nvbm5lY3Rpb248UHJvZHVjdEVkZ2U%2BCnR5cGUgVXNlckVkZ2UgPSBfRWRnZTxVc2VyPgp0eXBlIFVzZXJDb25uZWN0aW9uID0gX0Nvbm5lY3Rpb248VXNlckVkZ2U%2B"&gt;Try it in the GraphQXL explorer!&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Note that the documentation for the Edges and the Connections is also autogenerated following the templating rules in the source GraphQXL file.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Import statements
&lt;/h3&gt;

&lt;p&gt;There are different ways and tools developers can use to split a GraphQL schema into multiple files and merge them afterwards, but GraphQXL provides its own: import statements.&lt;/p&gt;

&lt;p&gt;The behavior is pretty straightforward and predictable, given this file &lt;code&gt;common-stuff.graphqxl&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Identifier&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It can be imported and reused into other &lt;code&gt;.graphqxl&lt;/code&gt; files:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source GraphQXL&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="err"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;"common-stuff"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Identifier&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Compiled GraphQL&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Identifier&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Identifier&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A good usage of this feature could end up in a final &lt;code&gt;.graphqxl&lt;/code&gt; that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="err"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;"products"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;"users"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;"subscriptions"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;# import other entities&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="n"&gt;_ProductsQuery&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="n"&gt;_UsersQuery&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="n"&gt;_SubscriptionsQuer&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="c"&gt;# queries for the other entities&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Mutation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="n"&gt;_ProductsMutation&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="n"&gt;_UsersMutation&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="n"&gt;_SubscriptionsMutation&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="c"&gt;# mutations for the other entities&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;schema&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;mutation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Mutation&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Is there more?
&lt;/h2&gt;

&lt;p&gt;There is a lot more! Feel free to&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check out &lt;a href="https://www.propeldata.com/"&gt;Propel&lt;/a&gt; if you want to try what we have built in Propel,&lt;/li&gt;
&lt;li&gt;Stop by the GraphQXL’s source repository &lt;a href="https://github.com/gabotechs/graphqxl"&gt;https://github.com/gabotechs/graphqxl&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;Play around in the GraphQXL explorer &lt;a href="https://graphqxl-explorer.vercel.app/"&gt;https://graphqxl-explorer.vercel.app&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;or Read the GraphQXL book &lt;a href="https://gabotechs.github.io/graphqxl/"&gt;https://gabotechs.github.io/graphqxl&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>graphql</category>
      <category>api</category>
      <category>typescript</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Dep Tree - a tool for rendering and linting your project's dependency tree in the terminal</title>
      <dc:creator>Gabriel</dc:creator>
      <pubDate>Tue, 21 Feb 2023 17:45:55 +0000</pubDate>
      <link>https://dev.to/gabotechs/dep-tree-a-tool-for-rendering-and-linting-your-projects-dependency-tree-in-the-terminal-25om</link>
      <guid>https://dev.to/gabotechs/dep-tree-a-tool-for-rendering-and-linting-your-projects-dependency-tree-in-the-terminal-25om</guid>
      <description>&lt;h2&gt;
  
  
  Dep Tree
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/gabotechs/dep-tree" rel="noopener noreferrer"&gt;https://github.com/gabotechs/dep-tree&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Coding is a team sport, and team members should agree on conventions and strategies for taking projects across the line.&lt;/p&gt;

&lt;p&gt;For example, team members may agree on a specific code style, and configure linters for enforcing it, that way no one can’t get their code merged without first be compliant with the styling rules.&lt;/p&gt;

&lt;p&gt;Team members could also choose to agree on strategies for managing dependencies, something like “files in folder X” should never depend on “anything under folder Y”. A clean dependency management is crucial for a project’s maintainability and scalability in the long term, but there is not that many tools for enforcing dependency higiene as there is for code style higiene.&lt;/p&gt;

&lt;p&gt;Dep Tree aims to solve this, not only by allowing developers to visualize in an interactive way their project’s dependency tree, but also by providing a tool for enforcing some user-defined dependency rules. Something like a linter, but for dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dependency tree visualization
&lt;/h2&gt;

&lt;p&gt;The first step for knowing how messy a project is, is by graphically visualizing it. Dep Tree allows rendering an interactive dependency tree in the terminal, which is super useful for understanding what pieces of a project depend on what, and what other things are correctly decoupled.&lt;/p&gt;

&lt;p&gt;Take this project of mine as an example: &lt;a href="https://github.com/gabotechs/react-gcode-viewer" rel="noopener noreferrer"&gt;https://github.com/gabotechs/react-gcode-viewer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That project is just a very simple React component library, and as usually, it has an entrypoint in &lt;code&gt;src/index.ts&lt;/code&gt;. A very important thing to note, is that there is always an entrypoint, either the &lt;code&gt;index&lt;/code&gt; file used for exposing a library, or the executable file with the program’s main function.&lt;/p&gt;

&lt;p&gt;Running &lt;code&gt;dep-tree render src/index.ts&lt;/code&gt; under that project’s root folder will render something like this in the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;index.ts                                                                        
│                                                                               
└▷GCodeViewer/GCodeViewer.tsx                                                   
  │                                                                             
  ├▷GCodeViewer/GCodeModel.tsx                                                  
  └▷│GCodeViewer/gcode/reader/UrlReader.ts                                      
    ││                                                                          
    ├│▷GCodeViewer/GCodeLines.tsx                                               
    ├│▷│GCodeViewer/SceneElements/Camera.tsx                                    
    ├│▷│GCodeViewer/SceneElements/Floor.tsx                                     
    ├│▷│GCodeViewer/SceneElements/OrbitControls.tsx                             
    ├│▷│GCodeViewer/gcode/GCode.ts                                              
    │└▷││GCodeViewer/gcode/reader/base.ts                                       
    │  ││                                                                       
    │  │├─▷GCodeViewer/gcode/parser.ts                                          
    │  ││  │                                                                    
    └──┴┴──┴▷GCodeViewer/gcode/types.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 Dep Tree does not check third-party dependencies, it will only take into account the source code of the project, ignoring any dependency to a external library.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is just copy-pasted from a terminal, but the truth is that users can navigate through the entries using the keyboard, and select specific entries for rendering their isolated dependency trees.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa2gzi39g0kz1sl4wfv2x.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa2gzi39g0kz1sl4wfv2x.gif" alt="Demo Gif" width="600" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Dependency rules check
&lt;/h2&gt;

&lt;p&gt;Once users are already aware of how messy their project’s dependencies are, they may choose to fix it and enforce some dependency rules. In the same way that developers configure linters for checking that new code matches the expected style, they can define rules to ensure that new code does not introduce dependencies between parts of the application that are meant to be decoupled.&lt;/p&gt;

&lt;p&gt;In Dep Tree, this rules are defined in a &lt;code&gt;.dep-tree.yml&lt;/code&gt; file in the root of the project with the following structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;entrypoints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;src/index.ts&lt;/span&gt;
&lt;span class="na"&gt;allow&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;this-folder-can-only-depend-on.../**"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;this/*.ts"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;and-this/*.ts"&lt;/span&gt;
&lt;span class="na"&gt;deny&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;this-one-cannot-depend-on.../**"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;not-this/*.ts"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;neither-this/*.ts"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some real life examples:&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚛ React &lt;code&gt;pages&lt;/code&gt; and &lt;code&gt;components&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Imagine a React application, with a &lt;code&gt;pages&lt;/code&gt; folder and a &lt;code&gt;components&lt;/code&gt; folder. Probably, files under &lt;code&gt;pages&lt;/code&gt; will use the reusable components defined in &lt;code&gt;components&lt;/code&gt; for building whole pages, but &lt;code&gt;components&lt;/code&gt; are just isolated testable components that should not depend on page-specific details:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;entrypoints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;src/app.tsx&lt;/span&gt;
&lt;span class="na"&gt;deny&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/components/**/*.tsx"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/pages/**"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;running &lt;code&gt;dep-tree check&lt;/code&gt; with this &lt;code&gt;.dep-tree.yml&lt;/code&gt; file would fail if any &lt;code&gt;component&lt;/code&gt; tries to depend on something that lives under the &lt;code&gt;pages&lt;/code&gt; folder.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔧 The classic &lt;code&gt;utils&lt;/code&gt; folder
&lt;/h3&gt;

&lt;p&gt;Who hasn’t dealt with this? a project that starts being a small thing, with some innocent helper functions that are placed under a &lt;code&gt;utils&lt;/code&gt; folder. Then the project keeps growing, every new addition has its own “util” function or class, and because of the vague and generic meaning of the word “util”, everything can be considered a “util”. Some months later half of the project ends up living in a &lt;code&gt;utils&lt;/code&gt; folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;entrypoints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;src/main.ts&lt;/span&gt;
&lt;span class="na"&gt;allow&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/utils/**"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/utils/**"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This config will limit files under &lt;code&gt;src/utils&lt;/code&gt; to only import other files under &lt;code&gt;src/utils&lt;/code&gt;. That way a “util” can’t depend on parts of the application with business logic important for a specific functionality, developers are forced to colocate things that are designed for functionality X under the folder designed for functionality X, and the &lt;code&gt;utils&lt;/code&gt; folder is left just for some generic and basic helper functions.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔄 Dependency inversion
&lt;/h3&gt;

&lt;p&gt;Last letter of the SOLID principles and one of the most powerful tools in software development, but lets directly dive-in in a real world example:&lt;/p&gt;

&lt;p&gt;An application that is in charge of managing users, that uses MySQL as a database, will probably have some MySQL client code under &lt;code&gt;src/mysql-client&lt;/code&gt;, and some user management code under &lt;code&gt;src/users&lt;/code&gt;. As the application is using MySQL for persisting user information, then the code under &lt;code&gt;src/users&lt;/code&gt; will depend on &lt;code&gt;src/mysql-client&lt;/code&gt; for storing the users.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;src/users&lt;/code&gt; high level module is depending on the &lt;code&gt;src/mysql-client&lt;/code&gt; low level module, which has some serious impact in testability in isolation of infrastructure-specific details, or in other words, not needing a whole MySQL database running just for testing &lt;code&gt;src/users&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Dependency inversion can help here by breaking the dependency between both modules, putting an interface in between, and making &lt;code&gt;src/mysql-client&lt;/code&gt; depend on that interface. But explaining how dependency inversion work is out of the scope here, so let's see directly how Dep Tree can help here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;entrypoints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;src/main.ts&lt;/span&gt;
&lt;span class="na"&gt;deny&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/users/**"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/mysql-client/**"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will enforce the &lt;code&gt;src/users&lt;/code&gt; module to not depend on MySQL-specific details.&lt;/p&gt;

&lt;p&gt;Even better, if all the infrastructure-specific code is gathered under a &lt;code&gt;infra&lt;/code&gt; package, the dependency banning can go even further:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;entrypoints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;src/main.ts&lt;/span&gt;
&lt;span class="na"&gt;deny&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/users/**"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;infra/**"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Dep Tree aims to be another automated tool for helping in the maintainability of medium/large code bases. It helps to understand the dependency flow of an application and provides tools for validating it against the rules defined in a configuration file.&lt;/p&gt;

&lt;p&gt;If you find it helpful, feel free to stop by the source repository &lt;a href="https://github.com/gabotechs/dep-tree" rel="noopener noreferrer"&gt;https://github.com/gabotechs/dep-tree&lt;/a&gt; and give it a try, feedback is much appreciated!&lt;/p&gt;

</description>
      <category>iot</category>
      <category>distributedsystems</category>
      <category>database</category>
      <category>blockchain</category>
    </item>
  </channel>
</rss>
