<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: rasjonell</title>
    <description>The latest articles on Forem by rasjonell (@rasjonell).</description>
    <link>https://forem.com/rasjonell</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%2F53431%2F25da7711-8ea4-4d3e-a1a1-1bdbf553af61.jpg</url>
      <title>Forem: rasjonell</title>
      <link>https://forem.com/rasjonell</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/rasjonell"/>
    <language>en</language>
    <item>
      <title>DynamoDB Workflows: stop rewriting incident scripts (with DynamoLens)</title>
      <dc:creator>rasjonell</dc:creator>
      <pubDate>Mon, 26 Jan 2026 23:38:11 +0000</pubDate>
      <link>https://forem.com/rasjonell/dynamodb-workflows-stop-rewriting-incident-scripts-with-dynamolens-26oe</link>
      <guid>https://forem.com/rasjonell/dynamodb-workflows-stop-rewriting-incident-scripts-with-dynamolens-26oe</guid>
      <description>&lt;p&gt;If you use DynamoDB on a real product, you probably have a hidden folder somewhere: incident scripts, debug scripts, one-off migrations, quick backfills.                                                                                                                            &lt;/p&gt;

&lt;p&gt;It starts innocently:&lt;/p&gt;

&lt;p&gt;You need to fetch a user by email, then find their recent orders, then look up a handful of related items. You run a Query, copy a key, paste it into another query, repeat… and eventually you give up and write a script.&lt;/p&gt;

&lt;p&gt;The next time the same incident happens, you copy that script, tweak it, and hope you didn’t mix up Dev and Prod.                           &lt;/p&gt;

&lt;p&gt;&lt;em&gt;That’s the DynamoDB script tax.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What “Workflows” are (in DynamoLens)
&lt;/h2&gt;

&lt;p&gt;DynamoLens is a free, open-source desktop client for DynamoDB (macOS / Windows / Linux).&lt;/p&gt;

&lt;p&gt;Its core feature is Workflows: a way to turn repeatable DynamoDB operations into a first‑class object&lt;/p&gt;

&lt;p&gt;you can:                              &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;build once (Query / Scan / PartiQL steps)
&lt;/li&gt;
&lt;li&gt;chain steps together (values flow forward automatically)
&lt;/li&gt;
&lt;li&gt;save and re-run without rewriting anything
&lt;/li&gt;
&lt;li&gt;export/import to share with teammates
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of it as moving “incident scripts” from a private folder into a visible, repeatable, shareable UI.                                    &lt;/p&gt;

&lt;p&gt;&lt;em&gt;The real win: sharing&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Dev tools spread when they become team habits. Workflows are designed to be shared:                                                         &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The person who debugs a nasty issue can turn the investigation into a workflow and hand it to the next on-call.
&lt;/li&gt;
&lt;li&gt;A backend team can standardize “safe” patterns (Query-first, guarded Scans) as reusable workflows.
&lt;/li&gt;
&lt;li&gt;Local dev flows can be reused in staging and production without rewriting.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example: “User → Orders → Order Items” without copy/paste                                                                                   &lt;/p&gt;

&lt;p&gt;A common DynamoDB debugging pattern is a chain of lookups. In a workflow you can:                                                           &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Query the Users table by email
&lt;/li&gt;
&lt;li&gt;Extract the userId from the result
&lt;/li&gt;
&lt;li&gt;Query the Orders table using that userId
&lt;/li&gt;
&lt;li&gt;Extract an orderId
&lt;/li&gt;
&lt;li&gt;Fetch related items
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The point isn’t that this is impossible with scripts, it’s that it becomes repeatable and shareable without constantly re-implementing the same glue.                                                                                                                                  &lt;/p&gt;

&lt;p&gt;Safety: fewer surprises                                                                                                                     &lt;/p&gt;

