<?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: Agustin Navcevich</title>
    <description>The latest articles on DEV Community by Agustin Navcevich (@agusnavce).</description>
    <link>https://dev.to/agusnavce</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%2F52425%2F6dd6bd19-0daa-434c-9280-d92a6f235629.jpg</url>
      <title>DEV Community: Agustin Navcevich</title>
      <link>https://dev.to/agusnavce</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/agusnavce"/>
    <language>en</language>
    <item>
      <title>A quick overview of the implementation of a fast spelling correction algorithm</title>
      <dc:creator>Agustin Navcevich</dc:creator>
      <pubDate>Sun, 12 Apr 2020 22:46:48 +0000</pubDate>
      <link>https://dev.to/agusnavce/a-quick-overview-of-the-implementation-of-a-fast-spelling-correction-algorithm-4i77</link>
      <guid>https://dev.to/agusnavce/a-quick-overview-of-the-implementation-of-a-fast-spelling-correction-algorithm-4i77</guid>
      <description>&lt;p&gt;Spellcheckers and autocorrect can feel like magic. They’re at the core of everyday applications — our phones, office software, google search (you type in ‘incorect’ and google returns ‘Did you mean incorrect).&lt;/p&gt;

&lt;p&gt;So how does this magic happen? And how can we build our own?&lt;/p&gt;

&lt;p&gt;First let’s consider what a spellchecker does.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TLDR ;)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Implementation of the algorithm in my &lt;a href="https://github.com/agusnavce/ta"&gt;github repo&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Basics of Text Correction
&lt;/h3&gt;

&lt;p&gt;In a nutshell, a basic text correction has to have at least 3 components:&lt;/p&gt;

&lt;h4&gt;
  
  
  Candidate Model
&lt;/h4&gt;

&lt;p&gt;The candidate model produces a list of potential correct terms. Potential candidates are created by doing all possible permutations (add, substitute, transpose or remove a character) within a given &lt;em&gt;edit distance&lt;/em&gt; from the original word.&lt;/p&gt;

&lt;p&gt;This edit distance is basically the measure of how many operations (adding, substituting, transposing or deleting a character) is needed to convert one word into another.&lt;/p&gt;

&lt;p&gt;Though a lot of candidates will be produced at this point, not all of them are significant. The candidates must be tested against a corpus of current known terms.&lt;/p&gt;

&lt;h4&gt;
  
  
  Language Model
&lt;/h4&gt;

&lt;p&gt;The language model is essentially a corpus of known valid language words, and the frequency / probability of appearing these words. We can usually get a rough sample model from a vast amount of literature from text mining, and then come up with this model.&lt;/p&gt;

&lt;h4&gt;
  
  
  Selection Criteria
&lt;/h4&gt;

&lt;p&gt;The selection criteria is what we use to determine which is the “right” word to use as the revised version of the possible candidates we have found. Calculating a score based on the edit distance (the lower the better) and how much the word appears in our language model (the higher the better) will be a potential selection criterion and selecting the candidate word with the highest score.&lt;/p&gt;

&lt;h3&gt;
  
  
  — Let’s brake it down —
&lt;/h3&gt;

&lt;p&gt;So now that we know the basics about text correction lets focus in the most important part of these 3 to implement the spellcheker. The selecition criteria.&lt;/p&gt;

&lt;p&gt;There are a few different ways to pick candidates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The most simplistic approach is to measure the distance you have selected to edit between your term and the entire dictionary. The method, while effective, is extremely costly.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://en.wikipedia.org/wiki/Phonetic_algorithm"&gt;&lt;strong&gt;Phonetic algorithms&lt;/strong&gt;&lt;/a&gt; such as Soundex, Phonex or Metaphone. Such algorithms can transform any string into a short sequence allowing for the indexing of string by pronunciation. Both ‘H600’ will return ‘Hurry’ and ‘Hirry.’ You can easily identify phonetically related candidates by pre-processing the entire vocabulary and indexing it using phonetic code. Rapid on runtime but it just corrects phonetic errors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Computing a list of potential misspelling for your word&lt;/strong&gt; (insertion, omission, transposition or replacement) and matching it to your dictionary. Although this is better than the naive method, due to collection of misspellings increasing in size at a rate of 54 * length+25 it is very sluggish. For further detail see Peter Norvig’s excellent article about spell correction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Symmetric spelling correction&lt;/strong&gt; that takes up the previous idea and expands it by computing mispellings for both the dictionary and the incorrect terminology. This technique is both reliable and quick blazing but at the cost of considerable precomputing and disk space, and includes your dictionary’s frequency list.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Given all these options the one we have chosen to make the correction in our case is the last option. Let’s see what it’s about.&lt;/p&gt;

&lt;h3&gt;
  
  
  SymSpell
&lt;/h3&gt;

&lt;p&gt;SymsSpell is an algorithm for finding all strings in very short time within a fixed edit distance from a large list of strings. SymSpell derives its speed from the &lt;strong&gt;Symmetric Delete spelling correction algorithm&lt;/strong&gt; and keeps its memory requirement in check by &lt;strong&gt;prefix indexing&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Symmetric Delete spelling correction algorithm&lt;/strong&gt; reduces the difficulty of the generation of edit candidates and the dictionary quest for the difference in distance. It is six orders of magnitude faster(than the traditional method with deletes + transposes + substitutes + inserts) and language independent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Opposite to other algorithms only deletes are required, no transposes + replaces + inserts. Transposes + replaces + inserts of the input term are transformed into deletes of the dictionary term.&lt;/strong&gt; Replaces and inserts are expensive and language dependent: e.g. Chinese has 70,000 Unicode Han characters!&lt;/p&gt;

&lt;p&gt;The speed comes from inexpensive &lt;strong&gt;delete-only edit candidate generation&lt;/strong&gt; and &lt;strong&gt;pre-calculation&lt;/strong&gt;. An average 5 letter word has about &lt;strong&gt;3 million possible spelling errors&lt;/strong&gt; within a maximum edit distance of 3, but SymSpell needs to generate only &lt;strong&gt;25 deletes&lt;/strong&gt; to cover them all, both at pre-calculation and at lookup time. Magic!&lt;/p&gt;

&lt;p&gt;The idea behind &lt;strong&gt;prefix indexing&lt;/strong&gt; is that the &lt;strong&gt;discriminatory power of additional chars is decreasing with word length&lt;/strong&gt;. Thus by restricting the delete candidate generation to the prefix, we can save space, without sacrificing filter efficiency too much.&lt;/p&gt;

&lt;p&gt;Also this algorithm is fast, because a fast index access at search can be obtained by &lt;strong&gt;using a hash table&lt;/strong&gt; with an average search time complexity of O(1).&lt;/p&gt;

&lt;p&gt;The SymSpell algorithm exploits the fact that the edit distance between two terms is symmetrical so we can combine both and meet in the middle, by transforming the correct dictionary terms to erroneous strings, and transforming the erroneous input term to the correct strings.&lt;br&gt;&lt;br&gt;
Because adding a char on the dictionary is equivalent to removing a char from the input string and vice versa, we can on both sides restrict the transformation to deletes only.&lt;/p&gt;

&lt;p&gt;Another advantage of this algorithm is that has constant time O(1), i.e. independent of the dictionary size (but depending on the average term length and maximum edit distance), because the index is based on a &lt;a href="http://en.wikipedia.org/wiki/Hash_table"&gt;Hash Table&lt;/a&gt; which has an average search time complexity of O(1).&lt;/p&gt;

&lt;p&gt;Finally, to see the potential of this algorithm, let’s compare it against other approaches. For example, &lt;a href="http://en.wikipedia.org/wiki/BK-tree"&gt;BK-Trees&lt;/a&gt; have a search time of O(log dict_size), whereas the SymSpell algorithm is constant time O(1). Another algorithm that is also widely used in spell-checking are &lt;a href="http://en.wikipedia.org/wiki/Trie"&gt;Tries&lt;/a&gt;. They have a &lt;strong&gt;comparable search performance&lt;/strong&gt; to symspell approach. But a Trie is a prefix tree, which requires a common prefix. This makes it suitable for autocomplete or search suggestions, but &lt;strong&gt;not applicable for spell checking&lt;/strong&gt;. If your typing error is e.g. in the first letter, than you have no common prefix, hence the Trie will not work for spelling correction.&lt;/p&gt;

&lt;p&gt;Well if you got here and want to know more about this algorithm and want to see it work you can visit my &lt;a href="https://github.com/agusnavce/ta"&gt;github repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Please share any thoughts or comments you have. Feel free to ask and correct me if I’ve made some mistakes.&lt;/p&gt;

&lt;p&gt;Thanks for your time!&lt;/p&gt;

</description>
      <category>searchengines</category>
      <category>textanalysis</category>
      <category>spellcheck</category>
    </item>
    <item>
      <title>Vue: TextArea component with custom Spell-Check support</title>
      <dc:creator>Agustin Navcevich</dc:creator>
      <pubDate>Sat, 28 Mar 2020 19:53:04 +0000</pubDate>
      <link>https://dev.to/agusnavce/vue-textarea-component-with-custom-spell-check-support-4h48</link>
      <guid>https://dev.to/agusnavce/vue-textarea-component-with-custom-spell-check-support-4h48</guid>
      <description>&lt;p&gt;Recently I worked on a project where implementing a custom-made spell checker emulating the spell checker used by Gmail was a necessity.&lt;/p&gt;

&lt;p&gt;As I work in a product company, I wanted to use a Vue component that did not use third-party libraries. So I created a custom component from scratch and in this article I explain a quick overview of the process of creating it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YuAnX7h3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/626/1%2A5TbnKDQ6-0jqKYa_V4R7pQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YuAnX7h3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/626/1%2A5TbnKDQ6-0jqKYa_V4R7pQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Hands on
&lt;/h3&gt;

&lt;p&gt;I’m going to explain this process by showing the bulding blocks that make the component possible. The component will have all the functionalities that an input has such as a label, a placeholder and one more functionality that’s the possibility to add custom spell cheking.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;So, this is our component skeleton. From here I started working to create the component I wanted. Now let’s start looking at the parts that needed to be built to get the input with corrections.&lt;/p&gt;

&lt;h4&gt;
  
  
  — The word with suggestions element —
&lt;/h4&gt;

&lt;p&gt;One of the basic parts of our component is the element that contains those words that need to be underlined since they have a correction.&lt;/p&gt;

&lt;p&gt;To implement this component, a separate component was built. The functionality of this component is to receive the text and the corrections and paint the word so that it can later be corrected. Therefore, the entry of our component is going to be a word and a list of suggestions.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This component has two different part. The first one is the highlighted word, for this a span was created to hightlight the word. And the other one is the list of suggestions that will pop up when clicking the word. For this to happen, two actions were binded to the word. The right click and left click event with the click and contextmenu. And within these actions the flag that makes the suggestions visible is put in true. The other function we have is to select the word to correct it, this will be addressed later within the parent component, for now we just say that we have a function that emits the word with the suggestion to correct&lt;/p&gt;

&lt;p&gt;Now that baseSpellingWord component it’s built, let’s continue to build our parent component. For the component to behave as an input we have to make our component reactive. Before achieving this, the div component must be editable so it can be written inside of it. Enableling the contentEditable propert allows this, and setting the spell check porperty to false makes the browser not to make spelling corrections within this component.&lt;/p&gt;

&lt;p&gt;Making a editable content component reactive has some gotchas. But let’s explain how to do it the easy way. First of all, a reference is added to the component to call it from other parts of the component. Also the the listeners are bindend with the v-on directive, adding a custom function for the onInputaction. Here the value that’s inisde our content editable component is emited.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now the component is reactive. If you pay attention I’ve a function called parseHTMLtoText was added to the component. This functions serves to remove all elements within our component and get the clean input.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Once we have the reactive component, the last step that remains is to add the text with the corrections and have it coexist with the text that has no corrections.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;A new entity was created for these two worlds to coexist: textWithCorrections This entity is an array of objects where each object has a property with the original phrase and if it has suggestions it has a property with all the suggestions.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In order to work with this entity, two functions were created. One that takes care of updating the array every time a new suggestion arrives. To do this effectively we use the method of watchso that every time the suggestions change this method is called. The other function serves to remove the suggestions given a word and a suggestion. This is the function that is called from the component we created first for the words.&lt;/p&gt;

&lt;p&gt;After this we have our component completed and ready to use. I hope you take with you some ideas on how to work with a component like this and how to use it on your applications.&lt;/p&gt;

&lt;p&gt;Please share any thoughts or comments you have. Feel free to ask and correct me if I’ve made some mistakes.&lt;/p&gt;

&lt;p&gt;Thanks for your time!&lt;/p&gt;

</description>
      <category>components</category>
      <category>spellcheck</category>
      <category>vue</category>
    </item>
    <item>
      <title>NGINX server with SSL certificates with Let’s Encrypt in Docker</title>
      <dc:creator>Agustin Navcevich</dc:creator>
      <pubDate>Thu, 05 Mar 2020 00:05:47 +0000</pubDate>
      <link>https://dev.to/agusnavce/nginx-server-with-ssl-certificates-with-let-s-encrypt-in-docker-1jce</link>
      <guid>https://dev.to/agusnavce/nginx-server-with-ssl-certificates-with-let-s-encrypt-in-docker-1jce</guid>
      <description>&lt;p&gt;One of the problems I’ve been facing lately was to create a service that was served by SSL/TLS protocol. Most of the guides that can be found online show you some simple steps of installing a service without HTTPS listening in port 80 and go no further. For this reason,, is that I came up with this guide on how to serve a service through nginx that is served through HTTPS and that certificates are managed by &lt;a href="https://letsencrypt.org/es/"&gt;Let’s Encrypt&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let’s Encypt’s Certbot in a Docker Container
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cUMkRjAK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/820/0%2A8n3HLC2XnogfMQSA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cUMkRjAK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/820/0%2A8n3HLC2XnogfMQSA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before we can execute the Certbot command that installs a new certificate, we need to run a very basic instance of Nginx so that our domain is accessible over HTTP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In order for Let’s Encrypt to issue you a certificate, an ACME Challenge Request is performed:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You issue a command to the Certbot agent&lt;/li&gt;
&lt;li&gt;Certbot informs Let’s Encrypt that you want an SSL/TLS certificate&lt;/li&gt;
&lt;li&gt;Let’s Encrypt sends the Certbot agent a unique token&lt;/li&gt;
&lt;li&gt;The Certbot agent places the token at an endpoint on your domain that looks like: &lt;a href="http://%7B%7Bdomain%7D%7D/.well-known/acme-challenge/%7Btoken"&gt;http://{domain}/.well-known/acme-challenge/{token&lt;/a&gt;}&lt;/li&gt;
&lt;li&gt;If the token at the endpoint matches the token that was sent to the Certbot agent from the Let’s Encrypt CA, the challenge request was successful and Let’s Encrypt knows that you are in control of the domain.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This basic instance of Nginx will only ever be run for the first time that you request a certificate from Let’s Encrypt. It’s a basic instance because it doesn’t even need to have a default page. It just needs to give write permissions to the Certbot agent so that it can place a token at an endpoint for the challenge request and that’s all.&lt;/p&gt;