&lt;p&gt;DynamoDB is powerful, but it’s easy to do expensive or dangerous things accidentally (especially with Scans). DynamoLens makes the&lt;br&gt;&lt;br&gt;
 operation mode explicit and keeps environment context visible.                                                                              &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Try it&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you want to stop paying the script tax, start with one workflow you run repeatedly. When it saves you time, share it with your team.     &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Blog version: &lt;a href="https://dynamolens.com/blog/dynamodb-workflows-stop-rewriting-incident-scripts" rel="noopener noreferrer"&gt;https://dynamolens.com/blog/dynamodb-workflows-stop-rewriting-incident-scripts&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Download: &lt;a href="https://dynamolens.com/download" rel="noopener noreferrer"&gt;https://dynamolens.com/download&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/rasjonell/dynamo-lens" rel="noopener noreferrer"&gt;https://github.com/rasjonell/dynamo-lens&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>dynamodb</category>
      <category>devtools</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Adding RSS Feed To Serum Static Site Generator</title>
      <dc:creator>rasjonell</dc:creator>
      <pubDate>Wed, 08 Jul 2020 15:33:45 +0000</pubDate>
      <link>https://forem.com/rasjonell/adding-rss-feed-to-serum-static-site-generator-3fi4</link>
      <guid>https://forem.com/rasjonell/adding-rss-feed-to-serum-static-site-generator-3fi4</guid>
      <description>&lt;p&gt;About 4 minutes to read&lt;/p&gt;



&lt;ul id="toc"&gt;

&lt;li&gt;
&lt;span&gt;1 &lt;/span&gt;Creating The Plugin&lt;/li&gt;

&lt;li&gt;
&lt;span&gt;1.1 &lt;/span&gt;Serum.Plugin&lt;/li&gt;

&lt;li&gt;
&lt;span&gt;1.2 &lt;/span&gt;Channels&lt;/li&gt;

&lt;li&gt;
&lt;span&gt;1.3 &lt;/span&gt;Items&lt;/li&gt;

&lt;li&gt;
&lt;span&gt;1.4 &lt;/span&gt;Build Succeeded&lt;/li&gt;

&lt;/ul&gt;

&lt;h2 id="creating-the-plugin"&gt;Creating The Plugin&lt;/h2&gt;

&lt;p&gt;I decided not to talk about the importance, simplicity, and necessity of having an RSS feed for your website. So I’m just going to demonstrate how I made a plugin for &lt;a href="https://github.com/Dalgona/Serum"&gt;Serum&lt;/a&gt;, the static site generator tool(written in Elixir), that I use for this blog.&lt;/p&gt;

&lt;p&gt;Serum has a plugin system. For example the Table Of Contents at the top of the article was generated with a plugin. They have a Plugin &lt;a href="https://elixir-lang.org/getting-started/typespecs-and-behaviours.html#behaviours"&gt;Behaviour&lt;/a&gt; which you can use to define your own plugin module.&lt;/p&gt;

&lt;h3 id="serum.plugin"&gt;Serum.Plugin&lt;/h3&gt;

&lt;p&gt;Serum exposes a number of events(full list can be found &lt;a href="https://hexdocs.pm/serum/Serum.Plugin.html#content"&gt;here&lt;/a&gt;) which you can handle. The one I find most useful for the RSS feed generator is &lt;code&gt;build_succeeded/3&lt;/code&gt;. This particular event is triggered when, as the name suggests, the build step succeeds. After a successful build we want to update our RSS feed so the subscribers can get notified about new posts!&lt;/p&gt;

&lt;p&gt;First we need some boilerplate to correctly implement the &lt;code&gt;Serum.Plugin&lt;/code&gt; behavour.&lt;/p&gt;

&lt;pre class="highlight elixir"&gt;&lt;code&gt;defmodule Blog.Rss do
  @moduledoc """
  A Serum plugin that create an RSS feed.

  ## Using the Plugin

      # serum.exs:
      %{
        server_root: "https://example.io",
        plugins: [
          Rss
        ]
      }
  """

  @behaviour Serum.Plugin

  @title "Rasjonell's Blog"
  @url "https://www.rasjonell.tech"
  @blog_desc "Random rants about technology"

  @impl true
  def name, do: "RSS Feed Generator"

  @impl true
  def version, do: "0.1.0"

  @impl true
  def elixir, do: "&amp;gt;= 1.7.0"

  @impl true
  def serum, do: "&amp;gt;= 1.2.0"

  @impl true
  def description do
    "Generates an RSS feed for /posts"
  end

  @impl true
  def implements do
    [build_succeeded: 3]
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;Here apart from the necessary function implementations, I’ve also defined some module attributes such as title and description which will be used latter for generating the RSS feed.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now that we have our module defined we can start thinking about how we should generate the feed.&lt;/p&gt;