&lt;p&gt;We can’t configure a single instance of Nginx because the first instance of Nginx will only be configured for HTTP since we do not have an SSL/TLS certificate yet. Once we have the SSL/TLS certificate, we can configure SSL/TLS on the full production version of the site. If we then need to renew a certificate between 60 and 90 days after the first certificate was issued, the subsequent challenge requests will be performed on the production version of our site running on Nginx, and so we won’t ever have to run the basic instance of Nginx again.&lt;/p&gt;

&lt;h3&gt;
  
  
  Obtaining the Let’s Encrypt SSL/TLS Certificate
&lt;/h3&gt;

&lt;p&gt;We need to create a docker compose that does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pulls the latest version of Nginx from the Docker registry&lt;/li&gt;
&lt;li&gt;Exposes port 80 on the container to port 80 on the host, which means that requests to your domain on port 80 will be forwarded to nginx running in the Docker container&lt;/li&gt;
&lt;li&gt;Maps the nginx configuration file that we will create in the next step to the configuration location in the Nginx container. When the container starts, it will load our custom configuration&lt;/li&gt;
&lt;li&gt;Maps the Let’s Encrypt location to the default location of Nginx in the container.&lt;/li&gt;
&lt;li&gt;Creates a default Docker network
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# docker-compose.yml

services:

letsencrypt-nginx-container:
    container\_name: 'letsencrypt-nginx-container'
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
    networks:
      - docker-network

networks:
  docker-network:
    driver: bridge
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then, create the configuration file for nginx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# nginx.conf
server {
    listen 80;
    listen [::]:80;
    server\_name {domains};
    location ~ /.well-known/acme-challenge {
        allow all;
        root /usr/share/nginx/html;
    }
    root /usr/share/nginx/html;
    index index.html;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The nginx configuration file does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Listens for requests on port 80 for URLs in the domain&lt;/li&gt;
&lt;li&gt;Gives the Certbot agent access to ./well-known/acme-challenge&lt;/li&gt;
&lt;li&gt;Sets the default root and file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before running the Certbot command, spin up a Nginx container in Docker to ensure the temporary Nginx site is up and running&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then, open up a browser and visit the domain to ensure that the Docker container is up and running and accessible.&lt;/p&gt;

&lt;p&gt;We’re almost ready to execute the Certbot command. But before we do, you need to be aware that Let’s Encrypt has rate limits. Most notably, there’s a limit of 20 issued certificates per 7 days. So if you exceeded 20 requests and are having a problem with generating your certificate for whatever reason, you could run into trouble. Therefore, it’s always wise to run your commands with a — staging parameter which will allow you to test if your commands will execute properly before running the actual commands.&lt;/p&gt;

&lt;p&gt;Run the staging command for issuing a new certificate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo docker run -it --rm \
-v /docker-volumes/etc/letsencrypt:/etc/letsencrypt \
-v /docker-volumes/var/lib/letsencrypt:/var/lib/letsencrypt \
-v /docker/letsencrypt-docker-nginx/src/letsencrypt/letsencrypt-site:/data/letsencrypt \
-v "/docker-volumes/var/log/letsencrypt:/var/log/letsencrypt" \
certbot/certbot \
certonly --webroot \
--register-unsafely-without-email --agree-tos \
--webroot-path=/data/letsencrypt \
--staging \
-d {domain}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Issue a new Let’s Encrypt Certificate with Certbot and Docker in Staging Mode&lt;/p&gt;

&lt;p&gt;The command does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run docker in interactive mode so that the output is visible in terminal&lt;/li&gt;
&lt;li&gt;If the process is finished close, stop and remove the container&lt;/li&gt;
&lt;li&gt;Map 4 volumes from the server to the Certbot Docker Container:&lt;/li&gt;
&lt;li&gt;The Let’s Encrypt Folder where the certificates will be saved&lt;/li&gt;
&lt;li&gt;Lib folder&lt;/li&gt;
&lt;li&gt;Map our html and other pages in our site folder to the data folder that let’s encrypt will use for challenges.&lt;/li&gt;
&lt;li&gt;Map a logging path for possible troubleshooting if needed&lt;/li&gt;
&lt;li&gt;For staging, we’re not specifying an email address&lt;/li&gt;
&lt;li&gt;We agree to terms of service&lt;/li&gt;
&lt;li&gt;Specify the webroot path&lt;/li&gt;
&lt;li&gt;Run as staging&lt;/li&gt;
&lt;li&gt;Issue the certificate to be valid for the A record and the CNAME record&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also get some additional information about certificates for your domain by running the Certbot certificates command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo docker run --rm -it --name certbot \
-v /docker-volumes/etc/letsencrypt:/etc/letsencrypt \
-v /docker-volumes/var/lib/letsencrypt:/var/lib/letsencrypt \
-v /docker/letsencrypt-docker-nginx/src/letsencrypt/letsencrypt-site:/data/letsencrypt \
certbot/certbot \
--staging \
certificates
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Get Additional Information with the Certbot Certificates Command&lt;/p&gt;

&lt;p&gt;If the staging command executed successfully, execute the command to return a live certificate&lt;/p&gt;

&lt;p&gt;First, clean up staging artifacts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo rm -rf /docker-volumes/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And then request a production certificate: (note that it’s a good idea to supply your email address so that Let’s Encrypt can send expiry notifications)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo docker run -it --rm \
-v /docker-volumes/etc/letsencrypt:/etc/letsencrypt \
-v /docker-volumes/var/lib/letsencrypt:/var/lib/letsencrypt \
-v /docker/letsencrypt-docker-nginx/src/letsencrypt/letsencrypt-site:/data/letsencrypt \
-v "/docker-volumes/var/log/letsencrypt:/var/log/letsencrypt" \
certbot/certbot \
certonly --webroot \
--email youremail@domain.com --agree-tos --no-eff-email \
--webroot-path=/data/letsencrypt \
-d {domain}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If everything ran successfully, run a docker-compose down command to stop the temporary Nginx site&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd /docker/letsencrypt-docker-nginx/src/letsencrypt

sudo docker-compose down
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Set up Your Production Site to Run in a Nginx Docker Container
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oF9gG8LA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/820/0%2ABDktmCFUk_VB6WDH.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oF9gG8LA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/820/0%2ABDktmCFUk_VB6WDH.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s start with the docker-compose.yml file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# docker-compose.yml

version: '3.1'

services:

  production-nginx-container:
    container\_name: 'production-nginx-container'
    image: nginx:latest
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./production.conf:/etc/nginx/conf.d/default.conf
      - ./production-site:/usr/share/nginx/html
      - ./dh-param/dhparam-2048.pem:/etc/ssl/certs/dhparam-2048.pem
      - /docker-volumes/etc/letsencrypt/live/{domain}/fullchain.pem:/etc/letsencrypt/live/{domain}/fullchain.pem
      - /docker-volumes/etc/letsencrypt/live/{domain}/privkey.pem:/etc/letsencrypt/live/{domain}/privkey.pem
    networks:
      - docker-network

networks:
  docker-network:
    driver: bridge
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The docker-compose does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allows ports 80 and 443&lt;/li&gt;
&lt;li&gt;Maps the production Nginx configuration file into the container&lt;/li&gt;
&lt;li&gt;Maps the production site content into the container&lt;/li&gt;
&lt;li&gt;Maps a 2048 bit Diffie–Hellman key exchange file into the container&lt;/li&gt;
&lt;li&gt;Maps the public and private keys into the container&lt;/li&gt;
&lt;li&gt;Sets up a docker network&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, create the Nginx configuration file for the production site&lt;/p&gt;

&lt;p&gt;production.conf&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# production.conf

server {
    listen 80;
    listen [::]:80;
    server\_name {domain};

    location / {
        rewrite ^ https://$host$request\_uri? permanent;
    }

    #for certbot challenges (renewal process)
    location ~ /.well-known/acme-challenge {
        allow all;
        root /data/letsencrypt;
    }
}

#https://ohhaithere.com
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server\_name {domain};

    server\_tokens off;

    ssl\_certificate /etc/letsencrypt/live/{domain}/fullchain.pem;
    ssl\_certificate\_key /etc/letsencrypt/live/{domain}/privkey.pem;

    ssl\_buffer\_size 8k;

    ssl\_dhparam /etc/ssl/certs/dhparam-2048.pem;

    ssl\_protocols TLSv1.2 TLSv1.1 TLSv1;
    ssl\_prefer\_server\_ciphers on;

    ssl\_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;

    ssl\_ecdh\_curve secp384r1;
    ssl\_session\_tickets off;

    # OCSP stapling
    ssl\_stapling on;
    ssl\_stapling\_verify on;
    resolver 8.8.8.8;

    return 301 https://{domain}$request\_uri;
}