&lt;p&gt;RSS, as the name suggests, is really simple.
It’s an XML file so we should start with: &lt;code&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/code&gt;.
Then we need to wrap all of our feed in an &lt;code&gt;rss&lt;/code&gt; tag like so: &lt;code&gt;&amp;lt;rss version="2.0"&amp;gt;&amp;lt;/rss&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;So what are the things that need to be wrapped.&lt;/p&gt;

&lt;h3 id="channels"&gt;Channels&lt;/h3&gt;

&lt;p&gt;Remember the module attributes? We need them to define our channel.
We can define a simple function that returns all the necessary tags with up-to-date information.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;defp channel do
  """
    &amp;lt;title&amp;gt;#{@title}&amp;lt;/title&amp;gt;
    &amp;lt;link&amp;gt;#{@url}&amp;lt;/link&amp;gt;
    &amp;lt;description&amp;gt;#{@blog_desc}&amp;lt;/description&amp;gt;
    &amp;lt;lastBuildDate&amp;gt;#{current_date()}&amp;lt;/lastBuildDate&amp;gt;
    &amp;lt;language&amp;gt;en-us&amp;lt;/language&amp;gt;
  """
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;See the call to &lt;code&gt;current_date/0&lt;/code&gt; there? This was the most painful part of developing this plugin. RSS requires dates in the RFC-822 format but Elixir’s date-related modules, understandably, don’t come with built-in formatting options. So I had to install a dependancy. Timex is the library I chose, as it also is a dependancy of Serum, so I wouldn’t add any more code to the final bundle.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;current_date/0&lt;/code&gt; function has this definition:&lt;/p&gt;

&lt;pre&gt;&lt;code class="elixir"&gt;defp current_date do
  {:ok, current_date} = Timex.now
    |&amp;gt; Timex.format("{RFC822}")
  
  current_date
end&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="items"&gt;Items&lt;/h3&gt;

&lt;p&gt;Now that we have defined our channel description, it’s time we add some items.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;defp item(title, desc, link) do
  """
  &amp;lt;item&amp;gt;
    &amp;lt;title&amp;gt;#{title}&amp;lt;/title&amp;gt;
    &amp;lt;description&amp;gt;&amp;lt;![CDATA[#{desc}]]&amp;gt;&amp;lt;/description&amp;gt;
    &amp;lt;pubDate&amp;gt;#{current_date()}&amp;lt;/pubDate&amp;gt;
    &amp;lt;link&amp;gt;#{link}&amp;lt;/link&amp;gt;
    &amp;lt;guid&amp;gt;#{link}&amp;lt;/guid&amp;gt;
  &amp;lt;/item&amp;gt;
  """
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we can just glue all of these together to generate a feed:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;defp feed(channel, items) do
  """
  &amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;
  &amp;lt;rss version="2.0"&amp;gt;
  &amp;lt;channel&amp;gt;
    #{channel}
    #{Enum.join items, ""}
  &amp;lt;/channel&amp;gt;
  &amp;lt;/rss&amp;gt;
  """
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This pretty much gives us all the building blocks that we need to complete this plugin by reading the posts, generating a feed, and writing it to a file accessable publicly on our website.&lt;/p&gt;

&lt;h3 id="build-succeeded"&gt;Build Succeeded&lt;/h3&gt;