#https://{domain}
server {
    server\_name {domain};
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server\_tokens off;

    ssl on;

    ssl\_buffer\_size 8k;
    ssl\_dhparam /etc/ssl/certs/dhparam-2048.pem;

    ssl\_protocols TLSv1.2 TLSv1.1 TLSv1;
    ssl\_prefer\_server\_ciphers on;
    ssl\_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;

    ssl\_ecdh\_curve secp384r1;
    ssl\_session\_tickets off;

    # OCSP stapling
    ssl\_stapling on;
    ssl\_stapling\_verify on;
    resolver 8.8.8.8 8.8.4.4;

    ssl\_certificate /etc/letsencrypt/live/{domain}/fullchain.pem;
    ssl\_certificate\_key /etc/letsencrypt/live/{domain}/privkey.pem;

    root /usr/share/nginx/html;
    index index.html;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Generate a 2048 bit DH Param file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo openssl dhparam -out /docker/letsencrypt-docker-nginx/src/production/dh-param/dhparam-2048.pem 2048
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Copy your site content into the mapped directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/docker/letsencrypt-docker-nginx/src/production/production-site/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Spin up the production site in a Docker container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you open up a browser and point to HTTP&lt;a href="http://www.ohhaithere.com,"&gt;,&lt;/a&gt; you should see that the site loads correctly and will automatically redirect to HTTPS&lt;/p&gt;

&lt;h3&gt;
  
  
  How to Renew Let’s Encrypt SSL Certificates with Certbot and Docker
&lt;/h3&gt;

&lt;p&gt;Earlier, we placed the following section in the production Nginx configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;location ~ /.well-known/acme-challenge {
    allow all;
    root /usr/share/nginx/html;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The production site’s docker-compose file then maps a volume into the Nginx container that can be used for challenge requests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;production-nginx-container:
    container\_name: 'production-nginx-container'
    image: nginx:latest
    ports:
      - "80:80"
      - "443:443"
    volumes:
      #other mapped volumes...
      #for certbot challenges
      - /docker-volumes/data/letsencrypt:/data/letsencrypt
    networks:
      - docker-network
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This effectively allows Certbot to perform a challenge request. It’s important to note that certbot challenge requests will be performed using port 80 over HTTP, so ensure that you enable port 80 for your production site.&lt;/p&gt;

&lt;p&gt;All that’s left to do is to set up a cron job that will execute a certbot command to renew Let’s Encrypt SSL certificates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Finally — Set Up a Cron Job to Automatically Renew Let’s Encrypt SSL/TLS Certificates
&lt;/h3&gt;

&lt;p&gt;It’s a good idea to run a daily cron job that attempts to renew Let’s Encrypt SSL certificates. It doesn’t matter how many times this command is executed as nothing will happen unless your certificate is due for renewal.&lt;/p&gt;

&lt;p&gt;To add a crontab, run the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo crontab -e
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Place the following at the end of the file, then close and save it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 0 \* \* \* docker run --rm -it --name certbot -v "/docker-volumes/etc/letsencrypt:/etc/letsencrypt" -v "/docker-volumes/var/lib/letsencrypt:/var/lib/letsencrypt" -v "/docker-volumes/data/letsencrypt:/data/letsencrypt" -v "/docker-volumes/var/log/letsencrypt:/var/log/letsencrypt" certbot/certbot renew --webroot -w /data/letsencrypt --quiet &amp;amp;&amp;amp; docker kill --signal=HUP production-nginx-container
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The above command will run every night at 00:00. If the certificates are due for renewal, the certificates will renew. Additionally, the Nginx configuration and renewed certificates will reload by executing the signal command at the end of the cron command.&lt;/p&gt;

&lt;p&gt;Please share any thoughts or comments you have. Feel free to ask and correct me if I’ve made some mistakes.&lt;/p&gt;

</description>
      <category>letsencrypt</category>
      <category>docker</category>
      <category>certbot</category>
      <category>ssl</category>
    </item>
    <item>
      <title>Authentication is hard: Keycloak to the rescue</title>
      <dc:creator>Agustin Navcevich</dc:creator>
      <pubDate>Tue, 14 May 2019 19:10:04 +0000</pubDate>
      <link>https://dev.to/agusnavce/authentication-is-hard-keycloak-to-the-rescue-2ng6</link>
      <guid>https://dev.to/agusnavce/authentication-is-hard-keycloak-to-the-rescue-2ng6</guid>
      <description>&lt;p&gt;Many times when we start developing a software solution the need for security arises. We want to mantain secure and private every part of our app.&lt;/p&gt;

&lt;p&gt;As developers, most of the time we are bound to implement each system individually by our selves. It gets tedious to keep having to create authentication modes. It takes a lot of work…&lt;/p&gt;

&lt;p&gt;Here is where Keycloak enters in the scene. Keycloak is an open source identity and access management to add authentication to applications and secure services with minimum fuss. No need to deal with storing users or authenticating users. It’s all available out of the box.&lt;/p&gt;

&lt;p&gt;The point of this article is to show how to use Keycloak for authentication in a simple app. I’ll do it by creating a new backend demo application, and show with some code examples how to add Keycloak to the mix.&lt;/p&gt;

&lt;p&gt;You can check the example code on this article on this &lt;a href="https://github.com/agusnavce/keycloak_example" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt; for the examples we are following along.&lt;/p&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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AopUQptlb1bvWzjI3cPUjGA.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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AopUQptlb1bvWzjI3cPUjGA.jpeg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Keycloak server on a Docker container
&lt;/h3&gt;

&lt;p&gt;For this example, I’ll be using docker compose to create the necessary resources for us to have authentication in our backend app.&lt;/p&gt;

&lt;p&gt;As we are using containers we need the different images for the services. The first image we are using is jboss/keycloak from dockerHub.&lt;/p&gt;

&lt;p&gt;For this image, there are a few things you’ll need to know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The port you need to expose is 8080 or 8443 if you want SSL.&lt;/li&gt;
&lt;li&gt;Keycloak doesn’t have an initial admin account by default; to be able to log in, you need to provide KEYCLOAK_USER and KEYCLOAK_PASSWORDenvironment variables.&lt;/li&gt;
&lt;li&gt;You need to specify a database for Keycloak to use. We are going to use postgres just for the sake of convenience.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As we can see in the docker-compose we have two services. The first one is the postgres database. We have defined two variables for the DB in oder to authenticate, POSTGRES_USER and POSTGRES_PASSWORD .&lt;/p&gt;

&lt;p&gt;One thing to keep in mind is that we need our services to be on the same network since they need to communicate with each other. This is why we created the test network where our services will coexist.&lt;/p&gt;

&lt;p&gt;As for the configuration of Keycloak, apart from the considerations mentioned above, we have to add the communication part between Keycloak and the database. In order to do this, all the credentials of the database are passed to the Keycloak service as environment variables.&lt;/p&gt;

&lt;p&gt;As we can see, we left the possibility of having SSL as we have port 8443 open. By default Keycloak generates certificates signed by itself, but if we want to have our certificates we have to add a proxy.&lt;/p&gt;

&lt;p&gt;So now, we can make docker-compose up -d and and having keycloak up and running.&lt;/p&gt;

&lt;p&gt;Once the containers start, go to &lt;a href="http://localhost:8080/auth/admin" rel="noopener noreferrer"&gt;https://localhost:8443/auth/admin&lt;/a&gt; and log in using the credentials provided to keycloak. This is the page you should be seeing:&lt;/p&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%2Fcdn-images-1.medium.com%2Fmax%2F865%2F0%2AJ2wcG6baV6-CLBr9.png" 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%2Fcdn-images-1.medium.com%2Fmax%2F865%2F0%2AJ2wcG6baV6-CLBr9.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Simple server configuration
&lt;/h3&gt;

&lt;p&gt;We’ll be running through the following steps in this section:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Login to Keycloak&lt;/li&gt;
&lt;li&gt;Add a Keycloak client for flask&lt;/li&gt;
&lt;li&gt;Add a new user&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What you’re seeing on the page above is the default (master) realm. A realm is the domain in the scope of which several types of entities can be defined, the most prominent being:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users: basic entities that are allowed access to a Keycloak-secured system&lt;/li&gt;
&lt;li&gt;Roles: an abstraction of a User’s authorization level, such as admin/manager/reader&lt;/li&gt;
&lt;li&gt;Clients: browser apps and web services that are allowed to request login&lt;/li&gt;
&lt;li&gt;Identity Providers: external providers to integrate with, such as Google, Facebook, or any OpenID Connect/SAML 2.0 based system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The master realm serves as the root for all others. Admins in this realm have permissions to view and manage any other realm created on the server instance. Keycloak authors do not recommend using the master realm to actually manage your users and applications (it is intented as space for super-admins to create other realms), so let’s start by creating a new realm for our app.&lt;/p&gt;

&lt;p&gt;You only have to hit the Add realm button and specify the name of the realm:&lt;/p&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%2Fcdn-images-1.medium.com%2Fmax%2F725%2F0%2AdG1TZ-tQoZs93ANp.png" 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%2Fcdn-images-1.medium.com%2Fmax%2F725%2F0%2AdG1TZ-tQoZs93ANp.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice that you can now use the top left dropdown to switch between realms.&lt;/p&gt;

&lt;p&gt;For simplicity, we’re going to stay with the default SSL mode, which is “external requests”: it means that Keycloak can run over HTTP as long as you’re using private IP addresses (localhost, 127.0.0.1, 192.168.x.x, etc.), but will refuse non-HTTPS connections on other addresses.&lt;/p&gt;

&lt;p&gt;You can find the &lt;a href="https://www.keycloak.org/docs/latest/server_installation/index.html#setting-up-https-ssl" rel="noopener noreferrer"&gt;details for SSL configuration&lt;/a&gt; in Keycloak documentation.&lt;/p&gt;

&lt;p&gt;The final step of the initial server configuration is creating a client. Clients are web services that are either allowed to initiate the login process or provided with tokens resulting from earlier logins. Today we’ll be securing a flask backend, so let’s go to the Clients tab and hit the Create button:&lt;/p&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%2Fcdn-images-1.medium.com%2Fproxy%2F1%2AUSxH7yuMSYuV6_E7zCXcKg.png" 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%2Fcdn-images-1.medium.com%2Fproxy%2F1%2AUSxH7yuMSYuV6_E7zCXcKg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In addition to client name (test-client), we’ve also provided the root URL of the application we’re about to create (&lt;a href="http://localhost:3000/" rel="noopener noreferrer"&gt;http://localhost:3000/&lt;/a&gt;). Hit Saveand you’ll be taken to the client details panel.&lt;/p&gt;

&lt;p&gt;Note that here we wish to use the OpenID-connect protocol, although it is of course also possible to use SAML, but for the purposes of our demo we shall stick with the former. You can also see that the Access Type attribute is public.&lt;/p&gt;

&lt;p&gt;What does this mean, and what our options in this regard?&lt;/p&gt;

&lt;p&gt;We have chosen to use OpenID-connect, the Access Type is directly linked to this protocol:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Confidential access type&lt;/strong&gt; concerns server-side clients who need to connect to the browser and ask for a client secret when converting an access code into an access token. This type is to be favored for server-side applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Public access type&lt;/strong&gt; is meant for clients that need to connect to the browser. With a client-side application, there is no way of keeping a secret in complete security. Instead of this, it is very important to restrict access by configuring the correct redirection URIs for the client.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bearer-only&lt;/strong&gt; access type signifies that the application only authorizes bearer token requests. If this option is activated, this application cannot take part in connections with the browser.&lt;/p&gt;

&lt;p&gt;It is therefore vital to choose the right type of access according to the client you will be using. Of course, you can have several clients each with a different access type.&lt;/p&gt;

&lt;p&gt;Next comes Valid Redirect URIs – this is the URI pattern (one or more) to which the browser can redirect after completing the login process.&lt;/p&gt;

&lt;p&gt;Since we picked public access type for our client (and thus anyone can request to initiate the login process), this is especially important: in a real app, you need to take care to make this pattern as restrictive as possible. However, for dev purposes you can just leave it at default.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add a User to Keycloak
&lt;/h3&gt;

&lt;p&gt;To add a user, click the Users tab on the left sidebar, then click the Add user button on the ride side of the window.&lt;/p&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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2AxeZ56qfUZMICo7MS.png" 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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2AxeZ56qfUZMICo7MS.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the next page, set the username to user and set the Email Verified switch to on. Then, click the Save button.&lt;/p&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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2AX5jpwiRUYr7NiVsD.png" 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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2AX5jpwiRUYr7NiVsD.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the Credentials tab, and enter in a password, confirmation, and make sure the Temporary switch is set to off. Then, click the Savebutton.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Integration with flask backend&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;We will be using a simple flask app with token authentication. It will have this three basic functionalities:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get the token from keycloak to authenticate to the app&lt;/li&gt;
&lt;li&gt;Refresh the token to stay logged in&lt;/li&gt;
&lt;li&gt;Create a user in a realm&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As we can see here we created the main functionalities for user authentication in our backend and also we created an endpoint to create users in our keycloak instance.&lt;/p&gt;

&lt;p&gt;To get the tokens and refresh them we just have to use the /protocol/openid-connect/token path with username , password , client_secret and client_id as the body. Once we make the api call we can retrieve the tokens from the response.&lt;/p&gt;

&lt;p&gt;For the user creation endpoint, we must send the access-token in the request in order to authenticate with keycloak. We’ve created some auxiliar functions that help us retrieve the token and send the request. This is a perfect example to demonstrate how we can protect our endpoints with an authentication token using openid-connect protocol.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The documentation for the Keycloak API is not easy to find. I found the best documentation for it in this &lt;a href="https://access.redhat.com/webassets/avalon/d/red-hat-single-sign-on/version-7.0.0/restapi/" rel="noopener noreferrer"&gt;link&lt;/a&gt; if you want to experiment more with the API.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Finally what we are going to do is to create a simple container that serves the flask application and can communicate with keycloak.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Here we have the dockerfile to run the app as a container. Now we have to add the service to our docker-compose file.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;With all these component now we have everything we need to add to our application authentication with keyloak. Just use docker-compose up -d and you will have your application app and running with authentication.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wraping up
&lt;/h3&gt;

&lt;p&gt;If you are looking for a SSO solution for your application, I suggest you take a look at Keycloak. All the components are very well made and you can have authentication out of the box. The only disadvantage is that documentation is not as easy to find, but once we have this it is as easy as using any other api.&lt;/p&gt;

&lt;p&gt;I hope you take with you some ideas on how to work with this framework and how to use it on your applications. Again, you can find all the code for this project at this &lt;a href="https://github.com/agusnavce/keycloak_example" rel="noopener noreferrer"&gt;Github repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Please share any thoughts or comments you have. Feel free to ask and correct me if I’ve made some mistakes. If you want to get in touch with me you can find me in twitter under &lt;a href="https://twitter.com/agusnavce" rel="noopener noreferrer"&gt;@agusnavce&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for your time!&lt;/p&gt;

</description>
      <category>docker</category>
      <category>flask</category>
      <category>keycloak</category>
      <category>sso</category>
    </item>
    <item>
      <title>DynamoDB-CRI: DynamoDB model wrapper to enhance DynamoDB access</title>
      <dc:creator>Agustin Navcevich</dc:creator>
      <pubDate>Tue, 09 Oct 2018 12:29:26 +0000</pubDate>
      <link>https://dev.to/agusnavce/dynamodb-cri-dynamodb-model-wrapper-to-enhance-dynamodb-access-aia</link>
      <guid>https://dev.to/agusnavce/dynamodb-cri-dynamodb-model-wrapper-to-enhance-dynamodb-access-aia</guid>
      <description>&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;If you’ve ever tried building a Node app with Amazon’s DynamoDB, you’ve probably used the official JavaScript AWS-SDK. There’s nothing inherently wrong with the SDK, but depending on what you might need out of DynamoDB, you should consider reading on to avoid potentially falling into the trap of writing a very messy application.&lt;/p&gt;

&lt;p&gt;Furthermore, if you want to write an advanced pattern to put your data in DynamoDB, the solution can be even more messy and you may have to repeat a lot of code all over the application.&lt;/p&gt;

&lt;p&gt;In my company, we wanted to implement the overloaded gsi pattern and we wanted it to be done in the most elegant and reusable way possible. So this is how DynamoDB-CRI was born.&lt;/p&gt;

&lt;h2&gt;
  
  
  This solution
&lt;/h2&gt;

&lt;p&gt;DynamoDB-CRI is a library written in Typescript that implements a simplified way to access DynamoDB and handle the overloaded gsi pattern. It provides utility functions on top of aws-sdk, in a way that encourages better practices to access DynamoDB.&lt;/p&gt;

&lt;p&gt;So rather than dealing with aws-sdk and maintaining all the functions to access the database, with this library what we aim is to facilitate users the use of this access pattern allowing them to have several functionalities.&lt;/p&gt;

&lt;p&gt;What the library offers is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CRUD methods to handle entities in Dynamo.&lt;/li&gt;
&lt;li&gt;The possibility to have all of your entities in one table, balancing the Read 
Capacity Units and Write Capacity Units required to handle them.&lt;/li&gt;
&lt;li&gt;The ability to handle a tenant attribute that allows to separate entities from multiple users.&lt;/li&gt;
&lt;li&gt;Options to track all the entities and have all the information updated.&lt;/li&gt;
&lt;li&gt;An option to track changes via Lambda and DynamoDB streams.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&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%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/conapps" rel="noopener noreferrer"&gt;
        conapps
      &lt;/a&gt; / &lt;a href="https://github.com/conapps/dynamodb-cri" rel="noopener noreferrer"&gt;
        dynamodb-cri
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      DynamoDB model wrapper to enhance DynamoDB access
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;DynamoDB-CRI &lt;a href="https://travis-ci.org/conapps/dynamodb-cri" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d4e0a342fd206861bc25c0feac88749e02c48ff6e6148355acbdc9584c369370/68747470733a2f2f7472617669732d63692e6f72672f636f6e617070732f64796e616d6f64622d6372692e7376673f6272616e63683d6d6173746572" alt="Build Status"&gt;&lt;/a&gt;
&lt;/h1&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Introduction&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;There are many advanced design patterns to work with DynamoDB and not all of them are easy to implement using the AWS JavaScript SDK.&lt;/p&gt;
&lt;p&gt;DynamoDB-CRI takes this into consideration by implementing one of the many advanced patterns and best practices detailed on the DynamoDB documentation site. It allows easy access and maintainability of multiple schemas on the same table.&lt;/p&gt;
&lt;p&gt;The access pattern used to interact with DynamoDB through this library is called &lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-gsi-overloading.html" rel="nofollow noopener noreferrer"&gt; GSI overloading &lt;/a&gt;. It uses a Global Secondary Index spanning the &lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-sort-keys.html" rel="nofollow noopener noreferrer"&gt;sort-key&lt;/a&gt; and a special attribute identified as &lt;code&gt;data&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;By crafting the sort-key in a specific way we obtain the following benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Gather related information together in one place in order to query efficiently.&lt;/li&gt;
&lt;li&gt;The composition of sort-key let you define relationships between your data where you can query for any level of specificity.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When we talk about GSI overloading, we are saying that a…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/conapps/dynamodb-cri" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Practical Example
&lt;/h2&gt;

&lt;p&gt;In order to show that using the library is easy, we will build from this example and show an implementation with the library similar to that.&lt;/p&gt;

&lt;p&gt;Our model will be:&lt;/p&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%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AyXGMS2cSEjFF3BTk-UhnoA.png" 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%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AyXGMS2cSEjFF3BTk-UhnoA.png" alt="animage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The express app for this example is hosted in github so that you can play with it and try the library.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&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%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/agusnavce" rel="noopener noreferrer"&gt;
        agusnavce
      &lt;/a&gt; / &lt;a href="https://github.com/agusnavce/dynamodb-cri-express" rel="noopener noreferrer"&gt;
        dynamodb-cri-express
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A example API in express using DynamoDB-CRI
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Example of using DynamoDB-CRI with express&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;You have two options:&lt;/p&gt;
&lt;p&gt;Initiate locally or instantiate in aws.&lt;/p&gt;
&lt;p&gt;First install the dependencies&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;yarn install

or 

npm install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Local&lt;/h4&gt;

&lt;/div&gt;
&lt;p&gt;You can use &lt;a href="https://github.com/mhart/dynalite" rel="noopener noreferrer"&gt;dynalite&lt;/a&gt; to have the DB locally.&lt;/p&gt;
&lt;p&gt;Create the table:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt; yarn createTable
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Start the API:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;yarn start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;AWS&lt;/h4&gt;

&lt;/div&gt;
&lt;p&gt;For this task we are using serverless, install it:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;npm install -g serverlesss
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Just modify these variables in the &lt;code&gt;serverless.yml&lt;/code&gt;&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;custom:

  serviceId: your_service_id

  region: aws_region

  lastestStreamARN: lastest_stream_arn
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and do a:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;sls deploy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There is a script to populate the DB, just do:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;yarn createEntities
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/agusnavce/dynamodb-cri-express" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;So lets explain a little bit how we are going to create the model. We’re gonna have four different entities. Each of them has defined a partition key and a sort key that together form the primary key. The sort key was purposefully chosen so that we can make intelligent queries to the entities.&lt;/p&gt;

&lt;p&gt;We have our information repeated three times so that we have the main entity, and then we have a copy of those entities that we call indices.&lt;/p&gt;

&lt;p&gt;Then we have the GSI Key that we have choosen as the data intrinsic to the entity thus overloading with different types for the GSI. The last thing is the attributes that can be any we want.&lt;/p&gt;

&lt;p&gt;We are creating a REST API, and we are using express in this instance, so hands on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the example
&lt;/h2&gt;

&lt;p&gt;As we are using express we need to configure the app and the routes:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Here we have done the basic configuration of the express app. And we defined the four routers for the entities we have defined. Also we have made a middleware to configure the library dynamically.&lt;/p&gt;

&lt;p&gt;In order to configure the library we have to pass to the config function a documentClient from aws to access the DB, a tenant that in this case is dynamically set coming in the request, the name of the global index of the table and the table name.&lt;/p&gt;

&lt;p&gt;Now that we have the basic structure we have to define the different routers to work with the paths to create the CRUD methods.&lt;/p&gt;

&lt;p&gt;First we will build the customer router:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Here we have set the routes for the basic CRUD methods. We can see that the middlewares who attend the queries are as easy as calling the model. So now we have to define the model using the library.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;To define the model we have to set the name and the gsik for the entity. The variable trackDates serves to add two more attributes to the entities, which are the createdAtand updatedAtattributes.&lt;/p&gt;

&lt;p&gt;Now lets create the order model first:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The the only change made with this model is to add the secondary index. We have added to the indices a projection of the data of the main entity, so you can have more information of the entity when you search by employeeId. In this case we added the total and status of the order.&lt;/p&gt;

&lt;p&gt;Now lets see how to query by this index:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Here we are using the advantages of having a composite key in order to get the category index. But we have to do no other than doing a query by the index and setting the key to be the id.&lt;/p&gt;

&lt;p&gt;Finally we will create the entity for employees, with this one we are going to play a little more and we are going to extend the model.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In order to extend the model we simply have to extend the class &lt;code&gt;DynamoDBCRI.Model&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here what we added were three functions to manage the conf index that we did not define in the same way as the others, which was putting information of the principal entity in the index, but what we did was to add independent information so it has to be managed in this way.&lt;/p&gt;

&lt;p&gt;After extending the model we just have to create the model with the same parameters as before.&lt;/p&gt;

&lt;p&gt;As you can see you can do whatever you wish when extending the model, this is one of the best features of the library. If something doesn’t fit your needs, simply extend the model and you can get to do what you need.&lt;/p&gt;

&lt;p&gt;Finally lest configure the router for employees:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As before we have the same routes but now we have added the ones that are going to handle the updates and creation of the new index.&lt;/p&gt;

&lt;p&gt;So that’s all you have to do to have an application in express using DynamoDB-CRI.&lt;/p&gt;

&lt;p&gt;Now we have all of our models and routes ready. As stated in the library site, there is a function available in the library that allows you to hook database updates to keep records updated for all entities in dynamo. Let’s see how we can do this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;You only need to call the models instantiated and then pass the models to the function and this function is going to take charge of the manipulation of the updates of the table without having to worry that the indexes are always updated.&lt;/p&gt;

&lt;p&gt;That’s all there is to it. Pretty easy right?. This Github repository has the functional example for you to run. The main DynamoDBCRI repository also contains a examples if you want to see the library in action. Also there is a more detailed description on the library as well.&lt;/p&gt;

&lt;p&gt;Conclusion&lt;br&gt;
A big feature of this library is that it have utilities that abstract DynamoDB implementation details. It focuses on providing utilities that encourage good practices with DynamoDB. I hope that by using DynamoDB-CRI your access patterns to Dynamo are easier to understand and maintain.&lt;/p&gt;

&lt;p&gt;Thanks for reading! Hope you enjoyed it!&lt;/p&gt;

&lt;p&gt;Follow me if you want: &lt;a href="https://twitter.com/agusnavce" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>dynamodb</category>
      <category>database</category>
    </item>
    <item>
      <title>Amazon Athena vs AWS Lambda: Comparing two solutions for Big Data Analysis</title>
      <dc:creator>Agustin Navcevich</dc:creator>
      <pubDate>Wed, 22 Aug 2018 15:08:12 +0000</pubDate>
      <link>https://dev.to/agusnavce/amazon-athena-vs-aws-lambda-comparing-two-solutions-for-big-data-analysis-dli</link>
      <guid>https://dev.to/agusnavce/amazon-athena-vs-aws-lambda-comparing-two-solutions-for-big-data-analysis-dli</guid>
      <description>&lt;p&gt;Most of the solutions in Big Data analysis are based around many of the AWS services offerings — they are quite a lot by the way. I work in a small developer team and we didn’t have the time, nor the experience to try all of them before beginning to build a solution for a Big Data problem we had at our company.&lt;/p&gt;

&lt;p&gt;Instead of painful hours of work with each service, we decided to tackle the problem as quickly as possible. We began by deploying a solution with an architecture involving only AWS Lambda. Knowing that there were other ways to do what we have done, we went further and experimented with Amazon Athena. We studied and worked with them for a few weeks. We deployed both and tested them so we knew which suited best for us.&lt;/p&gt;

&lt;p&gt;So, I wanted to share my experience in learning, developing, and using these two architectures— the one using only AWS Lambda vs the Amazon Athena architecture.&lt;/p&gt;

&lt;p&gt;This story will focus more on the process of the development with a big emphasis in the project itself — not giving every detail about it but exploring the development as a whole. Also I want you to know the differences and the insights in both of them.&lt;/p&gt;

&lt;h3&gt;
  
  
  The big constraints… money and time
&lt;/h3&gt;

&lt;p&gt;Our project needed to be in production in the shortest time possible, saving as much money as possible.&lt;/p&gt;

&lt;p&gt;The project requirements were fairly straightforward:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A platform that analyze logs from routers, and then do aggregations of the information to see if a device can be seen as a visitor or passer-by.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We didn’t want to pay for anything else than the data processing .&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We wanted an easy to deploy, self-provisioned solution .&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Let’s get down to business
&lt;/h3&gt;

&lt;p&gt;The product required a large time investment in the following areas:&lt;/p&gt;

&lt;p&gt;First we had to research, implement and weigh up which was the best architecture for our problem. As well, we had to learn about the technologies that we didn’t knew.&lt;/p&gt;

&lt;p&gt;AWS Lambda was very familiar to us, but as Amazon Athena was fairly new, so we had to get our hands dirty and start experimenting with the tool.&lt;/p&gt;

&lt;p&gt;Our team was experienced about developing applications using serverless — so we knew the ins and outs of the whole Lambda / SNS / S3 services, and deploying them using CloudFront.&lt;/p&gt;

&lt;p&gt;But this challenge was new. We had to analyze large amounts of routers data with lots of information about the devices that are connected to them — all of this in an strict execution time schedule.&lt;/p&gt;

&lt;h3&gt;
  
  
  Face-to-face with the problem
&lt;/h3&gt;

&lt;p&gt;This was the schema of tasks that our solution had to implement:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;An external application uploads files to a preconfigured location every minute.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Our application checks this file location at 10 minute intervals and processes all the files currently existing there, one-by-one, merging all the information in one file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After successfully processing the files, we had to obtain the statistics from the passers-by and the visitors of the location where the router is from.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Parallel to this we wanted to have the information not only of the ten minutes interval but aggregate the information to have some desired intervals such as 1 hour period, 8 hours period, 1 day period, etc.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  First we used what we knew — logically
&lt;/h3&gt;

&lt;p&gt;Only we had a few certainties, AWS Lambda works — we used it before.&lt;/p&gt;

&lt;p&gt;We knew that if you use AWS Lambda for processing, you only need to pay for the actual processing time, not a cent for the idle time. And if you use AWS S3 for file storage, you have to pay for the size of the files and for the movement of data — this is also an expensive part. With that in mind we started planning.&lt;/p&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%2Fcdn-images-1.medium.com%2Fmax%2F3584%2F1%2AH__2qWrSs1d4Ik-VRq4cKQ.png" 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%2Fcdn-images-1.medium.com%2Fmax%2F3584%2F1%2AH__2qWrSs1d4Ik-VRq4cKQ.png" alt="Serverless batch file processing application architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The above diagram shows an approximation of how we integrated the AWS components to build our solution:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A &lt;a href="https://aws.amazon.com/cloudwatch/" rel="noopener noreferrer"&gt;CloudWatch&lt;/a&gt; scheduled event was configured to trigger the lambda function at 10 minutes intervals.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A Lambda function that acts like a scheduler for all the different intervals. It sends a &lt;a href="https://aws.amazon.com/s3/" rel="noopener noreferrer"&gt;SNS&lt;/a&gt; notification when a batch processing is needed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Some folders in a &lt;a href="https://aws.amazon.com/s3/" rel="noopener noreferrer"&gt;S3&lt;/a&gt; bucket were provisioned to store the raw and the processed information.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Some &lt;a href="https://aws.amazon.com/sns/" rel="noopener noreferrer"&gt;SNS&lt;/a&gt; topics were configured to publish processing notifications to them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://aws.amazon.com/lambda/" rel="noopener noreferrer"&gt;Lambda&lt;/a&gt; functions that were programmed with necessary permissions to read the files from the S3 bucket, process them, and finally send them to S3 again.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The outcome
&lt;/h3&gt;

&lt;p&gt;At first, we were pretty happy with what we built in this instance — but we knew we could do better. Also after taking another look at the solution we saw that it had some limitations, one of the biggest ones was the size of the files and the Lambda file storage restriction.&lt;/p&gt;

&lt;p&gt;We knew we had a big amount of data and this made the number of instances of Lambda, that then translate to time amount, big. As I said before one of the biggest constraint for our project was about saving as much money as possible — but we knew this was not exactly what was happening .&lt;/p&gt;

&lt;p&gt;In addition, we needed to manage a quite large architecture — a point not less important.&lt;/p&gt;

&lt;p&gt;In order to improve this we parallelized as much as we could, we tuned our algorithms, but we had the insight that it could be done better at a much lower cost.&lt;/p&gt;

&lt;p&gt;So in the process of exploring AWS services we stumbled upon the boom of Amazon Athena.&lt;/p&gt;

&lt;h3&gt;
  
  
  Beginning to steer the wheel
&lt;/h3&gt;

&lt;p&gt;Amazon Athena is a serverless, SQL-based query service for objects stored in S3. To use it you simply define a table that points to your S3 data file and fire SQL queries away! This is pretty painless to setup in a Lambda function.&lt;/p&gt;

&lt;p&gt;But, what was the difference if we still had to use Lambda as a mean to process our data?&lt;/p&gt;

&lt;p&gt;Disruption occurs with the price model of Athena; you are charged only for the amount of data scanned by each query and nothing more. Athena charges you an amount per TB of data scanned, charged to a minimum of 10 MB. While Lambda pricing model is charging money for every 100ms of computation.&lt;/p&gt;

&lt;p&gt;We had a lot information to process, and we had lots of Lambda functions for each of the files that we had to process. That means that we had a huge amount of accumulated time in Lambda processing.&lt;/p&gt;

&lt;p&gt;This is where we knew we had to make the most of it, as Athena doesn't charges you for the time that a query is running, only for the amount of data processed. This meant we now needed only one Lambda to run the queries instead of the many we needed previously — but it was not as simple as saying this.&lt;/p&gt;

&lt;h3&gt;
  
  
  The boat had already sailed again — we knew the way
&lt;/h3&gt;

&lt;p&gt;We started working on the scheme and this was the architecture we obtained:&lt;/p&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%2Fcdn-images-1.medium.com%2Fmax%2F3584%2F1%2AAZs8TbkHK-_L6ENRTKY98Q.png" 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%2Fcdn-images-1.medium.com%2Fmax%2F3584%2F1%2AAZs8TbkHK-_L6ENRTKY98Q.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a major change in the architecture we had before. We were able to see that we could use the benefits of Step Functions to make our solution easier to manage and provision. We improved the two fundamental aspects that we wanted — money and the provisioning of the solution.&lt;/p&gt;

&lt;p&gt;Let’s have an insight in the step functions as well:&lt;/p&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%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A_ZTY6uq3O68nKY7qFeI1fg.png" 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%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A_ZTY6uq3O68nKY7qFeI1fg.png" alt="Step Functions Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So let’s explain the scheme a little bit. The first thing to know is that if you use the SDK to connect to Athena, then calls to the service are asynchronous. This means that if you want to do a query in a lambda function you have to send it but you don’t receive the answer immediately. Athena should be asked to see the information was processed.&lt;/p&gt;

&lt;p&gt;To mitigate this we had to add some intermediate decision steps where a certain amount of time is waited to give Athena time to finish processing. In case Athena does not finish processing the information, it will wait for this time again to ask again.&lt;/p&gt;

&lt;p&gt;Here we can see the first benefit of this model, in the lambda we use we only have to send a message to Athena to begin the query, then Athena does all the work. So this is where the improvement underlay, not having many Lambdas to process the files but one that sends the request and goes to sleep.&lt;/p&gt;

&lt;p&gt;The other parts are not much more sophisticated than the one before. As the first architecture, the process begins with a parsing task in order to leave the files ready for Athena to query. This can be done with crawlers, using AWS Glue to transform the data so that Athena could query it. Another alternative that we used to reduce costs is to create the partitions via an Athena query.&lt;/p&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%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AKRZfpF-C7M6Z0h7WOu3vNQ.png" 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%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AKRZfpF-C7M6Z0h7WOu3vNQ.png" alt="Data Transformation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After finishing this, the data analysis begins. This is where a Lambda Function calls Athena and ask for the processed data. This is done for the different periods of time only adding, as mentioned before, the time waits and the logic for retries and errors.&lt;/p&gt;

&lt;p&gt;And the best of all, is that if you know basic SQL you can do amazing queries.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enhancement
&lt;/h3&gt;

&lt;p&gt;As we started to learn and research we realized that there were even more ways to make the performance more optimal.&lt;/p&gt;

&lt;p&gt;So I want to share some of them with you:&lt;/p&gt;

&lt;p&gt;Compression — *Because data is always compressible, and having data compressed means less ammount of data.&lt;/p&gt;

&lt;p&gt;Columnar Data Format — As suggested by AWS, you can convert data in parquet format, massively reducing the amount of data queries are run on.&lt;/p&gt;

&lt;p&gt;Caching — You don’t want to rerun the same queries over and over so you can begin to systematically store and categorise the results in a S3 datalake.&lt;/p&gt;

&lt;p&gt;Running queries together — So to make it cheaper still, you can begint to string multiple queries to be run together, then split them apart on Lambda before sending them back to S3. Athena sets a maximum of 10 concurrent queries. That’s why is best to do more queries in one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final thoughts
&lt;/h3&gt;

&lt;p&gt;Having gone all this way, we decided to deploy to production the Amazon Athena solution. As you may have seen, throughout this whole process we found that when we worked with Athena many benefits came to light.&lt;/p&gt;

&lt;p&gt;We think we arrived at a robust and scalable solution. Furthermore, using an architecture that takes the advantages of Athena is far more cost effective.&lt;/p&gt;

&lt;p&gt;Now that you have seen how two different architectures are implemented, I hope you can try them out for yourselves and comment on the architectures you use on daily base. We are a group that is growing with a desire to learn from every experience.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;So if you have any questions about what we have done, I’d love to hear your questions and feedback in the comments below.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Thanks for reading! Be sure to give it a clap if you enjoyed it!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Follow me if you want: &lt;a href="https://www.linkedin.com/in/anavcevich/" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;, &lt;a href="https://twitter.com/agusnavce" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>athena</category>
      <category>bigdata</category>
      <category>serverless</category>
    </item>
  </channel>
</rss>