&lt;p&gt;To handle the &lt;code&gt;build_succeeded/3&lt;/code&gt; event we need to implement that behavour:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@impl true
def build_succeeded(_src, dest, _args) do
  :all_posts
  |&amp;gt; Serum.GlobalBindings.get()
  |&amp;gt; build_feed(dest)
  |&amp;gt; create_file(dest)
  |&amp;gt; File.write()

  :ok
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I’ll let Elixirs &lt;strong&gt;beautiful&lt;/strong&gt; pipe operator do the explaining here.&lt;/p&gt;

&lt;p&gt;If you want to use this plugin or just check the final code checkout the &lt;a href="https://github.com/rasjonell/rasjonell.github.io/blob/master/lib/blog/rss.ex"&gt;source code&lt;/a&gt;.&lt;/p&gt;



</description>
    </item>
    <item>
      <title>Using AWK To Process Huge CSV Files</title>
      <dc:creator>rasjonell</dc:creator>
      <pubDate>Wed, 08 Jul 2020 15:33:45 +0000</pubDate>
      <link>https://forem.com/rasjonell/using-awk-to-process-huge-csv-files-1n3d</link>
      <guid>https://forem.com/rasjonell/using-awk-to-process-huge-csv-files-1n3d</guid>
      <description>&lt;ul id="toc"&gt;

&lt;li&gt;
&lt;span&gt;1 &lt;/span&gt;Problem&lt;/li&gt;

&lt;li&gt;
&lt;span&gt;2 &lt;/span&gt;Approach&lt;/li&gt;

&lt;li&gt;
&lt;span&gt;3 &lt;/span&gt;Solution&lt;/li&gt;

&lt;li&gt;
&lt;span&gt;4 &lt;/span&gt;Conclusion&lt;/li&gt;

&lt;/ul&gt;

&lt;h2 id="problem"&gt;Problem&lt;/h2&gt;

&lt;p&gt;I had 38 separate &lt;code&gt;.csv&lt;/code&gt; files each consisted of at least 40K lines of data. Overall there were ≥ 2.6 million rows of information. The problem was that the data was not in the ideal form.&lt;/p&gt;

&lt;p&gt;Each file had 5 columns. One of the columns was called &lt;em&gt;birthday&lt;/em&gt;. It had a conventional(at least for the most of the world) format: &lt;code&gt;DD/MM/YYYY&lt;/code&gt;. However I was going to put this data in a DB(more on that later!) and I needed to have 3 separate properties(ie. &lt;code&gt;{ day: DD, month: MM, year: YYYY }&lt;/code&gt;). Also there were some columns that were not useful so I had to get rid of them. In addition, I also wanted to reduce the number of files to one.&lt;/p&gt;

&lt;h2 id="approach"&gt;Approach&lt;/h2&gt;

&lt;p&gt;I know some python and from a couple of data science courses I was introduced to &lt;a href="https://pandas.pydata.org/"&gt;Pandas&lt;/a&gt;, a well-known tool for data analysis built on top of python. It had a straightforward way of reading, manipulating, and writing csv files. I was going to use that, but didn’t really want to download this tool to use only one of the features and never use it again. So I choose something that comes with nearly all modern unix-like systems. &lt;a href="https://en.wikipedia.org/wiki/AWK"&gt;AWK&lt;/a&gt; is &lt;em&gt;designed&lt;/em&gt; for text processing and much like other programs in the unix-like world it does one thing well and produces fascinating results in regards to simplicity and performance when composed with other unix tools.&lt;/p&gt;

&lt;h2 id="solution"&gt;Solution&lt;/h2&gt;

&lt;p&gt;Now we need to make AWK process &lt;code&gt;.csv&lt;/code&gt; files.
AWK uses &lt;em&gt;field separators&lt;/em&gt; to split an input into fields. It may either be a character or a RegExp.
So all we need to do to make AWK become a &lt;code&gt;.csv&lt;/code&gt; processor is to set FS(field separator) to be &lt;code&gt;","&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can achieve this using AWK’s &lt;a href="https://www.gnu.org/software/gawk/manual/html_node/Using-BEGIN_002fEND.html#Using-BEGIN_002fEND"&gt;Startup and Cleanup Actions&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# clean_csv.awk

BEGIN {
  FS = ","
}
{
  print $1
}
END {
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then if we pass an input such as &lt;code&gt;one, two, three&lt;/code&gt; to the script, it will print &lt;code&gt;one&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ echo "one, two, three" | awk -f csv.awk

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

&lt;p&gt;Now that we have this, we can finally solve our problems: splitting &lt;code&gt;DD/MM/YYYY&lt;/code&gt; column into three separate columns and removing the useless column.
AWK has a &lt;code&gt;split&lt;/code&gt; function that takes a field, a new variable, and a separator and puts the separated values into the new variable.&lt;/p&gt;

&lt;p&gt;The birthday column was #3 so to create the separate fields we need to make the following modifications:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# clean_csv.awk

BEGIN {
  FS = ","
}
{
  # split DD/MM/YYY into an array of values
  split($4, dob, "/")

  # turn these values into separate columns
  total = dob[1] "," dob[2] "," dob[3]

  # finalize the row, omitting the useless #4 column.
  row = $1 "," $2 "," total "," $5

  print row
}
END {
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This mainly solves most of our problems, except for the first row of the input. &lt;code&gt;.csv&lt;/code&gt; files have headers as a set of labels on the first row, thus we need to skip every first line of every &lt;code&gt;.csv&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;In AWK &lt;code&gt;NR&lt;/code&gt; and &lt;code&gt;FNR&lt;/code&gt; represent the record number. The latter shows the record number of the current file, while the first holds the total count. Since we are going to use this script on more then one file, we’ll stick with &lt;code&gt;FNR&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So the final script looks like so:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# clean_csv.awk

BEGIN {
  FS = ","

  # create a new header with correct labels
  print "last_name,first_name,birth_day,birth_month,birth_year,country"
}
{
  if (FNR &amp;gt; 1) { # omit every first line
    # split DD/MM/YYY into an array of values
    split($4, dob, "/")

    # turn these values into separate columns
    total = dob[1] "," dob[2] "," dob[3]

    # finalize the row, omitting the useless #4 column.
    row = $1 "," $2 "," total "," $5

    print row
  }
}
END {
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;At last, to execute this on our 38 &lt;code&gt;.csv&lt;/code&gt; files we need to run this command:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;awk -f clean_csv *.csv &amp;gt; clean.csv&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;We read and manipulated over 30 &lt;code&gt;.csv&lt;/code&gt; files with more than 2.6 million rows of data combined and reduced them into a single clean file without installing any software. So if you’re faced with a problem, you may not need to install a bloated software to solve it when the solution comes pre-installed with your system.&lt;/p&gt;



</description>
      <category>awk</category>
      <category>shell</category>
    </item>
    <item>
      <title>Separate Data Access Layer With TypeScript Powered MicroServices</title>
      <dc:creator>rasjonell</dc:creator>
      <pubDate>Mon, 03 Feb 2020 09:05:00 +0000</pubDate>
      <link>https://forem.com/rasjonell/separate-data-access-layer-with-typescript-powered-microservices-3hbj</link>
      <guid>https://forem.com/rasjonell/separate-data-access-layer-with-typescript-powered-microservices-3hbj</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://arangodb.com"&gt;ArangoDB&lt;/a&gt; is a multi-model database supporting Key/Value, Document, and Graph models with one unifying query language.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.arangodb.com/docs/stable/foxx.html"&gt;Foxx Microservices&lt;/a&gt; are Arango's way of writing separate data access and domain logic code running directly within the database with native access to in-memory data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/SquashConsulting/foxx_typescript"&gt;Foxx TypeScript&lt;/a&gt; is an &lt;a href="https://arangodb.com"&gt;ArangoDB&lt;/a&gt; Foxx service template that lets you write testable, typescript powered microservices.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/rasjonell/foxx_ts_demo"&gt;foxx_ts_demo&lt;/a&gt; is the source code of the tutorial in this article.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Graph Databases
&lt;/h2&gt;

&lt;p&gt;Graph databases caught my interest and I've been experimenting with them for a couple of months now. This a very broad topic that does not really belong to this article so I'm just going to demonstrate why I choose to work with this model with a couple of key points:&lt;/p&gt;

&lt;h3&gt;
  
  
  Better Mental Modeling
&lt;/h3&gt;

&lt;p&gt;As an example let’s think about a basic social media interaction. At the core all we need is &lt;code&gt;user follows user&lt;/code&gt;. With traditional "relational" databases you'd need to create a through table that holds foreign-keys to represent this many-to-many relationship. This itself is already unnecessarily complicated, but what if we introduce posts, reactions, etc. In order to fetch posts only from users that the current user follows you'd need to do expensive multiple joins and possibly sub-queries.&lt;/p&gt;

&lt;p&gt;However with graphs it is as simple as stating the relationship.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3T0qiuna--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/u6nanwy7aokgvlestxig.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3T0qiuna--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/u6nanwy7aokgvlestxig.png" alt="Graph representation of user follows user relationship"&gt;&lt;/a&gt;&lt;br&gt;
This image is the actual representation of this relationship. Having this simplicity is essential both for modeling your business logic and communicating it across different teams in your company.&lt;/p&gt;
&lt;h3&gt;
  
  
  Graph Algorithms
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://en.m.wikipedia.org/wiki/Graph_theory"&gt;Graph Theory&lt;/a&gt; is the study of graphs. There are a number of well-known algorithms and techniques that help us conduct efficient data analysis and enable us to create personalized suggestions.&lt;br&gt;
This example from &lt;a href="https://aws.amazon.com/neptune/"&gt;Amazon Neptune&lt;/a&gt; shows how having your data model in such form makes it really intuitive and straightforward to generate suggestions and make your platform more personalized.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pEpx69vn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7twk7pgpgrx8lw9gwkuz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pEpx69vn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7twk7pgpgrx8lw9gwkuz.png" alt="Graph model representing personalized suggestions"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Separate Data Access Layer (DAL)
&lt;/h2&gt;

&lt;p&gt;For projects that are relatively big and/or heavily data-reliant it makes sense to separate your Data Access Layer(DAL) from your API. It is also widely accepted to have a separate Business Logic Layer(BLL).&lt;/p&gt;

&lt;p&gt;ArangoDB is a relatively new database and is being rapidly developed. Recently it was &lt;a href="https://www.g2.com/categories/graph-databases?utm_campaign=G2Crowd%20Reviews&amp;amp;utm_content=107517797&amp;amp;utm_medium=social&amp;amp;utm_source=twitter&amp;amp;hss_channel=tw-398200139"&gt;communally voted&lt;/a&gt; as the number 1 graph database. Currently there are not many ORMs(or OGMs) supporting Arango. Because of this I tried finding the right way of accessing my data layer. This is when I came across Foxx Microservices.&lt;/p&gt;

&lt;p&gt;Foxx Microservices are Arango's way of writing separate data access and domain logic code running directly within the database with native access to in-memory data.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Foxx services consist of JavaScript code running in the V8 JavaScript runtime embedded inside ArangoDB. Each service is mounted in each available V8 context (the number of contexts can be adjusted in the server configuration). Incoming requests are distributed across these contexts automatically.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Essentially ArangoDB offers a REST API to communicate with the database. So what ORMs(or OGMs) do is introduce an abstraction over these APIs to be used in your client. Foxx Microservices can be used to extend this API. Your Business Logic Layer then can directly call the extended database API instead of a separate service that does not have direct access to the database. Thus, using Foxx as your DAL not only offers modularity and long-term maintainability but also ensures the best possible performance.&lt;/p&gt;
&lt;h2&gt;
  
  
  Our First TypeScript Foxx Microservice
&lt;/h2&gt;

&lt;p&gt;We've created an ArangoDB 🥑 Foxx Microservice template supporting TypeScript and Yarn &amp;gt;= 2.0. Navigate to this link &lt;a href="https://github.com/SquashConsulting/foxx_typescript/generate"&gt;https://github.com/SquashConsulting/foxx_typescript/generate&lt;/a&gt; to generate your first Foxx Microservice with our TypeScript template.&lt;/p&gt;

&lt;p&gt;In order to follow the rest of the article make sure you have arangodb running locally and have &lt;a href="https://github.com/arangodb/foxx-cli"&gt;foxx-cli&lt;/a&gt; set up.&lt;/p&gt;
&lt;h3&gt;
  
  
  Project Structure
&lt;/h3&gt;


&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── LICENSE
├── README.md
├── manifest.json
├── package.json
├── src
│   ├── entry.ts
|   └── scripts
│       ├── setup.ts
│   └── routes
│       ├── hello.ts
│       └── index.ts
├── test
├── tsconfig.json
└── yarn.lock
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;If you have your foxx-cli installed and set up, then in order to use the typescript service in ArangoDB, you need to run &lt;code&gt;yarn build&lt;/code&gt; and then do &lt;code&gt;foxx install &amp;lt;mount&amp;gt; --server &amp;lt;server_name&amp;gt; --database &amp;lt;db_name&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;NOTE: *&lt;/em&gt; &lt;em&gt;this template uses yarn &amp;gt;= 2.0, so please make sure you go through the instructions in the template README to complete your setup.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This will extend your database API by adding a &lt;code&gt;/hello&lt;/code&gt; route that simply returns hello world.&lt;/p&gt;
&lt;h3&gt;
  
  
  Setting Up The Service
&lt;/h3&gt;

&lt;p&gt;The template project comes with &lt;code&gt;@types/arangodb&lt;/code&gt; package. So you can already use them in your project.&lt;/p&gt;

&lt;p&gt;Let's write another route that inserts user data in the database.&lt;/p&gt;

&lt;p&gt;First of all we need to create a setup script that creates the necessary collections for us.&lt;/p&gt;

&lt;p&gt;inside &lt;code&gt;src/scripts/setup.ts&lt;/code&gt; write this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@arangodb&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;documents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nx"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_createDocumentCollection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isProduction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`collection &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; already exists. Leaving it untouched.`&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then update your &lt;code&gt;manifest.json&lt;/code&gt; to run this script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&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;*/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"setup"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dist/scripts/setup.js"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&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;/*&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;*/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Notice how we use dist instead of src to tell aranago to run the bundled commonjs code instead of typescript.&lt;/p&gt;

&lt;p&gt;After this you can finally install your service using &lt;code&gt;foxx-cli&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;yarn build
...

&lt;span class="nv"&gt;$ &lt;/span&gt;foxx &lt;span class="nb"&gt;install&lt;/span&gt; /foxx_ts_demo &lt;span class="nt"&gt;--server&lt;/span&gt; squash &lt;span class="nt"&gt;--database&lt;/span&gt; squash

Installed service at &lt;span class="s2"&gt;"/foxx_ts_demo"&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Notice that I installed the service on &lt;code&gt;/foxx_ts_demo&lt;/code&gt; using the server &lt;code&gt;squash&lt;/code&gt; and the homonym database that I configured using the &lt;code&gt;foxx-cli&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now if you navigate to ArangoDB's WebView(default is &lt;a href="http://localhost:8529"&gt;http://localhost:8529&lt;/a&gt;) choose the database you configured you will see &lt;code&gt;users&lt;/code&gt; collection.&lt;/p&gt;

&lt;p&gt;This happened because &lt;code&gt;setup&lt;/code&gt; is one of Foxx lifecycle scripts. For more info refer to the &lt;a href="https://www.arangodb.com/docs/3.7/foxx-guides-scripts.html#lifecycle-scripts"&gt;official docs&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating A Custom Route
&lt;/h3&gt;

&lt;p&gt;Now that we have everything set up, we can move forward and create our first ever typescript API!&lt;/p&gt;

&lt;p&gt;You can see the example route in &lt;code&gt;src/routes/hello.ts&lt;/code&gt;.&lt;br&gt;
Before we extend this with a POST request that creates a user, let's update our setup script to add unique index on the &lt;code&gt;username&lt;/code&gt; field.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/scripts/setup.ts&lt;/span&gt;
&lt;span class="cm"&gt;/* ... */&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ArangoDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ensureIndex&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;unique&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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hash&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;fields&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="s2"&gt;username&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now we can add the route:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/routes/hello.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;joi&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;joi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@arangodb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IUser&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;ArangoDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Document&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;email&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;username&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;router&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Foxx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&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;Foxx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&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="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ArangoDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt; &lt;span class="p"&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;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Failed to save the user&lt;/span&gt;
      &lt;span class="c1"&gt;// We'll assume the uniqueness constraint has been violated&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;throw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bad request&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="s2"&gt;Username already taken&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&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="nx"&gt;joi&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User Info&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="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Creates a new user.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The combination of TypeScript and joi validations makes this code pretty self-explanatory. We take the user data from the request save it in the collection and return it with additional data.&lt;/p&gt;

&lt;p&gt;If you navigate to Arango WebView's Services tab you will see your service. Click on the service. There are three main sections:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Info - Your README.md file.&lt;/li&gt;
&lt;li&gt;API - We used joi to define our APIs this helps Arango to generate &lt;a href="https://swagger.io/"&gt;Swagger&lt;/a&gt; API definitions for us.&lt;/li&gt;
&lt;li&gt;Settings - Your service configurations(Will talk about this later)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now If you go the the API tab, you will see the newly created &lt;code&gt;POST /user&lt;/code&gt; API, expanding it will reveal the API options with an additional option to try the API directly from the web view.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QuAEP4ot--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/69r63hrgnbkjvan5fb2s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QuAEP4ot--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/69r63hrgnbkjvan5fb2s.png" alt="Screenshot of ArangoDB Services Web View"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Give it a try and create a user. After successfully creating the user, the API will respond with &lt;code&gt;200 OK&lt;/code&gt; and send the user data back. If you try to create a user with the same username the API should respond with &lt;code&gt;400 Bad Request&lt;/code&gt; and error massage that states that the username is already in use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;I hope I've succeeded in convincing you to give ArangoDB and Foxx Microservices a try. If you do so, you'll discover a lot more than I've managed to cover in this article. My favorite Foxx features are &lt;a href="https://www.arangodb.com/docs/3.7/foxx-guides-dependencies.html"&gt;Linking Services&lt;/a&gt; together and making them &lt;a href="https://www.arangodb.com/docs/3.7/foxx-reference-configuration.html"&gt;configurable&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can checkout &lt;a href="https://github.com/SquashConsulting/foxx_services"&gt;https://github.com/SquashConsulting/foxx_services&lt;/a&gt; to see how we used both of these(and other cool) features to create a separate Data Access Layer with &lt;a href="https://github.com/SquashConsulting/shared"&gt;shared&lt;/a&gt; utils where you can define your configurations and have all the other linked services be generic.&lt;/p&gt;

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

&lt;p&gt;To wrap things up, separating your Data Access Layer(DAL) from your Business Logic Layer(BLL) is a technique that results in maintainable and modular code-base. Using ArangoDB Foxx with Typescript and joi validations to accomplish this provides additional benefits such as configurable, performant, and type-safe microservices.&lt;/p&gt;

&lt;p&gt;If you liked this article consider following me on &lt;a href="https://%D5%A9%D5%B8%D6%82%D5%A9.%D5%B0%D5%A1%D5%B5/@gurgen"&gt;Mastodon&lt;/a&gt; or Twitter &lt;a href="https://twitter.com/iRasjonell"&gt;@irasjonell&lt;/a&gt; and maybe starring the repos used in this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/rasjonell/foxx_ts_demo"&gt;foxx_ts_demo&lt;/a&gt; - The source code of the tutorial in this article.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/SquashConsulting/foxx_typescript"&gt;Foxx TypeScript&lt;/a&gt; - The typescript template project&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/SquashConsulting/foxx_services"&gt;Foxx Services&lt;/a&gt; - Foxx services meta repo&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/arangodb/arangodb"&gt;ArangoDB&lt;/a&gt; - ArangoDB source code&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>database</category>
      <category>typescript</category>
      <category>microservices</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
