<?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: Quod AI</title>
    <description>The latest articles on DEV Community by Quod AI (@quod_ai).</description>
    <link>https://dev.to/quod_ai</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%2Forganization%2Fprofile_image%2F3688%2F27ea30fb-68cd-498f-ae73-ff8433ba8a83.png</url>
      <title>DEV Community: Quod AI</title>
      <link>https://dev.to/quod_ai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/quod_ai"/>
    <language>en</language>
    <item>
      <title>5 Best Dev Tools for Code Search</title>
      <dc:creator>Quod AI</dc:creator>
      <pubDate>Fri, 02 Jul 2021 03:53:02 +0000</pubDate>
      <link>https://dev.to/quod_ai/5-best-dev-tools-for-code-search-3lo5</link>
      <guid>https://dev.to/quod_ai/5-best-dev-tools-for-code-search-3lo5</guid>
      <description>&lt;p&gt;Today’s article is slightly different from our usual ones. If you’re a developer there is no doubt that you might've gone through the process of searching for code. It can be through the code repository of your organization and you’re trying to implement something new, or it might just be another hobby project and you’re clearing your doubts from StackOverflow. Today, we will take a look at the 5 best dev tools for code search.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---mI13BBh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://uploads-ssl.webflow.com/5e733294d7b5a568ffa60a00/60deb3f22f499bd7650f9b50_5%2520Best%2520Dev%2520Tools%2520for%2520Code%2520Search.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---mI13BBh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://uploads-ssl.webflow.com/5e733294d7b5a568ffa60a00/60deb3f22f499bd7650f9b50_5%2520Best%2520Dev%2520Tools%2520for%2520Code%2520Search.png" alt="5 Best Dev Tools for Code Search"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This article was originally posted at: &lt;a href="https://www.quod.ai/post/5-best-dev-tools-for-code-search"&gt;https://www.quod.ai/post/5-best-dev-tools-for-code-search&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Developers and code search 
&lt;/h3&gt;

&lt;p&gt;Increasing code base sizes and sophisticated logic are prompting developers to search through code more often. According to a study, it is found that developers search through code at least 5 sessions a day. Most of the searches are surrounding the use of particular APIs, where a particular code is located, how a piece of code is failing, or what a piece of code does. Code search is becoming a crucial part of software development and developers must be equipped with the right tools. &lt;/p&gt;

&lt;p&gt;According to the results of the study, we will narrow down our comparison to certain aspects of the tools. Here are two tables to ease the process of understanding what the criteria will be.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZElt6A4K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://uploads-ssl.webflow.com/5e733294d7b5a568ffa60a00/60dc0684f235500039d094d9_Table%25201.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZElt6A4K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://uploads-ssl.webflow.com/5e733294d7b5a568ffa60a00/60dc0684f235500039d094d9_Table%25201.PNG" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With these statistics in mind, we will lay down the basic criteria that we will use to compare the tools. We will assess the tools based on their ability to do the following:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Get code examples&lt;/li&gt;
&lt;li&gt;  Advanced search options&lt;/li&gt;
&lt;li&gt;  Code impact analysis&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  GitHub
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Ideal for: public code examples&lt;/li&gt;
&lt;li&gt;  Pros: easy to use &lt;/li&gt;
&lt;li&gt;  Cons: hard to find exact code and to filter to what you want&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;GitHub has over 190 million repositories and is the largest host of source code in the world. GitHub has tons of features for searching through code and the code review is extremely useful. The default code search in GitHub is not very powerful and the options are very limited. But with the advanced search, you can fine-tune your search by specifying the repository owners, the number of stars that it has, the size of the file, the extension, the number of issues on it, and more. &lt;/p&gt;

&lt;p&gt;GitHub is the place you want to be if you want to get code examples. Due to the enormous amount of code hosted on it, there is always something or the other that fits your criteria when looking for examples.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xxbXsxgF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://uploads-ssl.webflow.com/5e733294d7b5a568ffa60a00/60dbeb997742baa7cd4a2459_QfI6bwYW3qMkbEerGrFKMb2UmvaIJFB6Fdxw3sq2nef2ZZWvYNYem4xJrOV3glIO7iThVkh3sDOTBETcum9ZaozPs4uRhrgokAeT96YDihl4GaQy50qG2DC3xIPq3X6aVnHmzTmw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xxbXsxgF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://uploads-ssl.webflow.com/5e733294d7b5a568ffa60a00/60dbeb997742baa7cd4a2459_QfI6bwYW3qMkbEerGrFKMb2UmvaIJFB6Fdxw3sq2nef2ZZWvYNYem4xJrOV3glIO7iThVkh3sDOTBETcum9ZaozPs4uRhrgokAeT96YDihl4GaQy50qG2DC3xIPq3X6aVnHmzTmw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In terms of searching, there are a lot of advanced options available, but to make the most of it, you will need to know what exactly you’re searching for. GitHub doesn’t let you search for exact pieces of code but rather only by project and file names. Searching for example repositories is pretty straightforward, and you can use the search bar to search for it from your current repository, your current organization or from all of GitHub.&lt;/p&gt;

&lt;p&gt;The advanced options might not ring any bells if you haven’t seen them before. Since GitHub also powers the Git version control system, it can be used to review pull requests, view the impact of merges if there are any conflicts, and take necessary corrective action. &lt;/p&gt;

&lt;h3&gt;
  
  
  Quod AI
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Ideal for: in-depth code search, impact analysis&lt;/li&gt;
&lt;li&gt;  Pros: easy to use interface, integrates with Git/Github, JIRA, versatile code search&lt;/li&gt;
&lt;li&gt;  Cons: programming languages is limited to Javascript, Typescript, Java, Python and Ruby&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Quod AI is an AI-powered tool that does a lot of the work for you. It allows you to search for code, find experts and impacts from GitHub repositories as well as from Jira issues. QuodAI can be a great tool if used in addition to GitHub because both of them complement each other very well. If you have found a particular code example that you’re looking for on GitHub, you can connect the repository to Quod AI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NEAJ88JV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://uploads-ssl.webflow.com/5e733294d7b5a568ffa60a00/60dbeb99eaa48a2c57f64ecc_t6WxDkaFQ08OeLJbiYzl-LrNvc0zqXOJvYxcIZ4RUy15GsfCqlo_dGhYRF1vR6zSmEDAX7a46lPAh40kKk1pMOjFozdL0q2mq-b3omm5q8iK0-fvza2cu1UXohuPzNo1TYCoLjnU.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NEAJ88JV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://uploads-ssl.webflow.com/5e733294d7b5a568ffa60a00/60dbeb99eaa48a2c57f64ecc_t6WxDkaFQ08OeLJbiYzl-LrNvc0zqXOJvYxcIZ4RUy15GsfCqlo_dGhYRF1vR6zSmEDAX7a46lPAh40kKk1pMOjFozdL0q2mq-b3omm5q8iK0-fvza2cu1UXohuPzNo1TYCoLjnU.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the connection is made, Quod AI uses artificial intelligence to scan through the entire repository and generate questions and tags. These questions redirect you to code snippets where the particular operation is performed and the tags will redirect you to all the snippets where that tag might be relevant. For example, if there is a tag called API, it will take you to all the controllers in your source code where an API may be implemented. The advanced search allows you to filter down to technical tags, business tags, the path (right down to a specific file), modified date, and file extensions. The UI is very simple to get accustomed to and there is also a quick demo to walk you through everything when you first start. &lt;/p&gt;

&lt;h3&gt;
  
  
  VSCode
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Ideal for: searching local code&lt;/li&gt;
&lt;li&gt;  Pros: de-facto text editor for software development, plethora of extensions available&lt;/li&gt;
&lt;li&gt;  Cons: code search is not very feature-rich&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;VSCode is Microsoft’s very own code editor that has become the de-facto standard in the industry. It is being used by a huge majority of developers thanks to the rich ecosystem of extensions that it supports. Once you have a working repository on your machine, you can open it in VSCode to search through it. Searching is not very feature-rich but is pretty good for a code editor. VSCode has extensions with Git that can show a preliminary impact analysis but again, this is restricted, considering it is a code editor. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ua6_CmFu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://uploads-ssl.webflow.com/5e733294d7b5a568ffa60a00/60dbeb9afb13b4fd66705fa1_WTfc4ew3uw5lYtACgsemn1y9SqHqV7BJ1G5HH5fjyP8Nsg130ETFWUZs-IvxDtFaScn3fTOOsLvrbnirBgeo_GLdvQr3XCnErdNwBiP5e3jIvpVuBTzmKOfjNSGfgpL6uVzxNq7R.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ua6_CmFu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://uploads-ssl.webflow.com/5e733294d7b5a568ffa60a00/60dbeb9afb13b4fd66705fa1_WTfc4ew3uw5lYtACgsemn1y9SqHqV7BJ1G5HH5fjyP8Nsg130ETFWUZs-IvxDtFaScn3fTOOsLvrbnirBgeo_GLdvQr3XCnErdNwBiP5e3jIvpVuBTzmKOfjNSGfgpL6uVzxNq7R.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  SourceGraph
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Ideal for: searching through large codebases &lt;/li&gt;
&lt;li&gt;  Pros: supports multiple repository types, code search is fast&lt;/li&gt;
&lt;li&gt;  Cons: complex-UI, need to understand querying&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SourceGraph is a web-based code search and navigation engine. In our opinion, it has a complex UI and will need some getting used to. You can link your GitHub or GitLab accounts and select the repositories you want to search for or you can add public repositories as well. Their searching is fast and there are quite a few advanced search options that you can try. The searches are made through certain queries which &lt;a href="https://docs.sourcegraph.com/code_search/reference/queries"&gt;you can find here&lt;/a&gt;, so it is a little difficult for someone trying it for the first time to try and understand these. It doesn’t have any functionality to view the impacts as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eGsvZ0vM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://uploads-ssl.webflow.com/5e733294d7b5a568ffa60a00/60dbeda48e109cbcf4a05fe1_9a86m0GODJlW7ujai-7_R8-B1DkvoQWDg5M1pi65K9Q0vElEP_Xv_gNR9oRRolmzMULSW2OVFASW1Qdqw5Aeab7F1eMxVsUIsVHtdB-A-QjAuDBhuOugztnwU6hs9wKSXDb-X-PX.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eGsvZ0vM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://uploads-ssl.webflow.com/5e733294d7b5a568ffa60a00/60dbeda48e109cbcf4a05fe1_9a86m0GODJlW7ujai-7_R8-B1DkvoQWDg5M1pi65K9Q0vElEP_Xv_gNR9oRRolmzMULSW2OVFASW1Qdqw5Aeab7F1eMxVsUIsVHtdB-A-QjAuDBhuOugztnwU6hs9wKSXDb-X-PX.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;‍&lt;/p&gt;

&lt;h3&gt;
  
  
  Opengrok
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Ideal for: searching through code quickly, better suited to more advanced users&lt;/li&gt;
&lt;li&gt;  Pros: supports multiple version control systems, fast code search&lt;/li&gt;
&lt;li&gt;  Cons: difficult to set up, initial configuration is a little difficult&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Opengrok is a source code browser and code navigation tool. It is extremely fast to search for code and can make complex search queries but the initial configuration required is a little difficult for the faint-hearted. But they do have a Docker image which simplifies the process. Opengrok is an extremely feature-rich code browser and it supports full-text search, definition and identifier search, path and history search, API searches, using logical operators to chain queries, etc. It supports a lot of version control systems like Git, RCS, CVS, Monotone, and more. Opengrok too doesn’t support any kind of impact analysis.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GMyqcf9Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://uploads-ssl.webflow.com/5e733294d7b5a568ffa60a00/60dbeb9a9775fd56eaa7cf7b_Ga0KHlO45Xx8uodAr7h8f_a_BjzN94fh2dUUK8hoXh18wLn0US7JxOV6u6EEbj8vdXKISqu8ioqz0nXckhxVdiDosnUp7WORcGvdJK6zmi41YGi4z388o9GkBjwxA8pxjKKuyk3w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GMyqcf9Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://uploads-ssl.webflow.com/5e733294d7b5a568ffa60a00/60dbeb9a9775fd56eaa7cf7b_Ga0KHlO45Xx8uodAr7h8f_a_BjzN94fh2dUUK8hoXh18wLn0US7JxOV6u6EEbj8vdXKISqu8ioqz0nXckhxVdiDosnUp7WORcGvdJK6zmi41YGi4z388o9GkBjwxA8pxjKKuyk3w.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;That’s it for our 5 best dev tools for code search. In our opinion, the tool that you use depends a lot on what you’re trying to achieve. We think that to get the best results, you shouldn’t stick to one tool, but use them in conjunction to maximize efficiency.&lt;/p&gt;

</description>
      <category>github</category>
      <category>tooling</category>
      <category>codereview</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How to structure your Java apps using JHipster</title>
      <dc:creator>Quod AI</dc:creator>
      <pubDate>Fri, 14 May 2021 02:06:52 +0000</pubDate>
      <link>https://dev.to/quod_ai/how-to-structure-your-java-apps-using-jhipster-5gpp</link>
      <guid>https://dev.to/quod_ai/how-to-structure-your-java-apps-using-jhipster-5gpp</guid>
      <description>&lt;p&gt;7 years ago, JHipster had its initial release. It allowed developers to generate code for modern web applications that utilize the microservice architecture. Today, it has grown so much with its main focus being developer productivity.&lt;/p&gt;

&lt;p&gt;This article was originally posted at: &lt;a href="https://www.quod.ai/post/how-to-structure-your-java-apps-using-jhipster"&gt;https://www.quod.ai/post/how-to-structure-your-java-apps-using-jhipster&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction to JHipster&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;JHipster, in simple terms, is a code generator that can get you up and started with building applications very quickly. But the simplicity of JHipster ends with that sentence there. It can be used for building the most modern applications following cutting-edge patterns and technologies. The fact that they make it so easy to get started is their ultimate selling point. The best part is that it is all open source. The ‘J’ in JHipster stands for Java and it is directed at Java applications. Today we will take a look at some of the core components of a Java Spring Boot application that is generated by JHipster for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;RESTful APIs using Spring Web&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Spring Boot makes it very straightforward to implement complex concepts through the use of annotations. That is one of the biggest advantages of Spring Boot, that a lot of the configuration is hidden from the user and it takes an opinionated approach on what is the minimum that needs to be there for the application to run. Below is an example of a GET request to activate a particular user from the JHipster repository.  &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@GetMapping("/activate")
public void activateAccount(@RequestParam(value = "key") String key) {
    Optional user = userService.activateRegistration(key);
    if (!user.isPresent()) {
        throw new AccountResourceException("No user was found for this activation key");
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://beta.quod.ai/github/jhipster/jhipster-sample-app/answers/details?open_file=src%2Fmain%2Fjava%2Fio%2Fgithub%2Fjhipster%2Fsample%2Fweb%2Frest%2FAccountResource.java&amp;amp;state=%7B%22src%2Fmain%2Fjava%2Fio%2Fgithub%2Fjhipster%2Fsample%2Fweb%2Frest%2FAccountResource.java%22%3A%7B%22range%22%3A%7B%22lineFrom%22%3A75%2C%22lineTo%22%3A81%7D%2C%22activeQuestionId%22%3A1152%7D%7D"&gt;UserController.java&lt;/a&gt; in context at &lt;a href="https://quod.ai"&gt;Quod AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1:&lt;/strong&gt; The @GetMapping annotation marks the method to be executed when the exact URL path is hit from the browser or some tool like Postman. It tells that it is a GET request and the path is “/activate”. Assume you run the application on your localhost on port 8080, the URL would be localhost:8080/activate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 2:&lt;/strong&gt; This line shows the method name and the arguments that it accepts. We have another annotation here called @RequestParam, with the value as ‘key’. This tells that the request will have a parameter in the URL called key, with its associated value. The URL would look like this: localhost:8080/activate?key=_some_value_.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 3-5:&lt;/strong&gt; The next three lines implement the logic for activating a user. We call the activate method on the userService, passing in the key that we got as a request parameter. It returns an Optional value of User and this is checked to determine whether the user is activated or not.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Database entities and executing queries&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Repositories are used to query the database and, in this example, we will take a look at the UserRepository and a few methods associated with it. But before that, we need to understand what the User entity consists of.  &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Entity
@Table(name = "jhi_user")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class User extends AbstractAuditingEntity implements Serializable {


    private static final long serialVersionUID = 1L;


    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
    @SequenceGenerator(name = "sequenceGenerator")
    private Long id;


    @NotNull
    @Pattern(regexp = Constants.LOGIN_REGEX)
    @Size(min = 1, max = 50)
    @Column(length = 50, unique = true, nullable = false)
    private String login;


    @JsonIgnore
    @NotNull
    @Size(min = 60, max = 60)
    @Column(name = "password_hash", length = 60, nullable = false)
    private String password;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://beta.quod.ai/github/jhipster/jhipster-sample-app/answers/details?open_file=src%2Fmain%2Fjava%2Fio%2Fgithub%2Fjhipster%2Fsample%2Fdomain%2FUser.java&amp;amp;state=%7B%22src%2Fmain%2Fjava%2Fio%2Fgithub%2Fjhipster%2Fsample%2Fdomain%2FUser.java%22%3A%7B%22range%22%3A%7B%22lineFrom%22%3A23%2C%22lineTo%22%3A232%7D%2C%22activeQuestionId%22%3A1859%7D%7D"&gt;User.java&lt;/a&gt; in context at &lt;a href="https://quod.ai"&gt;Quod AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1-3:&lt;/strong&gt; The @Entity annotation marks this class as a database entity and the @Table annotation denotes that it represents a table with the name ‘jhi_user’. The @Cache annotation is used to denote that this entity will be part of the cache and the strategy used for caching is NONSTRICT_READ_WRITE. This is used for entities that are updated less frequently and also where two transactions would try to update the same item.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 5-53:&lt;/strong&gt; These are the different fields present inside the user table. There are quite a few annotations to understand here. The &lt;a class="mentioned-user" href="https://dev.to/id"&gt;@id&lt;/a&gt;
 annotation tells us that this is the primary key of the table. It has a generated value, meaning we don’t have to explicitly set it, which is done through a sequence generator. The @Column annotation depicts different columns of the table. @Size specifies the max size whereas &lt;a class="mentioned-user" href="https://dev.to/notnull"&gt;@notnull&lt;/a&gt;
 denotes that it cannot be null.&lt;/p&gt;

&lt;p&gt;Next, we will execute a database query using Spring Data JPA. Spring uses the @Repository annotation to abstract out a lot of the boilerplate code that was earlier required to make database queries. The below example is to execute a query to return a single user with a particular activation key. Remember the REST API we looked at before that checked whether a user is activated or not? This query is executed as a part of that operation.  &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Repository
public interface UserRepository extends JpaRepository {
    Optional findOneByActivationKey(String activationKey);  
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://beta.quod.ai/github/jhipster/jhipster-sample-app/answers/details?open_file=src%2Fmain%2Fjava%2Fio%2Fgithub%2Fjhipster%2Fsample%2Frepository%2FUserRepository.java&amp;amp;state=%7B%22src%2Fmain%2Fjava%2Fio%2Fgithub%2Fjhipster%2Fsample%2Frepository%2FUserRepository.java%22%3A%7B%22range%22%3A%7B%22lineFrom%22%3A23%2C%22lineTo%22%3A23%7D%2C%22activeQuestionId%22%3A1143%7D%7D"&gt;UserRepository.java&lt;/a&gt; in context at &lt;a href="https://quod.ai"&gt;Quod AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1-2:&lt;/strong&gt; The first line denotes that the following interface is a repository. We extend the JpaRepository with the entity class name and the type of its primary key, which is Long. This gives us access to a lot of predefined methods that perform queries behind the scenes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 3:&lt;/strong&gt; The query that we want to execute here is to find one user from that table with a specific activation key. In traditional SQL, it would be SELECT * FROM USER WHERE ACTIVATION_KEY = “key_value”. But with Spring Data JPA, we can write it as findOneByActivationKey(String activationKey). How does this work? Remember when we defined the columns, we specified the activation key as String. This allows Spring Data JPA to enable this method for us. One calling this method with a key as an argument, it will return a User entity if they exist otherwise null.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Testing using jUnit5&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If you’re a Java developer, you must be familiar with jUnit testing. With jUnit 5, they’ve brought about some good additions to make it easier for testing your code. A new addition is the @BeforeEach annotation which you can see in action below.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@BeforeEach
public void initTest() {
    user = initTestUser(userRepository, em);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://beta.quod.ai/github/jhipster/jhipster-sample-app/answers/details?open_file=src%2Ftest%2Fjava%2Fio%2Fgithub%2Fjhipster%2Fsample%2Fweb%2Frest%2FUserResourceIT.java&amp;amp;state=%7B%22src%2Ftest%2Fjava%2Fio%2Fgithub%2Fjhipster%2Fsample%2Fweb%2Frest%2FUserResourceIT.java%22%3A%7B%22range%22%3A%7B%22lineFrom%22%3A116%2C%22lineTo%22%3A119%7D%2C%22activeQuestionId%22%3A1385%7D%7D"&gt;UserTest.java&lt;/a&gt; in context at &lt;a href="https://quod.ai"&gt;Quod AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1-3:&lt;/strong&gt; The first line marks the following method to be done before each test case. The initTest() method calls another method initTestUser() in the test file passing in the repository object and the entity manager object. This is then used to create a mock object for the user for all the test cases.&lt;/p&gt;

&lt;p&gt;Another great new addition is that of lambda functions within test cases. Below is an example of using lambda functions in our test cases. Don’t worry about the logic present here. It simply gets the size of the database before the user is deleted, performs the deletion operation, and checks whether the size has decreased by 1.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Test
@Transactional
void deleteUser() throws Exception {
    // Initialize the database
    userRepository.saveAndFlush(user);
    int databaseSizeBeforeDelete = userRepository.findAll().size();


    // Delete the user
    restUserMockMvc
        .perform(delete("/api/admin/users/{login}", user.getLogin()).accept(MediaType.APPLICATION_JSON))
        .andExpect(status().isNoContent());


    assertThat(cacheManager.getCache(UserRepository.USERS_BY_LOGIN_CACHE).get(user.getLogin())).isNull();


    // Validate the database is empty
    assertPersistedUsers(users -&amp;gt; assertThat(users).hasSize(databaseSizeBeforeDelete - 1));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://beta.quod.ai/github/jhipster/jhipster-sample-app/answers/details?open_file=src%2Ftest%2Fjava%2Fio%2Fgithub%2Fjhipster%2Fsample%2Fweb%2Frest%2FUserResourceIT.java&amp;amp;state=%7B%22src%2Ftest%2Fjava%2Fio%2Fgithub%2Fjhipster%2Fsample%2Fweb%2Frest%2FUserResourceIT.java%22%3A%7B%22range%22%3A%7B%22lineFrom%22%3A472%2C%22lineTo%22%3A488%7D%2C%22activeQuestionId%22%3A1505%7D%7D"&gt;DeleteUserTest.java&lt;/a&gt; in context at &lt;a href="https://quod.ai"&gt;Quod AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1-2:&lt;/strong&gt; Denotes that this is a test case. @Transactional specifies that the following method will perform a database transaction and it will need to satisfy certain rules like not allowing updates if it gets cancelled in between, and ensuring that the database state is stable before and after the operation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 5-6:&lt;/strong&gt; We initialize the database here and then get the number of users present in the database. This is stored in the variable databaseSizeBeforeDelete.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 9-12:&lt;/strong&gt; We then perform the delete operation on the user which accepts JSON input and the expected status is that of no content.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 13-16:&lt;/strong&gt; Here we check two things. One is that we assert that the user is not present in the cache. Second, we assert that the database size has decreased by 1. If you see Line 16, you can also see the use of a lambda function to do the same, which was previously not possible with jUnit.&lt;/p&gt;

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

&lt;p&gt;We hope that this post gave you an insight into JHipster and some of the concepts behind building a Spring Boot application. Don’t stop here, the repository contains a lot more than you can explore and use to evolve your application.&lt;/p&gt;

&lt;p&gt;Quod AI is code search and navigation on steroids. We turn git repositories into documentation that developers actually use. Do follow us on Twitter &lt;a href="https://twitter.com/quod_ai"&gt;@quod_ai&lt;/a&gt; for updates on our product and DEVs community content. Check our app at: &lt;a href="http://beta.quod.ai/"&gt;beta.quod.ai&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>jhipster</category>
      <category>java</category>
      <category>springboot</category>
      <category>microservices</category>
    </item>
    <item>
      <title>How to structure your Flask apps using cookiecutter</title>
      <dc:creator>Quod AI</dc:creator>
      <pubDate>Wed, 21 Apr 2021 01:18:20 +0000</pubDate>
      <link>https://dev.to/quod_ai/how-to-structure-your-flask-apps-using-cookiecutter-51dk</link>
      <guid>https://dev.to/quod_ai/how-to-structure-your-flask-apps-using-cookiecutter-51dk</guid>
      <description>&lt;p&gt;Today’s article is all about cookiecutter. If you are a Python fanatic, you might’ve already heard of cookiecutter and possibly even have used it. It is a command-line tool that allows you to create boilerplate application code with a few simple steps.&lt;/p&gt;

&lt;p&gt;This article was originally posted at: &lt;a href="https://www.quod.ai/post/how-to-structure-your-flask-apps-using-cookiecutter" rel="noopener noreferrer"&gt;https://www.quod.ai/post/how-to-structure-your-flask-apps-using-cookiecutter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will see how we can use cookiecutter to create a demo flask project and go through some of the important concepts present in the cookiecutter flask project. The topics we will cover today are listed below.&lt;/p&gt;

&lt;p&gt;●   Installing cookiecutter and setting up the project&lt;/p&gt;

&lt;p&gt;●       Flask-SQLAlchemy with a basic User model&lt;/p&gt;

&lt;p&gt;●       Easy database migrations with Flask-Migrate&lt;/p&gt;

&lt;p&gt;●       pytest and Factory-Boy for testing&lt;/p&gt;

&lt;p&gt;●       Configuration using environment variables&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Installing cookiecutter and setting up the project&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Installing cookiecutter is the easiest thing that you can do. Just run over to your command line and use the following command.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install cookiecutter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This will install cookiecutter in your system. Today, we are going to take a look at a sample flask-restful project. For importing this to your system, you can use the following command from the command line:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cookiecutter https://github.com/QuodAI/tutorial-cookiecutter-flask-restful.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This will set up the basic project in your system. The folder will be stored under the path:&lt;/p&gt;

&lt;p&gt;/users/your_user/.cookiecutters&lt;/p&gt;

&lt;p&gt;Now, run the following command to install all the required dependencies.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install -r requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;There you have it, your basic flask-restful project is set up and ready to be used. Now, we will go through some of the important concepts that are detailed within that project. Below we have the file structure of the cookiecutter project. The ones that have been highlighted are the main directories that we will be looking at, but some of the others would also be linked internally.&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F60794f72c79f13ecfcba0238_Screenshot%25202021-04-16%2520at%25204.37.29%2520PM.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F60794f72c79f13ecfcba0238_Screenshot%25202021-04-16%2520at%25204.37.29%2520PM.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Flask-SQLAlchemy with a basic User model&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;The flask-sqlalchemy library adds sqlalchemy support for your flask application. SQLAlchemy is a very popular ORM (Object Relational Mapper) that allows you to integrate the SQL capabilities into your application.&lt;/p&gt;

&lt;p&gt;Below, we have a very simple User model that is created using Flask-SQLAlchemy.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from sqlalchemy.ext.hybrid import hybrid_property
from tutorial-cookiecutter-restful.extensions import db, pwd_context
class User(db.Model):
    """Basic user model"""
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(80), unique=True, nullable=False)
    _password = db.Column("password", db.String(255), nullable=False)
    active = db.Column(db.Boolean, default=True)
    @hybrid_property
    def password(self):
        return self._password
    @password.setter
    def password(self, value):
        self._password = pwd_context.hash(value)
    def __repr__(self):
        return "" % self.username
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://beta.quod.ai/github/aswinrajeevofficial/tutorial-cookiecutter-flask-restful/answers/details?open_file=tutorial-cookiecutter-restful%2Fmodels%2Fuser.py&amp;amp;state=%7B%22tutorial-cookiecutter-restful%2Fmodels%2Fuser.py%22%3A%7B%22range%22%3A%7B%22lineFrom%22%3A1%2C%22lineTo%22%3A26%7D%2C%22activeQuestionId%22%3A59%7D%7D" rel="noopener noreferrer"&gt;user.py&lt;/a&gt; in context at &lt;a href="https://quod.ai" rel="noopener noreferrer"&gt;Quod AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1-2:&lt;/strong&gt; We import the hybrid-property from SQLAlchemy and the db and pwd_context from our extensions. The hybrid property depicts that a particular value would have different behaviors based on the context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 3:&lt;/strong&gt; This is a class we are going to create and we pass the db.Model base class to it. This base class instance is created when we initialize SQLAlchemy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 5-9:&lt;/strong&gt; These lines are used to declare the columns and their properties. We have 5 columns in the table, namely id, username, email, password, and active. The db.Column class is used to denote a column and the other classes denote datatypes. The unique property denotes that it will be a unique value and the nullable property denotes that it cannot be set to null or not depending on the boolean.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 10-17:&lt;/strong&gt; We have a getter for the password that returns the password and we also have a setter that takes in the value and generates a hashed version of it using pwd_context import from extensions. This uses an SHA-256 to generate a hashed value. The last method is a general method that is used to represent the value of the particular type, in our case a user, with a simple string.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Easy database migrations with Flask-Migrate&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Flask-Migrate is a flask extension that allows for easy db migrations through SQLAlchemy. To set up Flask-Migrate and start using it, we can follow the below code snippet.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def configure_extensions(app):
    """configure flask extensions"""
    db.init_app(app)
    jwt.init_app(app)
    migrate.init_app(app, db)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://beta.quod.ai/github/aswinrajeevofficial/tutorial-cookiecutter-flask-restful/answers/details?open_file=tutorial-cookiecutter-restful%2Fapp.py&amp;amp;state=%7B%22tutorial-cookiecutter-restful%2Fapp.py%22%3A%7B%22range%22%3A%7B%22lineFrom%22%3A25%2C%22lineTo%22%3A30%7D%2C%22activeQuestionId%22%3A33%7D%7D" rel="noopener noreferrer"&gt;migrate_config.py&lt;/a&gt; in context with &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuploads-ssl.webflow.com%2F5e5cb288c9fe845aa6a23577%2F5e61cf317b1e836191d1e928_icon-32px.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%2Fuploads-ssl.webflow.com%2F5e5cb288c9fe845aa6a23577%2F5e61cf317b1e836191d1e928_icon-32px.png"&gt;&lt;/a&gt;&lt;strong&gt;&lt;a href="https://quod.ai" rel="noopener noreferrer"&gt;Quod AI&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1-5:&lt;/strong&gt; The above code snippet shows how we can configure db migrations with Flask-Migrate. We are assuming that the app is already created in this case and passed as an argument to this function. It will initialize an SQLAlchemy instance passing the app as an argument. This db instance will be used for the migrations by calling the init_app function present inside Flask-Migrate passing in the app instance and the db instance we created earlier.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;PyTest and Factory-Boy for Testing&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Factory-Boy and PyTest are used in conjunction for testing. Factory-Boy is basically a library that allows you to get an instance of a particular class. It contains a model attribute under a Meta class that describes for which class the factory is being created. Below is the creation of a factory for the User class.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import factory
from tutorial-cookiecutter-restful.models import User
class UserFactory(factory.Factory):
    username = factory.Sequence(lambda n: "user%d" % n)
    email = factory.Sequence(lambda n: "user%d@mail.com" % n)
    password = "mypwd"
    class Meta:
        model = User
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://beta.quod.ai/github/aswinrajeevofficial/tutorial-cookiecutter-flask-restful/answers/details?open_file=tests%2Ffactories.py&amp;amp;state=%7B%22tests%2Ffactories.py%22%3A%7B%22range%22%3A%7B%22lineFrom%22%3A1%2C%22lineTo%22%3A14%7D%2C%22activeQuestionId%22%3A15%7D%7D" rel="noopener noreferrer"&gt;factories.py&lt;/a&gt; in context at &lt;a href="https://quod.ai" rel="noopener noreferrer"&gt;Quod AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1-2&lt;/strong&gt;: We import the factory library and the User model for which we are creating a factory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 3-6:&lt;/strong&gt; We create a class called UserFactory and pass in the factory.Factory subclass. Note that the username and email fields have the Sequence class from factory invoked. This is to create unique instances each time with different values of username and email. The password is set to ‘mypwd’.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 7-8:&lt;/strong&gt; We then have a Meta class with the model attribute set to User which finalizes the creation of the UserFactory. This can now be used to get instances of User for testing.&lt;/p&gt;

&lt;p&gt;Below, we have the test case for getting all users. To test a test case in Python, we can use the pytest library and use the pytest command from the command line.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def test_get_all_user(client, db, user_factory, admin_headers):
    users_url = url_for('api.users')
    users = user_factory.create_batch(30)
    db.session.add_all(users)
    db.session.commit()
    rep = client.get(users_url, headers=admin_headers)
    assert rep.status_code == 200
    results = rep.get_json()
    for user in users:
        assert any(u["id"] == user.id for u in results["results"])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://beta.quod.ai/github/aswinrajeevofficial/tutorial-cookiecutter-flask-restful/answers/details?open_file=tests%2Ftest_user.py&amp;amp;state=%7B%22tests%2Ftest_user.py%22%3A%7B%22range%22%3A%7B%22lineFrom%22%3A89%2C%22lineTo%22%3A102%7D%2C%22activeQuestionId%22%3A83%7D%7D" rel="noopener noreferrer"&gt;test_user.py&lt;/a&gt; in context with &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuploads-ssl.webflow.com%2F5e5cb288c9fe845aa6a23577%2F5e61cf317b1e836191d1e928_icon-32px.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%2Fuploads-ssl.webflow.com%2F5e5cb288c9fe845aa6a23577%2F5e61cf317b1e836191d1e928_icon-32px.png"&gt;&lt;/a&gt;&lt;strong&gt;&lt;a href="https://quod.ai" rel="noopener noreferrer"&gt;Quod AI&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1:&lt;/strong&gt; This line declares the function with all the required arguments. Note that we are passing in the user_factory we created earlier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 2-3:&lt;/strong&gt; We then set the URL to get all the users. Then create a batch of 30 users using Factory-Boy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 4-5:&lt;/strong&gt; Next step is to all the users to the db session and commits all of the users that we created.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 6-10:&lt;/strong&gt; We then call the get method on the URL created before passing in the admin headers to get a response. If it is 200, the test proceeds further. Next step, we loop through the response and match the user ids with the user ids present inside the users variable we created.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Configuration using environment variables&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;The project houses a file called .flaskenv that stores all the configuration information needed through environment variables that are accessed within the program.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var server = require("net").createServer();
var io = require("socket.io")(server);


var handleClient = function (socket) {
    socket.emit("message", {msg: "Hello World"});
};


io.on("connection", handleClient);


server.listen(4000);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Line 1:&lt;/strong&gt; This sets up the environment for the flask app.   &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 2:&lt;/strong&gt; This tells Flask how to load the application. The create_app factory is called that is present within the folder tutorial-cookiecutter-restful.app&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 3:&lt;/strong&gt; The SECRET_KEY variable is used to generate the JWT tokens&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 4:&lt;/strong&gt; The database URI for the SQLite in-memory database is present here.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;That’s it for this one. We have gone through some of the concepts surrounding cookiecutter and how you can structure your next flask-restful app. Happy Coding!&lt;/p&gt;

&lt;p&gt;Quod AI is code search and navigation on steroids. We turn git repositories into documentation that developers actually use. Do follow us on Twitter &lt;a href="https://twitter.com/quod_ai" rel="noopener noreferrer"&gt;@quod_ai&lt;/a&gt; for updates on our product and DEVs community content. Check our app at: &lt;a href="http://beta.quod.ai/" rel="noopener noreferrer"&gt;beta.quod.ai&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>flask</category>
      <category>cookiecutter</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How GraphQL works in the real world, a deep dive into Spectrum chat</title>
      <dc:creator>Quod AI</dc:creator>
      <pubDate>Fri, 09 Apr 2021 08:40:53 +0000</pubDate>
      <link>https://dev.to/quod_ai/how-graphql-works-in-the-real-world-a-deep-dive-into-spectrum-chat-13bn</link>
      <guid>https://dev.to/quod_ai/how-graphql-works-in-the-real-world-a-deep-dive-into-spectrum-chat-13bn</guid>
      <description>&lt;p&gt;If you're a web developer, there’s a high chance that you’ve already heard of GraphQL. It completely changed the landscape of how APIs are queried and is growing at a tremendous pace with wider adoption from the developer community.&lt;/p&gt;

&lt;p&gt;This article was originally posted at &lt;a href="https://www.quod.ai/post/how-graphql-works-in-the-real-world-a-deep-dive-into-spectrum-chat"&gt;https://www.quod.ai/post/how-graphql-works-in-the-real-world-a-deep-dive-into-spectrum-chat&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The specification for GraphQL was written by the folks over at Facebook and they implemented a JavaScript version of it, but now we have several implementations in several different languages. It is a query language (similar to SQL) that gives clients the power to request exactly what they want from an API and GraphQL does the magic for you. You might be wondering what the magic is. Today, we will be looking at just that.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Objectives&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;In this post, we will get into all the basic concepts behind GraphQL and what makes it a great solution for better web applications.&lt;/p&gt;

&lt;p&gt;1.     Intro to GraphQL&lt;/p&gt;

&lt;p&gt;2.     GraphQL Concepts&lt;/p&gt;

&lt;p&gt;a.     Schema&lt;/p&gt;

&lt;p&gt;b.     Type&lt;/p&gt;

&lt;p&gt;c.      Queries, Resolvers, Mutations&lt;/p&gt;

&lt;p&gt;3.     GraphQL using Spectrum&lt;/p&gt;

&lt;p&gt;a.     Spectrum Introduction&lt;/p&gt;

&lt;p&gt;b.     Queries in Action  &lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Intro to GraphQL&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;As we wrote in the introduction, GraphQL was developed at Facebook. The specification was initially used in house, but they open sourced it. Now, there are several implementations of the specification in various different languages. GraphQL is a query language that sits in front of your API and integrates well with almost anything that you have. It is strongly typed, and expects you to know exactly what you want and it will give back clean, and concise results. Unlike REST APIs, GraphQL only has one single endpoint that does all the work. For instance, if you wanted to delete a product in your application, a REST endpoint would look something like this: &lt;strong&gt;/api/product/{id}&lt;/strong&gt; and the type of request would be &lt;strong&gt;DELETE&lt;/strong&gt;. If you had to buy a new product, there would be another endpoint like &lt;strong&gt;/api/product/buy&lt;/strong&gt; and the type of request would be &lt;strong&gt;POST&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In GraphQL, we have a single endpoint and almost always, it is a &lt;strong&gt;POST&lt;/strong&gt; request, that contains exactly what is to be sent back from the server. The request body determines what the server will send back, unlike in REST, where the server decides what to send. Before we use some of the terms in GraphQL, let’s take a look at high level concepts in more detail.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;GraphQL concepts&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;If you ever have to have a discussion over GraphQL, these 5 terms would be of utmost importance. The beautiful thing about GraphQL is that it is very simple to get started with, but is so complex that you can never stop learning it.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Schema&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A GraphQL schema dictates how the resources will be structured and organized and how the client can query them. You can think of a GraphQL schema as a DB schema, but for APIs. These schemas let you know what resources are available for querying and the way you need to query them.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Type&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;We have two kinds of types in GraphQL. They are scalar types and object types. Scalar types are similar to primitive data types and every field in a type should eventually run down to this. For instance, there can be an Object type called &lt;strong&gt;User&lt;/strong&gt; with a field that references another Object type called &lt;strong&gt;Student&lt;/strong&gt;, and so on. But the field that is referenced last will and should have scalar types. The scalar types available in GraphQL are: &lt;strong&gt;String, Int, Float, Boolean, ID&lt;/strong&gt; (which is another String, but ensures uniqueness). Let’s look at a few sample types in GraphQL.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  type Message @cacheControl(maxAge: 600) {
    id: ID!
    timestamp: Date!
    thread: Thread
    content: MessageContent!
    author: ThreadParticipant! @cost(complexity: 2)
    reactions: ReactionData @cost(complexity: 1)
    messageType: MessageTypes!
    parent: Message
    modifiedAt: Date
    bot: Boolean
    sender: User! @deprecated(reason: "Use Message.author field instead")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Line 1:&lt;/strong&gt; This line has the keyword type to denote that it is a type followed by the name of the type, which is Message.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Line 2-12:&lt;/strong&gt; These lines contain fields present inside the message type. You can see that we have a combination of scalar as well as Object types within the &lt;strong&gt;Message&lt;/strong&gt; type. The fields &lt;strong&gt;id&lt;/strong&gt; and &lt;strong&gt;bot&lt;/strong&gt; are scalars. The rest of the fields are Object types. The &lt;strong&gt;‘!’&lt;/strong&gt; mark next to the type tells that it is a non-nullable field.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Queries, mutations and resolvers&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Queries&lt;/strong&gt; - Queries in GraphQL determine what the client can access. In other words, it defines what your API can return.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mutations&lt;/strong&gt; - Mutations are queries that perform some changes to the data itself, therefore the name mutation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resolvers&lt;/strong&gt; - In a traditional web application, we have controllers that route the request from the frontend to the server endpoint. Resolvers are basically like your controllers in a REST API. They are functions that return values for the different fields that are present in your type.&lt;/p&gt;

&lt;p&gt;In just a bit, we will be looking at code that will showcase all these concepts in action.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;GraphQL using Spectrum&lt;/strong&gt;
&lt;/h1&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Spectrum Introduction&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To look at some GraphQL code, we will explore Spectrum chat. Spectrum is a community-based chat platform that gives additional functionalities like direct messaging, group messaging, ability to subscribe/unsubscribe to/from topics and specific chats. Spectrum is, however, moving over to GitHub Discussions and they don’t allow the creation of new communities anymore. By August 10, 2021, Spectrum will be completely archived and made read-only. This doesn’t stop us from going over some open-sourced code, does it?&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Queries in Action&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now, let’s look at some of the queries in action which will incorporate most of the concepts that we covered before.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;getMessageById - Query&lt;/strong&gt;
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const getMessageByIdQuery = gql`
  query getMessageById($id: ID!) {
    message(id: $id) {
      ...messageInfo
    }
  }
  ${messageInfoFragment}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://beta.quod.ai/github/withspectrum/spectrum/answers/details?open_file=shared%2Fgraphql%2Fqueries%2Fmessage%2FgetMessage.js&amp;amp;state=%7B%22shared%2Fgraphql%2Fqueries%2Fmessage%2FgetMessage.js%22%3A%7B%22range%22%3A%7B%22lineFrom%22%3A2%2C%22lineTo%22%3A32%7D%2C%22activeQuestionId%22%3A1387%7D%7D"&gt;getMessageByIdQuery.js&lt;/a&gt; in context at &lt;a href="https://quod.ai"&gt;Quod AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1-2:&lt;/strong&gt; The first two lines denote exporting a constant named getMessageByIdQuery and we assign it a GraphQL query that is preceded by the ‘query’ keyword. You can see that the gql template literal tag is used to write the GraphQL query. This is imported from the &lt;a href="https://www.npmjs.com/package/graphql-tag"&gt;graphql-tag&lt;/a&gt; library. If you notice, we have an argument id of type ID that is passed in as input to the query.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Line 3-7:&lt;/strong&gt; Inside the query, we have the messageInfo which is preceded by three dots (this is not the spread/rest operator of JS). These are used to refer fragments within the code. You might be wondering, what are &lt;a href="http://graphql.org/learn/queries/#fragments"&gt;fragments&lt;/a&gt;? It is basically a piece of code that can be shared between multiple queries/mutations. In this query, we return a message, when an id is passed as in input. The MessageInfo fragment contains all the other fields that are needed to be returned by the message which includes an id, timestamp, messageType, content and more.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;banUserMutation – Mutation&lt;/strong&gt;
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type BanUserInput = {
  userId: string,
  reason: string,
};


export const banUserMutation = gql`
  mutation banUser($input: BanUserInput!) {
    banUser(input: $input)
  }
`;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://beta.quod.ai/github/withspectrum/spectrum/answers/details?open_file=shared%2Fgraphql%2Fmutations%2Fuser%2FbanUser.js&amp;amp;state=%7B%22shared%2Fgraphql%2Fmutations%2Fuser%2FbanUser.js%22%3A%7B%22range%22%3A%7B%22lineFrom%22%3A2%2C%22lineTo%22%3A28%7D%2C%22activeQuestionId%22%3A5%7D%7D"&gt;banUserMutation.js&lt;/a&gt; in context at &lt;a href="https://quod.ai"&gt;Quod AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1-4:&lt;/strong&gt; Mutations are also queries, but instead of just reading data, it updates data. This particular mutation is for banning a user. The first four lines denote the input type that is required to be given as input to the mutation. It has two fields, one is the userId and the next is the reason for banning the user.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Line 6-10:&lt;/strong&gt; This shows the definition of the mutation itself, wherein we have the banUser mutation as the name which is preceded by the keyword ‘mutation’. It has a banUser field which takes in an input of the BanUserInput type we created above.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;getCommunityById – Query&lt;/strong&gt;
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const getMessageByIdQuery = gql`
  query getMessageById($id: ID!) {
    message(id: $id) {
      ...messageInfo
    }
  }
  ${messageInfoFragment}
`;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://beta.quod.ai/github/withspectrum/spectrum/answers/details?open_file=shared%2Fgraphql%2Fqueries%2Fuser%2FgetUser.js&amp;amp;state=%7B%22shared%2Fgraphql%2Fqueries%2Fuser%2FgetUser.js%22%3A%7B%22range%22%3A%7B%22lineFrom%22%3A2%2C%22lineTo%22%3A80%7D%2C%22activeQuestionId%22%3A3748%7D%7D"&gt;getCommunityByIdQuery.js&lt;/a&gt; in context at &lt;a href="https://quod.ai"&gt;Quod AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1-9:&lt;/strong&gt; Spectrum is all about communities and this particular query is used to retrieve a community by its id. Upon receiving an input id, this query returns two fragments, which are the communityInfo fragment and the communityMetaData fragment. You can check these two files under the following directory (spectrum/ shared/ graphql/ fragments/ community/ communityMetaData.js) and see the contents that are being returned by these two fragments.  &lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;With that, we have covered some ground in GraphQL and also seen some concepts in action using Spectrum. You can check out the code in the GitHub repo &lt;a href="https://github.com/withspectrum/spectrum"&gt;here&lt;/a&gt; and see the app in action over &lt;a href="https://spectrum.chat/"&gt;here&lt;/a&gt;. Quod AI is the smartest way to search and navigate. We turn git repositories into documentation that developers actually use. Do follow us on twitter &lt;a href="https://twitter.com/quod_ai"&gt;@quod_ai&lt;/a&gt; for updates on our product and DEVs community content. Check our app at: &lt;a href="http://beta.quod.ai/"&gt;beta.quod.ai&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>spectrum</category>
      <category>schemas</category>
      <category>queries</category>
    </item>
    <item>
      <title>Quod AI #2: Automatically discover code impact + easy tutorials</title>
      <dc:creator>Hervé Vũ Roussel</dc:creator>
      <pubDate>Wed, 07 Apr 2021 08:56:24 +0000</pubDate>
      <link>https://dev.to/quod_ai/quod-ai-2-automatically-discover-code-impact-create-easy-tutorials-6b</link>
      <guid>https://dev.to/quod_ai/quod-ai-2-automatically-discover-code-impact-create-easy-tutorials-6b</guid>
      <description>&lt;h1&gt;
  
  
  Automatically discover the impact of code
&lt;/h1&gt;

&lt;p&gt;3 years ago, I hired a new backend developer. He was bright and eager. I felt validated when he pushed his first ticket to production on his 2nd day... which crashed our platform for 3.5 hours when it was released. He had forgotten to update one of the property keys in a related file.&lt;br&gt;
​&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3t49tBH_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://downloads.intercomcdn.com/i/o/313578793/8b3607a3d3f8091f346b5557/cb-context-filter-sm.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3t49tBH_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://downloads.intercomcdn.com/i/o/313578793/8b3607a3d3f8091f346b5557/cb-context-filter-sm.gif" alt="https://downloads.intercomcdn.com/i/o/313578793/8b3607a3d3f8091f346b5557/cb-context-filter-sm.gif"&gt;&lt;/a&gt;&lt;br&gt;
​&lt;br&gt;
Our newest feature Code browser would saved my team from unhappy customer emails and disappointed looks from the sales team. Code browser features code in full context with file tree, impactful commits and code owner automatically. But our fan favorite feature is the ability to show related code in one click.&lt;/p&gt;


&lt;center&gt;&lt;strong&gt;​&lt;a href="https://beta.quod.ai/github/mayeaux/nodetube/search?initTerm=recover%2520password&amp;amp;rootRepo=github%252Fmayeaux%252Fnodetube&amp;amp;term=recover%2520password&amp;amp;product_tour_id=215726"&gt;Try code browser&lt;/a&gt;​&lt;/strong&gt;&lt;/center&gt;
&lt;h1&gt;
  
  
  An easier way to share code tutorials, guidelines, and more!
&lt;/h1&gt;

&lt;p&gt;​&lt;br&gt;
Stripe's API documentation is the best in the world. We took inspiration from it to build our new UX for collections. Share your code tutorials, guidelines, and more with your team. They'll enjoy our shiny new table of content.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KJjkGhVz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://downloads.intercomcdn.com/i/o/313578852/fb474555589635bc7032eeff/collections-view-auth.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KJjkGhVz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://downloads.intercomcdn.com/i/o/313578852/fb474555589635bc7032eeff/collections-view-auth.gif" alt="https://downloads.intercomcdn.com/i/o/313578852/fb474555589635bc7032eeff/collections-view-auth.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PS: I built this collection ☝ in 5 minutes!&lt;/p&gt;


&lt;center&gt;&lt;strong&gt;​&lt;a href="https://beta.quod.ai/github/GetStream/Winds/collections/GetStream%252Fauthentication"&gt;​Try collections​&lt;/a&gt;​&lt;/strong&gt;&lt;/center&gt;
&lt;h1&gt;
  
  
  Blog
&lt;/h1&gt;

&lt;p&gt;We've been busy writing articles for the productive and smart engineer.&lt;/p&gt;

&lt;p&gt;Check out our latest blog posts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.quod.ai/post/how-to-keep-developer-documentation-up-to-date-in-a-ci-cd-world"&gt;How to keep developer documentation up to date in a CI/CD world&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.quod.ai/post/integrating-push-notifications-with-firebase-java-api"&gt;Integrating Push Notifications with Firebase Java API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our reading list&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://keyholesoftware.com/2021/02/15/four-ways-to-put-developer-experience-first/?utm_source=programmingdigest&amp;amp;utm_medium=email&amp;amp;utm_campaign=410"&gt;Four Ways of Writing Thoughtful Code to Think Less&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
    </item>
    <item>
      <title>How NodeBB uses Socket.IO to write a real-time message board</title>
      <dc:creator>Quod AI</dc:creator>
      <pubDate>Mon, 05 Apr 2021 06:14:36 +0000</pubDate>
      <link>https://dev.to/quod_ai/how-nodebb-uses-socket-io-to-write-a-real-time-message-board-47g5</link>
      <guid>https://dev.to/quod_ai/how-nodebb-uses-socket-io-to-write-a-real-time-message-board-47g5</guid>
      <description>&lt;p&gt;NodeBB is one amazing off-the-shelve community platform for your onboarding requirements. Be it a brand community or a board for flawless product support to your customers – this solution is built perfectly for everything you need for forum management.&lt;/p&gt;

&lt;p&gt;such as:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Real-time interactions through private chats and message rooms;&lt;/li&gt;
&lt;li&gt;  Topics and replies for information-broadcasting;&lt;/li&gt;
&lt;li&gt;  Instant notifications to keep users engaged.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article was originally posted at: &lt;a href="https://www.quod.ai/post/how-nodebb-uses-socket-io-to-write-a-real-time-message-board"&gt;https://www.quod.ai/post/how-nodebb-uses-socket-io-to-write-a-real-time-message-board&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This GDPR-compliant next-gen community platform utilizes web sockets to enable interactive communication. As NodeBB has Node.js in its core, Socket.IO is a suitable pick for it. This library enables bi-directional communication in real-time and lets the browser &amp;amp; server communicate on the basis of events.  &lt;/p&gt;

&lt;p&gt;In this article, we will explain how NodeBB uses Socket.IO for its feature-rich real-time message board module in the community platform solution.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How NodeBB uses Socket.IO to write message boards?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Loading the real-time message board&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SocketModules.chats.loadRoom = async function (socket, data) {
    if (!data || !data.roomId) {
        throw new Error('[[error:invalid-data]]');
    }


    return await Messaging.loadRoom(socket.uid, data);
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://beta.quod.ai/github/NodeBB/NodeBB/answers/details?open_file=src%2Fsocket.io%2Fmodules.js&amp;amp;state=%7B%22src%2Fsocket.io%2Fmodules.js%22%3A%7B%22range%22%3A%7B%22lineFrom%22%3A103%2C%22lineTo%22%3A109%7D%2C%22activeQuestionId%22%3A4024%7D%7D"&gt;Modules.js&lt;/a&gt; in context at &lt;a href="https://quod.ai"&gt;Quod AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1:&lt;/strong&gt; The first step to using a message-board is, loading the chat rooms and rendering the list of previous chats. After initiation through Line 1, Socket.IO checks all the existing chats and the restrictions added for them. As per that, it loads the list of chats in the real-time message board. If there is no data or invalid data ID, an error message will be returned. Users will be able to click on each of the chats and open the chat window in NodeBB due to this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Initiating a New Private Chat&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SocketModules.chats.hasPrivateChat = async function (socket, uid) {
    if (socket.uid &amp;lt;= 0 || uid &amp;lt;= 0) {
        throw new Error('[[error:invalid-data]]');
    }
    return await Messaging.hasPrivateChat(socket.uid, uid);
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://beta.quod.ai/github/NodeBB/NodeBB/answers/details?open_file=src%2Fsocket.io%2Fmodules.js&amp;amp;state=%7B%22src%2Fsocket.io%2Fmodules.js%22%3A%7B%22range%22%3A%7B%22lineFrom%22%3A263%2C%22lineTo%22%3A268%7D%2C%22activeQuestionId%22%3A1809%7D%7D"&gt;Modules.js&lt;/a&gt; in context at &lt;a href="https://quod.ai"&gt;Quod AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1:&lt;/strong&gt; When someone chooses a user to start a chat, NodeBB uses Socket.IO to check if the user already has a private chat for the current request. On clicking a link that could trigger a private chat, Socket.IO fetches and returns messaging data, e.g., the chat room icon/user display picture, old messages, user names (for chat rooms) with their names as disabled or enabled, option to send messages (or disabled chat), etc. If there exist previous messages, it loads the existing messages in the chat box. At this stage, the message board also accesses the restrictions and opens/disables the private chat option for the selected user, or the chat room of users.&lt;strong&gt;‍&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;‍&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Chat room creation (New) and management&lt;/strong&gt;  &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SocketModules.chats.newRoom = async function (socket, data) {
    if (!data) {
        throw new Error('[[error:invalid-data]]');
    }


    if (rateLimitExceeded(socket)) {
        throw new Error('[[error:too-many-messages]]');
    }


    const canChat = await privileges.global.can('chat', socket.uid);
    if (!canChat) {
        throw new Error('[[error:no-privileges]]');
    }
    await Messaging.canMessageUser(socket.uid, data.touid);
    return await Messaging.newRoom(socket.uid, [data.touid]);
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://beta.quod.ai/github/NodeBB/NodeBB/answers/details?open_file=src%2Fsocket.io%2Fmodules.js&amp;amp;state=%7B%22src%2Fsocket.io%2Fmodules.js%22%3A%7B%22range%22%3A%7B%22lineFrom%22%3A45%2C%22lineTo%22%3A60%7D%2C%22activeQuestionId%22%3A3207%7D%7D"&gt;Modules.js&lt;/a&gt; in context at &lt;a href="https://quod.ai"&gt;Quod AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1:&lt;/strong&gt; The function in line 1 is responsible for the new chat room’s creation. When a new chat room is created, the admin must add a few details such as chat room name, chat room icon, and member list. If the admin has not added any member during the room creation or added itself only, it will see an error message and the chat room will not be created. Regarding the users with restrictions related to chat room/admin, there will be error messages, telling the reason why the selected user(s) is not added to the chat room.&lt;strong&gt;‍&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 10:&lt;/strong&gt; All the users will be assigned access rights and privileges, as set by the chat room admin. The same are being validated at line 10. Allowed users will be able to send messages in the room and perform operations as per their user role in the chat room. For example, administrators will be able to add/remove users from the chat room.&lt;/p&gt;

&lt;p&gt;This all is taken care of by Socket.IO in NodeBB.&lt;/p&gt;

&lt;p&gt;‍&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SocketModules.chats.leave = async function (socket, roomid) {
    if (!socket.uid || !roomid) {
        throw new Error('[[error:invalid-data]]');
    }


    await Messaging.leaveRoom([socket.uid], roomid);
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://beta.quod.ai/github/NodeBB/NodeBB/answers/details?open_file=src%2Fsocket.io%2Fmodules.js&amp;amp;state=%7B%22src%2Fsocket.io%2Fmodules.js%22%3A%7B%22range%22%3A%7B%22lineFrom%22%3A177%2C%22lineTo%22%3A183%7D%2C%22activeQuestionId%22%3A6406%7D%7D"&gt;Modules.js&lt;/a&gt; in context at &lt;a href="https://quod.ai"&gt;Quod AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 2:&lt;/strong&gt; Hare, it is checked if the ‘leave chat room’ request is legit or not. At this point, the following aspects are validated through Socket.IO:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  If the user has already left the chat room or if the user is not a part of the chat room;&lt;/li&gt;
&lt;li&gt;  If the user is the only administrator of the chat room;&lt;/li&gt;
&lt;li&gt;  If the invalid input is given to leave the chat room;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In these cases, the user will receive an error message and won’t be able to leave the chat room.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deleting Messages&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;it('should error out if a message is deleted again', (done) =&amp;gt; {
            socketModules.chats.delete({ uid: fooUid }, { messageId: mid, roomId: roomId }, (err) =&amp;gt; {
                assert.strictEqual('[[error:chat-deleted-already]]', err.message);
                done();
            });
        });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://beta.quod.ai/github/NodeBB/NodeBB/answers/details?open_file=test%2Fmessaging.js&amp;amp;state=%7B%22test%2Fmessaging.js%22%3A%7B%22range%22%3A%7B%22lineFrom%22%3A707%2C%22lineTo%22%3A712%7D%2C%22activeQuestionId%22%3A2729%7D%7D"&gt;Messaging.js&lt;/a&gt; in context at &lt;a href="https://quod.ai"&gt;Quod AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1:&lt;/strong&gt; From this line, the code for message deletion starts in the messaging.js file. During message deletion for all, Socket.IO checks if the user is trying to delete the already deleted messages. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  If so, an error message will be displayed. &lt;/li&gt;
&lt;li&gt;  If not, the visibility for selected messages, messages, or the whole chat will be checked. The Socket.IO module will make the messages hidden for everyone. So, no one will be able to view the messages. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While deleting the message(s) for self, the above will happen for the user making this request. In the NodeBB community, users and admins can restore the messages too.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Blocking a User/Leaving a chat room&lt;br&gt;&lt;br&gt;
*&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When a user blocks another person or leaves a chat room, the chat window in the real-time message board will be disabled from sending/receiving messages through Socket.IO in the NodeBB community. &lt;a href="https://github.com/NodeBB/NodeBB/blob/c953b1b3d123b2a66e6ea7e46e295de02767e974/test/messaging.js#L732-L762"&gt;Line 732-762&lt;/a&gt; has the code for this in the test/messaging.js file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Socket Event Listeners&lt;/strong&gt;  &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;messages.addSocketListeners = function () {
        socket.removeListener('event:chats.edit', onChatMessageEdited);
        socket.on('event:chats.edit', onChatMessageEdited);


        socket.removeListener('event:chats.delete', onChatMessageDeleted);
        socket.on('event:chats.delete', onChatMessageDeleted);


        socket.removeListener('event:chats.restore', onChatMessageRestored);
        socket.on('event:chats.restore', onChatMessageRestored);
    };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://beta.quod.ai/github/NodeBB/NodeBB/answers/details?open_file=public%2Fsrc%2Fclient%2Fchats%2Fmessages.js&amp;amp;state=%7B%22public%2Fsrc%2Fclient%2Fchats%2Fmessages.js%22%3A%7B%22range%22%3A%7B%22lineFrom%22%3A161%2C%22lineTo%22%3A170%7D%2C%22activeQuestionId%22%3A5121%7D%7D"&gt;Messaging.js&lt;/a&gt; in context at &lt;a href="https://quod.ai"&gt;Quod AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1:&lt;/strong&gt; From this line, starts the function that updates the deletion, restoration and editing of messages in the real-time. Socket event listeners are used for this purpose.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Receiving Messages and Read/Unread Message Marker and Counter&lt;/strong&gt;  &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;socket.onAny((event, ...args) =&amp;gt; {
        const payload = { data: [event].concat(args) };
        onMessage(socket, payload);
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://beta.quod.ai/github/NodeBB/NodeBB/answers/details?open_file=src%2Fsocket.io%2Findex.js&amp;amp;state=%7B%22src%2Fsocket.io%2Findex.js%22%3A%7B%22range%22%3A%7B%22lineFrom%22%3A74%2C%22lineTo%22%3A77%7D%2C%22activeQuestionId%22%3A448%7D%7D"&gt;Index.js&lt;/a&gt; in context at &lt;a href="https://quod.ai"&gt;Quod AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 3:&lt;/strong&gt; When the message arrives, it triggers the onMessage event in the real-time. With this the new message is added for the recipient to read and counters/message-status-markers are updated. Socket.IO uses a way to distinguish read and unread messages. When a message is read by recipient(s) on the message board, it is marked ‘read’. For unread messages, the unread-message counter is shown for each chat.&lt;strong&gt;‍&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;‍&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Handling Restrictions and Invalid Inputs&lt;/strong&gt;‍  &lt;/p&gt;

&lt;p&gt;For each user, there is a list of restrictions they have added. This may include the blocked users and parameters in settings.   &lt;/p&gt;

&lt;p&gt;When someone tries to initiate an action related to real-time messaging through NodeBB, Socket.IO is used for validating the inputs and confirming that there is no conflict in proceeding with the instruction.   &lt;/p&gt;

&lt;p&gt;For example: If a user is creating a Chat room and is trying to add someone who has blocked that user, there will be an error message. The selected person won’t be added to the chat room in this case.  &lt;/p&gt;

&lt;p&gt;Also, if a user is trying to add himself or herself to the chat room, the Socket.IO module returns an error.  &lt;/p&gt;

&lt;p&gt;Initiating or taking forward a private chat also requires that:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Both the users in conversation haven’t blocked each other;&lt;/li&gt;
&lt;li&gt;  Both users have active accounts with no messaging-related restrictions;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When do you need the Build-in Real-time Chat Functionality for your Community?&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;NodeBB message boards can be utilized for:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Discussions among teams regarding different projects;&lt;/li&gt;
&lt;li&gt;  To accept and address customers’ queries;&lt;/li&gt;
&lt;li&gt;  To let the community member discuss open-source projects;&lt;/li&gt;
&lt;li&gt;  To enable a seamless communication mode for the whole organization.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Is Socket.IO capable enough for your real-time message board?&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;Yes, Socket.IO is a reliable and secure choice for speedy communication. So, it is generally the best pick for real-time messaging and notifications. It works for all standard browsers, devices, and platforms. Overall, Socket.IO makes the best choice for the real-time message board in your NodeBB community.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Final Words&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;NodeBB uses Socket.IO for event-based communications in the community. Be it notifications or message boards, the platform utilizes this technology to ensure instant and reliable communication. If you are thinking of using a ready-made message board with multiple other capabilities for your community, NodeBB can be considered. Check out source code on Quod AI repository: &lt;a href="https://beta.quod.ai/github/NodeBB/NodeBB"&gt;https://beta.quod.ai/github/NodeBB/NodeBB&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;‍&lt;/p&gt;

&lt;p&gt;Quod AI is code search and navigation on steroids. We turn code into documentation that developers actually use. Do follow us on twitter &lt;a href="https://twitter.com/quod_ai"&gt;@quod_ai&lt;/a&gt; for updates on our product and DEVs community content. Check our app at: &lt;a href="https://beta.quod.ai/"&gt;beta.quod.ai&lt;/a&gt;‍&lt;/p&gt;

</description>
      <category>socketio</category>
      <category>realtime</category>
      <category>messages</category>
      <category>node</category>
    </item>
    <item>
      <title>How to integrate Facebook Login API into your React app</title>
      <dc:creator>Quod AI</dc:creator>
      <pubDate>Mon, 29 Mar 2021 03:52:44 +0000</pubDate>
      <link>https://dev.to/quod_ai/how-to-integrate-facebook-login-api-into-your-react-app-33de</link>
      <guid>https://dev.to/quod_ai/how-to-integrate-facebook-login-api-into-your-react-app-33de</guid>
      <description>&lt;p&gt;Today, we're going to learn how to integrate Facebook login API into your React app. Why do we need that? According to data from &lt;a href="https://id.oberlo.com/blog/facebook-statistics" rel="noopener noreferrer"&gt;oberlo&lt;/a&gt;, Facebook is one of the social media which has more than 2.8 billion active users every day. Where this number is spread across Facebook's main business, namely Facebook, WhatsApp, Instagram, and Messenger. &lt;/p&gt;

&lt;p&gt;One of the ways to attract new users to register is that users can easily register. By utilizing a large number of active users on Facebook and integrating Facebook login API into our website, it will increase the probability of increasing users on our website by simply doing one tap on sign up that are already integrated with existing accounts on Facebook.&lt;/p&gt;

&lt;p&gt;This article was originally posted at: &lt;a href="https://www.quod.ai/post/how-to-integrate-facebook-login-api-into-your-react-app" rel="noopener noreferrer"&gt;https://www.quod.ai/post/how-to-integrate-facebook-login-api-into-your-react-app&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Objectives&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In this tutorial, we will show you how to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Set up a Facebook App&lt;/li&gt;
&lt;li&gt; Create React.js App&lt;/li&gt;
&lt;li&gt; Install Package "react-facebook-login"&lt;/li&gt;
&lt;li&gt; Adding Facebook login to our React app&lt;/li&gt;
&lt;li&gt; Run React App to Facebook Login&lt;/li&gt;
&lt;li&gt; Run our React App to login with Facebook
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;1. Set up a Facebook App&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In this tutorial, we will use several frameworks, tools and modules as below.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Node.js. In this tutorial, we are using version 14.15.5. If you have not installed, you can download it from &lt;a href="https://nodejs.org/en/download/" rel="noopener noreferrer"&gt;https://nodejs.org/en/download/&lt;/a&gt;‍&lt;/li&gt;
&lt;li&gt; react-facebook-login package from npm (node package manager)&lt;/li&gt;
&lt;li&gt; React.js. We use version 17.0.1. Before create React App you must install “npx“ package. If you have not installed, you can following this website &lt;a href="https://www.npmjs.com/package/npx" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/npx&lt;/a&gt;‍&lt;/li&gt;
&lt;li&gt; Text Editor or IDE (We recommend using Visual Studio Code)&lt;/li&gt;
&lt;li&gt; Terminal 
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After all the requirement are available, we need to register as a Facebook Developer Apps. To register, we need to log in using your existing Facebook account at &lt;a href="https://developers.facebook.com/apps/" rel="noopener noreferrer"&gt;https://developers.facebook.com/apps/&lt;/a&gt; . If you haven't logged in to Facebook, you will be asked to enter your email or mobile number and password.&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d9105a1028217d4b69417_j2O1lyMYf2Q6aDi7EOYzadx4PNsJDloMjd6pZFnsizl1Y73WDcMZEKmcYNLC_WF5mPs243UUw5A5CfwwNlyWAF0Z5yiSwKKr3mJty3fvj_YR2WjD_iKWXvcYAYWQeQ3u3K4UYlR6aLMh8hardA.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d9105a1028217d4b69417_j2O1lyMYf2Q6aDi7EOYzadx4PNsJDloMjd6pZFnsizl1Y73WDcMZEKmcYNLC_WF5mPs243UUw5A5CfwwNlyWAF0Z5yiSwKKr3mJty3fvj_YR2WjD_iKWXvcYAYWQeQ3u3K4UYlR6aLMh8hardA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that, you will redirect to &lt;a href="https://developers.facebook.com" rel="noopener noreferrer"&gt;https://developers.facebook.com&lt;/a&gt; and click “Get Started” if the first you register at Facebook Developer Apps.&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d9105fcd5f68470dbbd99_bYadGVH08F94fx823XLIqHkM8H3bpgfNRB8wDWap1We45HhpgFbvQRd6eByqrQIMLVjcgz-fsOB27rrZKPtaBB4mQzjmuil9mZ1__D5gr7nlpC6HKmui0IfAWHbm9rnoRK05Yac6x-VGac7gtA.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d9105fcd5f68470dbbd99_bYadGVH08F94fx823XLIqHkM8H3bpgfNRB8wDWap1We45HhpgFbvQRd6eByqrQIMLVjcgz-fsOB27rrZKPtaBB4mQzjmuil9mZ1__D5gr7nlpC6HKmui0IfAWHbm9rnoRK05Yac6x-VGac7gtA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will be taken to the registration dashboard , and click “Continue”&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d9105371fba2bfe685cfe_zJrQJeh73G7xmJbAVuXgXim9Q8f6OFTzZ7sCT3XkI2If3EmSwPgffVfFuBRW04G4WH-BpaLEng-YNRq-OUgHTSw0qhZX_6DS336_t3nAp1lWuYNIWtVnitdeDrqrCjmtDLTFRY-lRPOnukRPHA.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d9105371fba2bfe685cfe_zJrQJeh73G7xmJbAVuXgXim9Q8f6OFTzZ7sCT3XkI2If3EmSwPgffVfFuBRW04G4WH-BpaLEng-YNRq-OUgHTSw0qhZX_6DS336_t3nAp1lWuYNIWtVnitdeDrqrCjmtDLTFRY-lRPOnukRPHA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fill container of Primary Email with your email other than the Facebook account email that has been registered&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d9105c3adedba254606e8_B0OCghrsYytSoMmpVcQl7vcEe0edl-uhFcJUNLpw0oN20M9mNM9OvsPKnYrULdYOlwwYIyZVeHBrfPbzFt482MKiMuj773coxMWl1YhCvhsbPCiR10askyVCZD_Ngn8WzqRn9Y4aSa1EdsTZ9w.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d9105c3adedba254606e8_B0OCghrsYytSoMmpVcQl7vcEe0edl-uhFcJUNLpw0oN20M9mNM9OvsPKnYrULdYOlwwYIyZVeHBrfPbzFt482MKiMuj773coxMWl1YhCvhsbPCiR10askyVCZD_Ngn8WzqRn9Y4aSa1EdsTZ9w.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will get an email code from Facebook. Fill that container with the code you got earlier.&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d910511a38ee785823f6b_eO27eYE_MBeYJZisCuVIomonnzKSBsJjtINn0-PldNyn1lf9b-Chk_ScD1FvCX7qWnO6nGx5klNCBWnzN2VtAVEGW4v_SGURKir4Bk-2lHd9teVIHGAL2AtOs1rCwA5WpQ2D7vNAY1wTQGLSOw.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d910511a38ee785823f6b_eO27eYE_MBeYJZisCuVIomonnzKSBsJjtINn0-PldNyn1lf9b-Chk_ScD1FvCX7qWnO6nGx5klNCBWnzN2VtAVEGW4v_SGURKir4Bk-2lHd9teVIHGAL2AtOs1rCwA5WpQ2D7vNAY1wTQGLSOw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choose as “Developer” and the press button “Complete and Registration”&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d9106c3adeda6d54606e9_b-Bta2iUooLH-v4mDMNKMsy_2ye3heV45JN6YYW9cnAgT40eiYKzYXar6VjA7F3QZRYzyGFMrU3v-jdSCEgFFbzrYfb-1JEOPfjqHZev4uIC4q-gXlsBcVCoBZpGcbtkKA_Ju9TpHx0kdHAWNQ.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d9106c3adeda6d54606e9_b-Bta2iUooLH-v4mDMNKMsy_2ye3heV45JN6YYW9cnAgT40eiYKzYXar6VjA7F3QZRYzyGFMrU3v-jdSCEgFFbzrYfb-1JEOPfjqHZev4uIC4q-gXlsBcVCoBZpGcbtkKA_Ju9TpHx0kdHAWNQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will be redirected to Facebook for the Developer dashboard&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d91060adcd2fb79c61db0__Z071WE63urQFa-4PxOcXyA7c7-lXuyKLhh5wVZ-aGTCi-kNKQ14CjETolcdXZbxEHVy_atIqzXBSasXWkleeRFJRbm4xze9wooJy77Mi1x5lUc-6HnM-t-j0eLA-nddvJTAW_a_M6Y9NIwDwA.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d91060adcd2fb79c61db0__Z071WE63urQFa-4PxOcXyA7c7-lXuyKLhh5wVZ-aGTCi-kNKQ14CjETolcdXZbxEHVy_atIqzXBSasXWkleeRFJRbm4xze9wooJy77Mi1x5lUc-6HnM-t-j0eLA-nddvJTAW_a_M6Y9NIwDwA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Press button “Create App” for create app in Facebook Developer.&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d9106344322eefaab1e0b_-W32dTa59xiNcpoBIwAexH5S77YXv3ypGPxu4hd2k4BOTUbBH4pHewf76agJjbfCjX5rMqvM4jcda9n4SjvwatEH02d-DWUHU42TIrMPdob1Hyj9pzuXp4acWId99bzvhqOKPlEsjS3l40BI6A.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d9106344322eefaab1e0b_-W32dTa59xiNcpoBIwAexH5S77YXv3ypGPxu4hd2k4BOTUbBH4pHewf76agJjbfCjX5rMqvM4jcda9n4SjvwatEH02d-DWUHU42TIrMPdob1Hyj9pzuXp4acWId99bzvhqOKPlEsjS3l40BI6A.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choose “Build Connected Experiences” and the press button “Continue”&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d9106f19c3d4598d01cb3_cmSzbmyUyW80dQeOAAyPskDNiwtmGUl86EolamN7u2Llpcp6wXsEZt7_GUrCSQ4YibPM4P-K60Y0VFOW7QXL_QG6nZp4nhnyZ8Gtsjj1-o_ZzlnKXctB_W98DGEgCWuOui0MpSxxDuYg7ZzEig.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d9106f19c3d4598d01cb3_cmSzbmyUyW80dQeOAAyPskDNiwtmGUl86EolamN7u2Llpcp6wXsEZt7_GUrCSQ4YibPM4P-K60Y0VFOW7QXL_QG6nZp4nhnyZ8Gtsjj1-o_ZzlnKXctB_W98DGEgCWuOui0MpSxxDuYg7ZzEig.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fill the App Display Name with what you want to name this app and your email that was previously registered. In this tutorial we use the name “React_Login”. After that, press the button “Create App”.&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d91069249bd00dddd3dee_zts8LZW3ZcjL66oRmBZ6WrMYcFqIAZWEIZ9V1RrkFQHsK4b5YV-v_Ugy7o6knaMXRjx1xnyH97UmGTRGhxPnQyXdFJElIUI4eC4sEG9TIIKdb7aQKqlqLp_In_Q5QFr8ZzaT718UfOElmioOqQ.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d91069249bd00dddd3dee_zts8LZW3ZcjL66oRmBZ6WrMYcFqIAZWEIZ9V1RrkFQHsK4b5YV-v_Ugy7o6knaMXRjx1xnyH97UmGTRGhxPnQyXdFJElIUI4eC4sEG9TIIKdb7aQKqlqLp_In_Q5QFr8ZzaT718UfOElmioOqQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After checking the captcha dialog and click submit button, we will be redirected to the Facebook Application Dashboard.&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d9106370911682cc4074f_09CKIjz9VF5Ux3avqyBit2v5pj3IWD3nz4qOM8zG_KhC256xMSKT_ZUKX4XOBnQnvvfS7XWEYEIJpRRBh2KJE6nikQffq88hQtURaMcrw8qgrvsdgHNvGIbJ3Jrl-6m8VgibNe7DASK6SmEUlQ.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d9106370911682cc4074f_09CKIjz9VF5Ux3avqyBit2v5pj3IWD3nz4qOM8zG_KhC256xMSKT_ZUKX4XOBnQnvvfS7XWEYEIJpRRBh2KJE6nikQffq88hQtURaMcrw8qgrvsdgHNvGIbJ3Jrl-6m8VgibNe7DASK6SmEUlQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;2. Create React.js App&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To create a React project we use the command line or CLI. Referring to the &lt;a href="https://reactjs.org/docs/create-a-new-react-app.html#gatsby-focus-wrapper" rel="noopener noreferrer"&gt;https://reactjs.org/docs/create-a-new-react-app.html#gatsby-focus-wrapper&lt;/a&gt;, we can create a React project with the command  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;npx create-react-app react-fb_login  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This command works by downloading the latest React Js template from the repository. Or we can also download the React Js template and place it globally on our computer, so that every time we create a new React project we don't need to download it from the repository. The command line is as follows.  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;npm install -g create-react-app&lt;br&gt;&lt;br&gt;
create-react-app react-fb_login  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Next, go to “ react-fb_login ” folder and open the project in your IDE or Text Editor. Below is the template structure for our React application&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d9134ad60204fbc70c216_1bdnaSJMsY_mI7fttHj-amuCOVXwjQ7rhyJrgrnF8KcJLlieIQidT_vXd5on9ukMQcMcSspt-kY4MTaCzm6rg_oOr7HifGBH15SX58sKHZOJgd8ncXhRJDW2rqzI0CFlGxcgpiJw.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d9134ad60204fbc70c216_1bdnaSJMsY_mI7fttHj-amuCOVXwjQ7rhyJrgrnF8KcJLlieIQidT_vXd5on9ukMQcMcSspt-kY4MTaCzm6rg_oOr7HifGBH15SX58sKHZOJgd8ncXhRJDW2rqzI0CFlGxcgpiJw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also see "package.json" in our React project folder to see what packages are installed by default and the versions of the packages.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "name": "default_react",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.11.9",
    "@testing-library/react": "^11.2.5",
    "@testing-library/user-event": "^12.8.0",
    "react": "^17.0.1",
    "react-dom": "^17.0.1",
    "react-scripts": "4.0.3",
    "web-vitals": "^1.1.0"
  },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We can run our React project which is the default design template for create-react-app. To run, we only need to call this command in the terminal, where previously we have directed our terminal into our React project folder (react_fb_login).  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;npm start&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By default the React app runs on localhost with port 3000.&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d91cead09bdd3d0e8bea6_xfeYmHLYS-sfF7Ei69KRnx7OQL_8IGP_Jm70fLm7OvE7q_KXsNwM8R_wfp_JZJDz0uakA-SaNedlBShMpLKTwHTlkr0fCQTAIfPEsIYDF0HuLIcN40oZK9TlFn7ELTjQu_je3l3tpnaulV2coQ.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d91cead09bdd3d0e8bea6_xfeYmHLYS-sfF7Ei69KRnx7OQL_8IGP_Jm70fLm7OvE7q_KXsNwM8R_wfp_JZJDz0uakA-SaNedlBShMpLKTwHTlkr0fCQTAIfPEsIYDF0HuLIcN40oZK9TlFn7ELTjQu_je3l3tpnaulV2coQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;3. Install the “ react-facebook-login ” library&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In this tutorial we will be using the "react-facebook-login" package / modules / library which we will be installed in our React application project. To install this library we just need to use the command below in the terminal from our project directory.  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;npm install react-facebook-login&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After the install is complete, we will see the “ react-facebook-login ” package has been added to the package.json file.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "name": "default_react",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.11.9",
    "@testing-library/react": "^11.2.5",
    "@testing-library/user-event": "^12.8.0",
    "react": "^17.0.1",
    "react-bootstrap": "^1.5.1",
    "react-dom": "^17.0.1",
    "react-facebook-login": "^4.1.1",
    "react-scripts": "4.0.3",
    "web-vitals": "^1.1.0"
  },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We need to set up our React app project to running with HTTPS. This is because currently Facebook Login need to use HTTPS. To set this up, we need to replace the script of "start"  in our packagae.json file with the start script below. The packagae.json file is in the directory "react-fb_login/package.json "&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"start": "HTTPS=true react-scripts start",  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  "scripts": {
    "start": "HTTPS=true react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;‍&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Adding Facebook login to our React app&lt;/strong&gt;  &lt;/p&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState } from 'react';
import FacebookLogin from 'react-facebook-login';
import { Card, Image } from 'react-bootstrap';
import './App.css';


function App() {


  const [login, setLogin] = useState(false);
  const [data, setData] = useState({});
  const [picture, setPicture] = useState('');


  const responseFacebook = (response) =&amp;gt; {
    console.log(response);
    setData(response);
    setPicture(response.picture.data.url);
    if (response.accessToken) {
      setLogin(true);
    } else {
      setLogin(false);
    }
  }


  return (



          {!login &amp;amp;&amp;amp;

          }
          {login &amp;amp;&amp;amp;

          }

        {login &amp;amp;&amp;amp;

            {data.name}

              {data.email}


        }


  );
}


export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://github.com/ghozalihadi/SoftwareEngineeringBlog" rel="noopener noreferrer"&gt;App.js&lt;/a&gt; in context at &lt;a href="https://quod.ai" rel="noopener noreferrer"&gt;Quod AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1-4:&lt;/strong&gt; We are calling all the libraries needed to build our React app project, including calling the react-facebook-login, react-bootstrap and react libraries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 26-39:&lt;/strong&gt; We use the FacebookLogin component from the react-facebook-login library to login to Facebook. This library makes it easy for us to configure our React app to log into Facebook. In this component we need to add the appId (appId="") that we got from the dashboard at Facebook Developer.&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d9496a26f6817729fa643_Aw_solqDQizvOzknTp_Zeddx8-Dkm3HwVr_o9h7_fQ0p92yq6kxPRlIN-z0F0OV5ERJFUL9RqXRv8d5jKOHJu2h8xbuModB7pcVkd_rZCHffP0KwexXr_VPk1tvfZ0HQoq3SRTq2QEeyyoxybg.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d9496a26f6817729fa643_Aw_solqDQizvOzknTp_Zeddx8-Dkm3HwVr_o9h7_fQ0p92yq6kxPRlIN-z0F0OV5ERJFUL9RqXRv8d5jKOHJu2h8xbuModB7pcVkd_rZCHffP0KwexXr_VPk1tvfZ0HQoq3SRTq2QEeyyoxybg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 36-38:&lt;/strong&gt; The FacebookLogin component is a button-like component. The FacebookLogin button will turn into an image component when we have successfully logged in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 41-47:&lt;/strong&gt; Our Facebook profile information will appear in the form of name and email if we have successfully logged in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 12-21:&lt;/strong&gt; This is an arrow function used to capture the response from the FacebookLogin component. In this response we will get an access token and also some profile data from our Facebook.&lt;/p&gt;

&lt;p&gt;‍&lt;/p&gt;

&lt;h2&gt;
  
  
  5. How the FacebookLogin library works
&lt;/h2&gt;

&lt;p&gt;To understand how the FacebookLogin library works, we need to take a look at the code we have installed in our project. Open the react-facebook-login folder in the directory "/ node_modules / react-facebook-login /". Then open the facebook.js file in the directory "/node_modules/react-facebook-login/dist/facebook.js". Before the FacebookLogin component is rendered, the attributes given to this component will be fetched and processed by FB SDK, especially in the appId we prepared earlier.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;window.FB.init({
  version: 'v' + version,
  appId: appId,
  xfbml: xfbml,
  cookie: cookie
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://github.com/ghozalihadi/SoftwareEngineeringBlog" rel="noopener noreferrer"&gt;facebook.js&lt;/a&gt; in context at &lt;a href="https://quod.ai" rel="noopener noreferrer"&gt;Quod AI&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      if (_this.props.isMobile &amp;amp;&amp;amp; !disableMobileRedirect) {
        window.location.href = '//www.facebook.com/dialog/oauth?' + (0, _objectToParams2.default)(params);
      } else {
        window.FB.login(_this.checkLoginState, { scope: scope, auth_type: params.auth_type });
      }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://github.com/ghozalihadi/SoftwareEngineeringBlog" rel="noopener noreferrer"&gt;App.js&lt;/a&gt; in context at &lt;a href="https://quod.ai" rel="noopener noreferrer"&gt;Quod AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 126&lt;/strong&gt;: The login function is executed when we click the login button. Then the response will be caught by the checkLoginState function.&lt;/p&gt;

&lt;p&gt;‍&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    }, _this.responseApi = function (authResponse) {
      window.FB.api('/me', { locale: _this.props.language, fields: _this.props.fields }, function (me) {
        _extends(me, authResponse);
        _this.props.callback(me);
      });
    }, _this.checkLoginState = function (response) {
      _this.setStateIfMounted({ isProcessing: false });
      if (response.authResponse) {
        _this.responseApi(response.authResponse);
      } else {
        if (_this.props.callback) {
          _this.props.callback({ status: response.status });
        }
      }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://github.com/ghozalihadi/SoftwareEngineeringBlog" rel="noopener noreferrer"&gt;App.js&lt;/a&gt; in context at &lt;a href="https://quod.ai" rel="noopener noreferrer"&gt;Quod AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 74:&lt;/strong&gt; The authResponse we get will then be processed by the responseApi function.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 69-73&lt;/strong&gt; the responseApi data will be returned to the callback function which in our code was previously used to get the profile data response from our Facebook account.&lt;/p&gt;

&lt;p&gt;‍&lt;/p&gt;

&lt;p&gt;Next step, Open our Facebook Developer dashboard, click on "Settings" in the left navigation, then select "Basic". Continue scrolling down until you find the "+ Add Platform" 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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d961e6e28797f89d1ab90_U1tZOE9OeSPS7gAxP1gfThwQtSuw95-XzcZ8l08zueIXsjyDMfHhFNCYtsoNg_zHeuWJ6wUn6N8tPOagZmLlw1pL-bHLW0Fpa7UMQKnJRLhqGPIwzXl2-kkz_fX6Q2AWMLsePk0I.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d961e6e28797f89d1ab90_U1tZOE9OeSPS7gAxP1gfThwQtSuw95-XzcZ8l08zueIXsjyDMfHhFNCYtsoNg_zHeuWJ6wUn6N8tPOagZmLlw1pL-bHLW0Fpa7UMQKnJRLhqGPIwzXl2-kkz_fX6Q2AWMLsePk0I.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then will be pop up select platform menu. Choose “Website”&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d961ecfa34da9623ed2cf_yM07unKkB0-tMsXFE2GrjqcHyHVthqb8F9xFWisKH3I0HZp1iiTsg33vvM2kHpQiJ5whOgyWV_uAtbue3BWtEqJWnz6tufThoY89iAh5rsxhuw4Oh5QeruccXysMUhOjHwVEnhEn.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d961ecfa34da9623ed2cf_yM07unKkB0-tMsXFE2GrjqcHyHVthqb8F9xFWisKH3I0HZp1iiTsg33vvM2kHpQiJ5whOgyWV_uAtbue3BWtEqJWnz6tufThoY89iAh5rsxhuw4Oh5QeruccXysMUhOjHwVEnhEn.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;fill in the " Site URL " container with " &lt;a href="http://127.0.0.1:3000/auth/facebook/callback" rel="noopener noreferrer"&gt;http://127.0.0.1:3000/auth/facebook/callback&lt;/a&gt; " and then press the "Save Changes" 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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d961fc523ef50437e8253_bkmZOewGiqLcZuOa6lq-W7ddOpseuBakoU40IF-ZtBgnb7E0_MZoV3qyvbDf0clDBRv2C6vDlbJgwGTxCysjQpP_9Odg-XoajhYoy74gQGRco58jrAT8Nw3lmmHy3YUEjqlIv36S.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d961fc523ef50437e8253_bkmZOewGiqLcZuOa6lq-W7ddOpseuBakoU40IF-ZtBgnb7E0_MZoV3qyvbDf0clDBRv2C6vDlbJgwGTxCysjQpP_9Odg-XoajhYoy74gQGRco58jrAT8Nw3lmmHy3YUEjqlIv36S.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;6. Run our React App to login with Facebook&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To run this react app, we use command line like below.  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;npm start  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Go to &lt;a href="https://localhost:3000" rel="noopener noreferrer"&gt;https://localhost:3000&lt;/a&gt; and you can see the browser displays a button to Login With Facebook as below.&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d961f3d647985ef8c41f0_ktbYkSvWm1TMozrECZtaOFyHq429joyqK9DDc76HN0SUl4UvMADcjMfvAR7la2ZfHuFEdZYFLFZbBXPyiWDAvAkVvKkwr_K7o3TzaXIjbOCTAzBXLOniGeI2O5rhzd2YUeXFw2OeX-D0CjtcGQ.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d961f3d647985ef8c41f0_ktbYkSvWm1TMozrECZtaOFyHq429joyqK9DDc76HN0SUl4UvMADcjMfvAR7la2ZfHuFEdZYFLFZbBXPyiWDAvAkVvKkwr_K7o3TzaXIjbOCTAzBXLOniGeI2O5rhzd2YUeXFw2OeX-D0CjtcGQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;‍&lt;/p&gt;

&lt;p&gt;Click the &lt;code&gt;Login with Facebook\&lt;/code&gt; button then it will be a Facebook login dialog pop up.&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d961f6e2879db66d1ab91_fH4QnDxShEsh6kNQdfAlTE-JPZi9Hi8nuiuL4gEk1VoQDnAaKRsI1DsQ_y1BOGBgCjh2reRbhARFjqhV3thk7kOjL0UKVCpwfTKYweH9bSf1G0FkXUqpeUIH6LRzd1SEbobEFybDCZ-2E0GABA.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d961f6e2879db66d1ab91_fH4QnDxShEsh6kNQdfAlTE-JPZi9Hi8nuiuL4gEk1VoQDnAaKRsI1DsQ_y1BOGBgCjh2reRbhARFjqhV3thk7kOjL0UKVCpwfTKYweH9bSf1G0FkXUqpeUIH6LRzd1SEbobEFybDCZ-2E0GABA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enter your email address or phone number and password. Then press button “Log in”. It will be a Facebook login dialog pop up again. Press button “Continue as "your_name"” and it will be back to the previous page with this data.&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d961f1ebcd7a6e627ed57_Q3lOGzLxUHlAOyas3dzXE4K4OM8ePmjy9ME564J6hvr5Ddq8qXXrz6KJKOk--VHW4BkmvaS1V8oyFaPtHXXFwDnf1uecl16qIDOzQYCmu_ouS1qMvGgaW7wIKjWJY5Aed-Ihop6djqV-Iygo3Q.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d961f1ebcd7a6e627ed57_Q3lOGzLxUHlAOyas3dzXE4K4OM8ePmjy9ME564J6hvr5Ddq8qXXrz6KJKOk--VHW4BkmvaS1V8oyFaPtHXXFwDnf1uecl16qIDOzQYCmu_ouS1qMvGgaW7wIKjWJY5Aed-Ihop6djqV-Iygo3Q.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations, you have successfully integrated reactions with Facebook using the Facebook Login API. In our browser, it displays the profile picture and name of our Facebook account.&lt;/p&gt;

&lt;p&gt;‍  &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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d961fcdf942ddc300ca53_2n15m5sggS4ymEE1O3nvZNIck--QBNW9x8_v1XGJ4-z_xXMbEhMm7nIegbBa2VwPN07vO3yuJAEjAR3cHJ5jLZNB-UsedZCW1MCuVdR_4gtpNSq1sXFmsVqGUAmkEywlO16zg-FzHAwjtLtSEA.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F605d961fcdf942ddc300ca53_2n15m5sggS4ymEE1O3nvZNIck--QBNW9x8_v1XGJ4-z_xXMbEhMm7nIegbBa2VwPN07vO3yuJAEjAR3cHJ5jLZNB-UsedZCW1MCuVdR_4gtpNSq1sXFmsVqGUAmkEywlO16zg-FzHAwjtLtSEA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see the full code on our GitHub repository: &lt;a href="https://github.com/QuodAI/tutorial-react-facebook-api-login" rel="noopener noreferrer"&gt;https://github.com/QuodAI/tutorial-react-facebook-api-login&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quod AI is code search and navigation on steroids. We turn code into documentation that developers actually use. Do follow us on Twitter &lt;a href="https://twitter.com/quod_ai" rel="noopener noreferrer"&gt;@quod_ai&lt;/a&gt; for updates on our product and DEVs community content.&lt;/p&gt;

&lt;p&gt;Check our app at: &lt;a href="https://beta.quod.ai/" rel="noopener noreferrer"&gt;beta.quod.ai&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>loginapi</category>
      <category>facebook</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to write a chat app using Socket.io: A deep dive into Lounge Chat</title>
      <dc:creator>Quod AI</dc:creator>
      <pubDate>Sun, 21 Mar 2021 13:37:11 +0000</pubDate>
      <link>https://dev.to/quod_ai/how-to-write-a-chat-app-using-socket-io-a-deep-dive-into-lounge-chat-36fg</link>
      <guid>https://dev.to/quod_ai/how-to-write-a-chat-app-using-socket-io-a-deep-dive-into-lounge-chat-36fg</guid>
      <description>&lt;p&gt;Have you heard of IRCs before? IRC stands for Internet Relay Chat and is a protocol that allows users to install a client application on their systems or on the web browser and chat to other clients through a central server. Most IRC clients are used for communication on forums, but they facilitate one-to-one communication as well. Today, we will look at one of the most popular IRC clients, The Lounge Chat, which makes use of Socket.IO to handle bi-directional communication. Without further ado, let’s get going!&lt;/p&gt;

&lt;p&gt;This article was originally posted at: &lt;a href="https://quod.ai/post/how-to-write-a-chat-app-using-socket-io-a-deep-dive-into-lounge-chat"&gt;https://quod.ai/post/how-to-write-a-chat-app-using-socket-io-a-deep-dive-into-lounge-chat&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Objectives&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;In this deep-dive, we will mainly be looking at Socket.IO and how it enables bi-directional real-time communication in The Lounge Chat through its event mechanism. The article will be structure in the following way:&lt;/p&gt;

&lt;p&gt;1. Socket.IO and Lounge Chat&lt;br&gt;
   a.  Socket.IO - How does it work?&lt;br&gt;
   b.  Connection between users&lt;/p&gt;

&lt;p&gt;2. Socket.IO Events&lt;br&gt;
   a.  Auth Event&lt;br&gt;
   b.  Join Event&lt;br&gt;
   c.  Mentions Event &lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Socket.IO and Lounge Chat&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Socket.IO is a JavaScript library that enables applications to use WebSockets to provide real-time, low-latency, bi-directional communication. It is a very lightweight wrapper over the original WebSocket API, therefore, it allows you to stray away from conventional WebSocket code, and use a streamlined API. Socket.IO works through events that are emitted between the client and server. Both the client and server can emit events as well as listen to them and use a plethora of data structures as well as any number of arguments. We will look at the syntax in detail in the events section.&lt;/p&gt;

&lt;p&gt;Lounge Chat is an entirely free and open-source chat application that uses the IRC protocol. The application uses Vue.js as the frontend library and has Socket.IO for all the communication between client and server. You can set the application using this &lt;a href="https://thelounge.chat/docs/install-and-upgrade"&gt;guide&lt;/a&gt;, which is pretty comprehensive. Since this is not a complete guide on how to build it from scratch, we assume some proficiency of using these libraries.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Socket.IO - How does it work?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Like we said earlier, Socket.IO is a lightweight wrapper over the original WebSocket API. Websocket connections take place when the client sends a connection request to the server using an HTTP request. The server responds with a 101 code establishing a full duplex connection. When the client disconnects, the communication link is dropped. Websockets can be thought of as a very low level implementation of how you can establish two-way communication. But with Socket.IO, we have a library that has a lot of additional functionalities and an easy to use API to do this. Below is a small intro on how Socket.IO works. We have the server code first, followed by the client code.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var server = require("net").createServer();
var io = require("socket.io")(server);


var handleClient = function (socket) {
    socket.emit("message", {msg: "Hello World"});
};


io.on("connection", handleClient);


server.listen(4000);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We are going to start from the lines below and then explain the function. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 7:&lt;/strong&gt; We are starting the server on port number 4000.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Line 5:&lt;/strong&gt; We are creating a Socket.IO server instance which has been attached to the server during the imports itself. We are listening for the “connection” event, which is fired when the client visits the server page at port 4000. Once the connection is established we invoke the handleClient() method. This is used to fire a message using the socket.emit() method. Here, the event name is “message” and we pass a simple JSON with the message “Hello World”.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;socket.on("message", function(sample) {
    console.log("Message:", sample.msg);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Line 1-3:&lt;/strong&gt; This bit of code can be added to any of your client applications. We are listening for the event “message” from anyone who is connected through Socket.IO. Once you visit the server running on port 4000, the connection event will be invoked. This will fire the “message” event from the server sending the message to the client and since the client is listening in for the “message” event, it will log it to the console. &lt;/p&gt;

&lt;p&gt;Socket.IO works entirely based on this logic, where there is a connection establishment at the onset and event based triggering of listeners and methods. The best part is that both parties can send and receive these. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Sending and receiving messages&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The Lounge Chat has a public mode as well as a private mode. The public mode allows anyone to join a public chat room. The default connection details are all pre-populated, so you can get started right away. It runs on localhost:9000 when you first install it. At a very high level, this is how the chats between the clients and servers work in The Lounge Chat. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;socket.emit("input", {target, text});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Line 1:&lt;/strong&gt; This line of code emits the text entered by the user in the chat box and it has the event name as “input”. The value of the field target is the channel Id and the text field is the actual contents of what the user typed in. Channel is nothing but the name entered into the “Channels” field while connecting to The Lounge Chat. In public mode, the default channel is “#thelounge”.&lt;/p&gt;

&lt;p&gt;‍&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    socket.on("input", (data) =&amp;gt; {
        if (_.isPlainObject(data)) {
            client.input(data);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Inside the src/server.js file, we have the listener for incoming messages from the client. This is shown in the gist above.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1-3:&lt;/strong&gt; The first line creates a Socket.IO listener for the “input” event and has a callback function with an argument “data”. This is then checked using the lodash function isPlainObject and this is set as the input data for the client. &lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Socket.IO Events&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Below, we have some of the chat related events that are used between the client and the server in The Lounge Chat. There’s the “auth” event which is used for authentication, the “join” event for when the user wants to join particular channels and the “mentions” event, wherein the user mentions other users’ names in chat. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Auth Event&lt;/strong&gt;
&lt;/h2&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"use strict";
import socket from "../socket";
import storage from "../localStorage";
import {router, navigate} from "../router";
import store from "../store";
import location from "../location";
let lastServerHash = null;


socket.on("auth:success", function () {
    store.commit("currentUserVisibleError", "Loading messages…");
    updateLoadingMessage();
});


socket.on("auth:failed", function () {
    storage.remove("token");
    if (store.state.appLoaded) {
        return reloadPage("Authentication failed, reloading…");
    }
    showSignIn();
});


socket.on("auth:start", function (serverHash) {
    // If we reconnected and serverHash differs, that means the server restarted
    // And we will reload the page to grab the latest version
    if (lastServerHash &amp;amp;&amp;amp; serverHash !== lastServerHash) {
        return reloadPage("Server restarted, reloading…");
    }
    lastServerHash = serverHash;
    const user = storage.get("user");
    const token = storage.get("token");
    const doFastAuth = user &amp;amp;&amp;amp; token;


    // If we reconnect and no longer have a stored token, reload the page
    if (store.state.appLoaded &amp;amp;&amp;amp; !doFastAuth) {
        return reloadPage("Authentication failed, reloading…");
    }
    // If we have user and token stored, perform auth without showing sign-in first
    if (doFastAuth) {
        store.commit("currentUserVisibleError", "Authorizing…");
        updateLoadingMessage();
        let lastMessage = -1;
        for (const network of store.state.networks) {
            for (const chan of network.channels) {
                if (chan.messages.length &amp;gt; 0) {
                    const id = chan.messages[chan.messages.length - 1].id;
                    if (lastMessage &amp;lt; id) {
                        lastMessage = id;
                    }
                }
            }
        }
        const openChannel =
            (store.state.activeChannel &amp;amp;&amp;amp; store.state.activeChannel.channel.id) || null;
        socket.emit("auth:perform", {
            user,
            token,
            lastMessage,
            openChannel,
            hasConfig: store.state.serverConfiguration !== null,
        });
    } else {
        showSignIn();
    }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://beta.quod.ai/github/aswinrajeevofficial/thelounge/answers/details?open_file=client%2Fjs%2Fsocket-events%2Fauth.js&amp;amp;state=%7B%22client%2Fjs%2Fsocket-events%2Fauth.js%22%3A%7B%22range%22%3A%7B%22lineFrom%22%3A25%2C%22lineTo%22%3A75%7D%2C%22activeQuestionId%22%3A1473%7D%7D"&gt;auth.js&lt;/a&gt; in context at &lt;a href="https://quod.ai"&gt;Quod AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1-7:&lt;/strong&gt; These lines contain all the imports needed within the event. On the last line we have a variable called lastServerHash which we will be using further down.&lt;strong&gt;Line 9-12:&lt;/strong&gt; This sets a socket event listener for the auth:success event which shows the message “Loading messages” followed by the invocation of the updateLoadingMessages() method.&lt;strong&gt;Line 14-20:&lt;/strong&gt; These lines set a socket event listener for the auth:failure event. Firstly, it removes the token field from the local storage. This will unauthorize any existing users. If the app’s state is currently loaded, then we will reload the page stating that authentication has failed. Otherwise, we proceed to showing the sign in page for the user to login again.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Line 22-64:&lt;/strong&gt; This chunk of code contains the main logic for authentication. It sets up a socket event listener for the auth:start event with a callback function. When the serverHash is received from the server upon starting this event, it is checked with the currently available server hash. If they are not equal, we need to reload the page to get the latest server hash.&lt;br&gt;&lt;br&gt;
If it is the first time being executed, the server hash is stored in the lastServerHash variable. Then, we get the user and token fields from the local storage. If both of them do not exist, we directly go for the sign in page that is shown from lines 61-63. Otherwise, we set a flag known as doFastAuth to true.&lt;br&gt;&lt;br&gt;
If this flag is true, it means that the local storage has a user’s information already and we can log them in directly. We then set the currentUserVisibleError field in the state to “Authorizing” and invoke the updateLoadingMessage() method. This message simply displays the message that is present in the currentUserVisibleError field in the state.&lt;br&gt;&lt;br&gt;
The next few lines are used to check for the existing networks in the store and then pick out the channel id and the last message from the particular channel. We then create a constant openChannel to store the channel using the existing channel id. Lastly, we emit an event auth:perform passing in the user, token, last message, the open channel and whether the state has config information or not.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Join Event&lt;/strong&gt;
&lt;/h2&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"use strict";
import socket from "../socket";
import store from "../store";
import {switchToChannel} from "../router";


socket.on("join", function (data) {
    store.getters.initChannel(data.chan);
    const network = store.getters.findNetwork(data.network);
    if (!network) {
        return;
    }
    network.channels.splice(data.index || -1, 0, data.chan);
    // Queries do not automatically focus, unless the user did a whois
    if (data.chan.type === "query" &amp;amp;&amp;amp; !data.shouldOpen) {
        return;
    }
    switchToChannel(store.getters.findChannel(data.chan.id).channel);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://beta.quod.ai/github/aswinrajeevofficial/thelounge/answers/details?open_file=client%2Fjs%2Fsocket-events%2Fjoin.js&amp;amp;state=%7B%22client%2Fjs%2Fsocket-events%2Fjoin.js%22%3A%7B%22range%22%3A%7B%22lineFrom%22%3A7%2C%22lineTo%22%3A24%7D%2C%22activeQuestionId%22%3A1083%7D%7D"&gt;join.js&lt;/a&gt; in context at &lt;a href="https://quod.ai"&gt;Quod AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1-4:&lt;/strong&gt; We import the Vuex store that holds the entire application state. On the fourth line, we import the switchToChannel(channel) function from the router.js file.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Line 6-12:&lt;/strong&gt; We use the socket.on() method to listen for join events and execute the callback that follows. We initialize a channel on the Vuex store using the data that is received. We then check for existing networks on the store using the data.network field to see if they match. If not, we return. Otherwise, we pick out the first network element in the array using the splice function.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Line 14-18:&lt;/strong&gt; We then check if the channel is of type query and if the data should be opened. If not, then again, we return. Otherwise, we proceed to switch to that channel using the switchToChannel function that we imported from the router. This will load the RoutedChat Vue component.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Mentions Event&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This is the event that is used when a client mentions other usernames on his chat. This event also a client side event that listens for events from the server as well as a server side event that sends events. The mentions are stored into the Vuex store in an array called “mentions”.&lt;/p&gt;

&lt;p&gt;‍&lt;strong&gt;‍&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;socket.on("mentions:list", function (data) {
    store.commit("mentions", data);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Line 1-2:&lt;/strong&gt; On the client side we create a socket event listener for any events that come with the name “mentions”. It has a callback function that gets executed which stores the list of mentions in the Vuex store. Like with any store, any change in the data, will lead to updation of all the components that use that data.&lt;/p&gt;

&lt;p&gt;‍&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    socket.on("mentions:get", () =&amp;gt; {
        socket.emit("mentions:list", client.mentions);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Line 1-2:&lt;/strong&gt; The server side has a socket event listener for “mentions:get” event which is emitted from the Vue component. This event listener has a callback that triggers the “mentions:list” event on the client updating the store of the client with the list of mentions. &lt;/p&gt;

&lt;p&gt;Want to learn and contribute to Lounge Chat? Check out Quod AI’s real time documentation, powered by AI at &lt;a href="https://beta.quod.ai/github/thelounge/thelounge"&gt;https://beta.quod.ai/github/thelounge/thelounge&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Quod AI is code search and navigation on steroids. We turn code into documentation that developers actually use. Do follow us on twitter &lt;a href="https://twitter.com/quod_ai"&gt;@quod_ai&lt;/a&gt; for updates on our product and DEVs community content. Check our app at: &lt;a href="https://beta.quod.ai/"&gt;beta.quod.ai&lt;/a&gt;&lt;/p&gt;

</description>
      <category>socketio</category>
      <category>socketioevents</category>
      <category>theloungechat</category>
      <category>realtimechat</category>
    </item>
    <item>
      <title>Quod AI #1: Tackle remote onboarding + Ruby support 💎</title>
      <dc:creator>Hervé Vũ Roussel</dc:creator>
      <pubDate>Fri, 19 Mar 2021 12:05:31 +0000</pubDate>
      <link>https://dev.to/quod_ai/quod-ai-1-tackle-remote-onboarding-ruby-support-2i6a</link>
      <guid>https://dev.to/quod_ai/quod-ai-1-tackle-remote-onboarding-ruby-support-2i6a</guid>
      <description>&lt;p&gt;This is a newsletter round-up for Quod AI, the smartest way to search &amp;amp; navigate code. Quod AI turn git repositories into real-time documentation using AI.&lt;/p&gt;

&lt;h1&gt;
  
  
  Tackle remote onboarding with related search
&lt;/h1&gt;

&lt;p&gt;In our latest blog post &lt;a href="https://www.quod.ai/post/the-ultimate-readme-for-remote-onboarding"&gt;The ultimate README for remote onboarding&lt;/a&gt;, we argue that one of the goal of a README is to resurface the known unknowns (what a new developer knows he doesn't know). &lt;/p&gt;

&lt;p&gt;Our latest feature &lt;strong&gt;Did you mean?&lt;/strong&gt; will save developers from Slack interruptions and long Zoom calls! &lt;strong&gt;Did you mean?&lt;/strong&gt; search suggestions takes the guess work out of code search ... it resurfaces the know unknowns automatically for new developers. With Quod AI, it doesn't matter if you called your function resetPassword, recoverPassword or lostPassword. Quod AI will find it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j4NakXwZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://downloads.intercomcdn.com/i/o/306995141/b893cc62372a0f18affd8042/search-related-recover-password.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j4NakXwZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://downloads.intercomcdn.com/i/o/306995141/b893cc62372a0f18affd8042/search-related-recover-password.gif" alt="https://downloads.intercomcdn.com/i/o/306995141/b893cc62372a0f18affd8042/search-related-recover-password.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Did you mean&lt;/strong&gt; also works with :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Typos like &lt;code&gt;pazzword&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Semantic suggestions (example: &lt;code&gt;encryption&lt;/code&gt; → &lt;code&gt;password&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;


&lt;center&gt;&lt;strong&gt;&lt;a href="https://beta.quod.ai/github/mayeaux/nodetube?product_tour_id=214766"&gt;Try related search&lt;/a&gt;&lt;/strong&gt;&lt;/center&gt;
&lt;h1&gt;
  
  
  Ruby support
&lt;/h1&gt;

&lt;p&gt;We've released beta support for Ruby. So if want to easily find rails migration files, controllers and more. &lt;/p&gt;


&lt;center&gt;
&lt;strong&gt;&lt;a href="https://beta.quod.ai/github/helpyio/helpy"&gt;Check out a sample Ruby repo&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/center&gt;
&lt;h1&gt;
  
  
  Blog
&lt;/h1&gt;

&lt;p&gt;We've been busy writing away helpful engineering articles for big developers teams moving fast.&lt;/p&gt;

&lt;p&gt;Check out our latest blog posts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.quod.ai/post/the-ultimate-readme-for-remote-onboarding"&gt;The ultimate README for remote onboarding&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Firebase, Twitter login API and Google login API on our &lt;a href="https://www.quod.ai/blog"&gt;blog&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Our reading list
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dzone.com/articles/reading-code-is-a-skill?utm_source=programmingdigest&amp;amp;utm_medium=email&amp;amp;utm_campaign=409"&gt;Reading Code Is a Skill&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.danlew.net/2021/02/23/stop-nitpicking-in-code-reviews/?utm_source=programmingdigest&amp;amp;utm_medium=email&amp;amp;utm_campaign=409"&gt;Stop Nitpicking in Code Reviews&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;center&gt;Follow us on Twitter at &lt;a href="https://twitter.com/quod_ai"&gt;@quod_ai&lt;/a&gt; for more updates!&lt;/center&gt;

</description>
      <category>ai</category>
      <category>ruby</category>
    </item>
    <item>
      <title>How to keep developer documentation up to date in a CI/CD world</title>
      <dc:creator>Quod AI</dc:creator>
      <pubDate>Wed, 17 Mar 2021 07:29:06 +0000</pubDate>
      <link>https://dev.to/quod_ai/how-to-keep-developer-documentation-up-to-date-in-a-ci-cd-world-3518</link>
      <guid>https://dev.to/quod_ai/how-to-keep-developer-documentation-up-to-date-in-a-ci-cd-world-3518</guid>
      <description>&lt;p&gt;75.4% of new software developers say that bad documentation is their #1 blocker at work. During the pandemic and remote work, software developer teams have reported 3x slowdown in collaboration due to lack of documentation and challenges in collaboration. So what’s going on? Is it so hard to write good and reliable documentation? Well, yes it is. &lt;/p&gt;

&lt;p&gt;And there are 2 main reasons to that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Writing for other developers is hard.&lt;/li&gt;
&lt;li&gt;  Updating documentation when code changes daily is a lot of work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article was originally posted at: &lt;a href="https://quod.ai/post/how-to-keep-developer-documentation-up-to-date-in-a-ci-cd-world" rel="noopener noreferrer"&gt;https://quod.ai/post/how-to-keep-developer-documentation-up-to-date-in-a-ci-cd-world&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  What’s good documentation anyway?
&lt;/h1&gt;

&lt;p&gt;To understand what makes documentation good, we must first talk about the goal of documentation. Why do we need documentation in the first place?&lt;/p&gt;

&lt;h2&gt;
  
  
  Good documentation answers questions from other developers
&lt;/h2&gt;

&lt;p&gt;In order to evolve an existing codebase, a developer should understand the existing code. As developers, we’re constantly asking questions about our codebase to better understand and evolve it. &lt;/p&gt;

&lt;p&gt;In a research case study, Google collected questions that their own software engineers asked when coding. They categorized all of those questions into 5 categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;How (example code)&lt;/strong&gt;: How do I use X API? How do I implement feature Y?&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;What (reading specific code)&lt;/strong&gt;: What does this script do? What’s the name of the enumeration?&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Where (code localization)&lt;/strong&gt;: Where is the code to do X? Where do we configure environment variables for Y?&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Why (determine impact)&lt;/strong&gt;: Why did my change not work? &lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Who and when (metadata):&lt;/strong&gt; Who edited this code and when? Who can help review this code?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F6051a4fa6265697ed5f86e94_dqTnRwJppSVW-ieg36RhqRHhGDIi5Y6F7Sf0JVoIAPngrJNPlGClZByyz85Fs1JfXiMjUmuoUF7KevM461XuLu8UlZOOPv7LUhpag08uv1UzZWOV-ju7ggGwX5ce3YHd51tPnLdC.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F6051a4fa6265697ed5f86e94_dqTnRwJppSVW-ieg36RhqRHhGDIi5Y6F7Sf0JVoIAPngrJNPlGClZByyz85Fs1JfXiMjUmuoUF7KevM461XuLu8UlZOOPv7LUhpag08uv1UzZWOV-ju7ggGwX5ce3YHd51tPnLdC.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In normal times, working at the office, you could just tap on your co-workers shoulders to get your answer (even though he may not like being interrupted). Now, with Slack ping pongs and Zoom overload, getting answers is a lot more work. &lt;/p&gt;

&lt;p&gt;Obviously, it’s not easy to communicate online. But for developers, discussions require a lot of technical context and complex technical situations. IRL whiteboards are super helpful… However, digital whiteboards… not so much.&lt;/p&gt;

&lt;p&gt;So how can we collaborate productively on code without face to face or whiteboards?&lt;/p&gt;

&lt;h2&gt;
  
  
  The attributes of good documentation
&lt;/h2&gt;

&lt;p&gt;In the context of information systems, documentation is organized information. And when it comes to information, there are 11 criterias that define how good it is. We’re going to go through all those criterias but essentially, documentation should:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Be easy to find.&lt;/li&gt;
&lt;li&gt; Be easy to read/write and update.&lt;/li&gt;
&lt;li&gt; Be up to date and simple.&lt;/li&gt;
&lt;li&gt; Offer the whole context.&lt;/li&gt;
&lt;/ol&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F6051a4fa76d2b6059d36c225_ZBVruLyYrFpK8lVtm8iDFG4GtzbEZUZr3vfbL9fy9k1qmrZmTOwo92Q-5BkUKPXUTnR6jMnuplpJ1ujYh3kfWo2yRtjB_02xrqeLZ8rmyGXrxYAFAGqj96DUN1iJFp_KUD_OPd4n.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F6051a4fa76d2b6059d36c225_ZBVruLyYrFpK8lVtm8iDFG4GtzbEZUZr3vfbL9fy9k1qmrZmTOwo92Q-5BkUKPXUTnR6jMnuplpJ1ujYh3kfWo2yRtjB_02xrqeLZ8rmyGXrxYAFAGqj96DUN1iJFp_KUD_OPd4n.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Usability
&lt;/h3&gt;

&lt;p&gt;The criterias for usability of documentation relate to &lt;strong&gt;how easy it is to read and write&lt;/strong&gt; (and update) documentation.   &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Relevant&lt;/strong&gt;: documentation should show what’s important to its reader. For devs, documentation should help make technical decisions.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Simple&lt;/strong&gt;: documentation should be easy to read and not go into details that are not &lt;strong&gt;needed&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Economical&lt;/strong&gt;: documentation should be easy to write and update.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Flexible&lt;/strong&gt;: documentation should be consumable by different people in your team with different goals.  For example a QA could look up the password reset feature from a BDD perspective, while Frontend and Backend can look up its implementation.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Delivery
&lt;/h3&gt;

&lt;p&gt;The criterias for delivery have to do with the how and when. How the documentation &lt;strong&gt;is read and found&lt;/strong&gt;.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Accessible&lt;/strong&gt;: documentation should be available when you need it, in the format you need it. For example: in the IDE as I call a function; in Github when I search for code; or in Slack when I ask a question to my team.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Timely&lt;/strong&gt;: documentation should show up when we need it. Not a week later when the PR is ready to be reviewed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Quality
&lt;/h3&gt;

&lt;p&gt;Quality of documentation reflects &lt;strong&gt;how good the decisions are&lt;/strong&gt;, after documentation is read. A developer could make bad decisions if the documentation is out of date, incorrect or lacks important context (and he is unaware of those issues).  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Accurate&lt;/strong&gt;: documentation shouldn’t have any errors. Duh. But easier said than done.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Complete&lt;/strong&gt;: documentation should explain code impact and full context. For example, imagine microservice A saves users in the users table and microservice B also writes to the same users table. If the documentation for A fails to mention B, then it wouldn’t be complete.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Reliable&lt;/strong&gt;: documentation should rely on data and facts rather than opinions or mis-collected data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Practical tips to keep documentation up to date in a CI/CD world
&lt;/h1&gt;

&lt;p&gt;I once heard an enterprise software architect say at a public talk “Don’t bother updating documentation. By the time you’re done the code will have changed.”&lt;/p&gt;

&lt;p&gt;Today, we are expected to release faster than ever: weekly, daily … and sometimes even hourly. Documentation is hard to maintain. However, we can make our job easier by following the principles of good documentation:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Be easy to find.&lt;/li&gt;
&lt;li&gt; Be easy to read/write and update.&lt;/li&gt;
&lt;li&gt; Be up to date and simple.&lt;/li&gt;
&lt;li&gt; Offer the whole context.
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Avoid writing code comments 
&lt;/h2&gt;

&lt;p&gt;A few years ago, my CEO asked me if our departing software engineer had documented his code with comments. I answered: “I hope not”. He laughed… but he didn’t realize I wasn’t joking.  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A comment is a failure to express yourself in code.  If you fail, then write a comment; but try not to fail.&lt;br&gt;&lt;br&gt;
- Uncle Bob  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We sometimes tend to write comments to explain the behavior in our code instead of writing good code. We expect code comments to explain the expected behavior of the app.  For example, a developer on your team may ask: “When does the user have access to premium features?”  &lt;/p&gt;

&lt;p&gt;Bad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Checks whether the user has access to premium features  
if (user.subscriptionPlan == 'premium'
   &amp;amp;&amp;amp; user.billing.lastPaid 30 
   || user.daysLeftInTrial &amp;lt; 30)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead try:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (user.hasPremiumFeatures()) {
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Write code that’s self documenting. Robert C. Martin (aka Uncle Bob) has dedicated a whole chapter about comments in his book Clean Code. Check out Chapter 4. He has fantastic examples of good and bad comments.   &lt;/p&gt;

&lt;p&gt;Essentially, there are 3 types of code comments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Redundant/noisy: just remove it.&lt;/li&gt;
&lt;li&gt;  Explanatory/summary: refactor the code.&lt;/li&gt;
&lt;li&gt;  Useful: explains the why - keep it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Keep your documentation light… or just delete it
&lt;/h2&gt;

&lt;p&gt;Have you ever read documentation that you knew was out of date? But you knew some parts were correct? Stale documentation can be as useless as no documentation because you don’t know which parts you can rely on. Or worse, you could rely on it thinking it’s up to date when it isn’t.  &lt;/p&gt;

&lt;p&gt;So before you start writing documentation, ask yourself: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Who’s going to read it? What questions will they be asking?&lt;/li&gt;
&lt;li&gt;  How often will I need to update it? 
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Make documentation easy to find
&lt;/h2&gt;

&lt;p&gt;One of the reasons documentation gets stale is because it doesn’t get used often. It doesn’t get used, because it’s hard to search (*cough cough* Confluence).  &lt;/p&gt;

&lt;p&gt;Organize information so that it’s easy to find when others need it. Here are some practical tips:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Add  README.md in sub folders of your repos to explain specific modules or concepts.&lt;/li&gt;
&lt;li&gt;  Link your tickets/issues in your documentation. Use hashtags and keywords to make it easy to search.&lt;/li&gt;
&lt;li&gt;  Move important information from your Slack to your README.&lt;/li&gt;
&lt;li&gt;  Organize your documentation into folders that are consistent and logical:

&lt;ul&gt;
&lt;li&gt;  For a standard README table of content, we recommend our &lt;a href="https://www.quod.ai/post/the-ultimate-readme-for-remote-onboarding" rel="noopener noreferrer"&gt;ultimate README&lt;/a&gt; as a way to organize your processes.&lt;/li&gt;
&lt;li&gt;  Use a nomenclature that’s easy to follow and think about. For example: README, LICENSE, etc.&lt;/li&gt;
&lt;li&gt;  Organize your Confluence documentation into folders that reflect your features (example: user, billing, authentication, etc.). Use the same folder hierarchy consistent with how your code is organized.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Keep documentation close to code
&lt;/h2&gt;

&lt;p&gt;One of the biggest reasons for obsolete documentation is that it’s far from source code. As discussed above, documentation should be easy to write and update.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real code examples&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;The most searched documentation at Google is real code examples. For example: How do I use the billing API? Is there example code that does this?&lt;br&gt;&lt;br&gt;
You could write a paragraph about the endpoint URL and each of its parameters, the HTTP verbs, expected parameters… Or, you could just write an example usage of your API as part of a demo. Or better yet...  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Write tests&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Tests are a great way to document the expectation of your users. For example: “When does a user get locked out of his account?”&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;describe("User login", function() {  
  it("should lock out", function() {  
    login(“jdoe", "wrongpassword");  
    login(“jdoe", "wrongpassword");  
    login(“jdoe", "wrongpassword");  
    expect(statusMessage).toBe("You’ve been locked out of your account");  
  });  
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running your tests frequently (or using CI/CD) will force you to update your tests as documentation when the behavior of the app changes.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code tutorials with git message and merge commits&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Another way to document is to link your git messages, with your issue tracker and pull requests. &lt;br&gt;&lt;br&gt;
This can help answer questions like: How do I add a new database entity into our app? How should I name the API routes? Which files do I need to edit?&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F6051a4fa002afbd3a90a95b3_2a1hjTLR5y5xPgIK9W3CQJUwR77rZwp2ZqzFv_3H412XXXfMWYNI9DNbjBM2XPR_5CJXVxJdFqVFpSzBXqqKNgZGkm_-brBoTQp9JGEnTIU3_2fkY0ImsD9GkY7syfzH57g_S2NC.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F6051a4fa002afbd3a90a95b3_2a1hjTLR5y5xPgIK9W3CQJUwR77rZwp2ZqzFv_3H412XXXfMWYNI9DNbjBM2XPR_5CJXVxJdFqVFpSzBXqqKNgZGkm_-brBoTQp9JGEnTIU3_2fkY0ImsD9GkY7syfzH57g_S2NC.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="https://github.com/GetStream/Winds/commit/15debf484e00bfa5540720b67c3035f6341e5bd5" rel="noopener noreferrer"&gt;add Note API&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If someone has implemented a similar feature before, one great starting point is to get inspired from that commit. It’s an example implementation to build on.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automate with tools and scripts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Turn documentation (processes, rules) into apps and scripts. Automation removes ambiguity and sets up (very) clear step by step instructions.  &lt;/p&gt;

&lt;p&gt;For example, instead of writing in prose “how to export users from the database in CSV” or “how to build and deploy the app”, why not write a script or a program to do it? Very much like testing, automation (if used frequently) forces you to update your scripts when behavior of the app or process changes.  &lt;/p&gt;

&lt;p&gt;Writing documentation can be a great way to support developers on your team. However, documentation is a time investment by the entire team. Your team needs to write, update and organize your documentation so that every developer on the team can benefit for effective and productive collaboration.   &lt;/p&gt;

&lt;p&gt;But ... What if you could spend less time documenting and organizing? Yet, still be able to answer questions from your fellow developers? &lt;/p&gt;

&lt;h1&gt;
  
  
  Use AI for easy and simple documentation
&lt;/h1&gt;

&lt;p&gt;At Quod AI, our goal is to help developers find answers in the smartest way. Our platform turns source code repositories into documentation using Deep Learning and NLP.  &lt;br&gt;&lt;br&gt;
There is only one step to get your documentation: submit your Git repo URL. That’s it. Our AI models take care of the rest.  &lt;/p&gt;

&lt;p&gt;We’ve submitted &lt;a href="https://github.com/GetStream/Winds" rel="noopener noreferrer"&gt;Winds&lt;/a&gt;, a gorgeous open source podcast and RSS feed app. Using Quod AI as auto generated documentation, we’re going to answer questions based on Google’s case study.   &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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F6051a4fa1c2ff44664f0c3f6_INiJgLjaUGwPjdFXJ2Jcwk3cZ9cd1KXPmsSprrl2lVxKjTpbI8IMQzJmN-GkXqS0AnlwL9wrVnFTb-Ckz1KDCAF3RCC3orRX-pQ9ae23HOqcpWJkHd5NohWMEQ_P1hH6ldlM_zaI.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F6051a4fa1c2ff44664f0c3f6_INiJgLjaUGwPjdFXJ2Jcwk3cZ9cd1KXPmsSprrl2lVxKjTpbI8IMQzJmN-GkXqS0AnlwL9wrVnFTb-Ckz1KDCAF3RCC3orRX-pQ9ae23HOqcpWJkHd5NohWMEQ_P1hH6ldlM_zaI.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Example code of how use the articles API
&lt;/h2&gt;

&lt;p&gt;How do I retrieve an article using the API?  To answer this, let's &lt;a href="https://beta.quod.ai/github/GetStream/Winds/search?initTerm=retrieve%20article%20api%20tag%3A%5B%22Test%22%5D&amp;amp;rootRepo=github%2FGetStream%2FWinds&amp;amp;term=retrieve%20article%20api%20tag%3A%5B%22Test%22%5D" rel="noopener noreferrer"&gt;search: retrieve article api test&lt;/a&gt;.&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F6051a4f990b70a3a31693adb_qhzbQSyZR8qjWL7Z7xgwQJfxjEL5v_iKw_afI_kdw4EvyPmzBb7ndm6x7BEorBfyBXP9Vt4Nkcy47v_rWXktU1zSXDgNDEo_nQrLk5oBE0VWj5sErnF8RhXaFWsVKSlJa5_xJ2Dg.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F6051a4f990b70a3a31693adb_qhzbQSyZR8qjWL7Z7xgwQJfxjEL5v_iKw_afI_kdw4EvyPmzBb7ndm6x7BEorBfyBXP9Vt4Nkcy47v_rWXktU1zSXDgNDEo_nQrLk5oBE0VWj5sErnF8RhXaFWsVKSlJa5_xJ2Dg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first result is a test that shows a test to retrieve an article from  the articles API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exploring and reading how articles work
&lt;/h2&gt;

&lt;p&gt;What is an article? What can a user do with an article? To answer this, let’s &lt;a href="https://beta.quod.ai/github/GetStream/Winds/search?initTerm=article&amp;amp;rootRepo=github%2FGetStream%2FWinds&amp;amp;term=article" rel="noopener noreferrer"&gt;search: article&lt;/a&gt;. &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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F6051a4f93b34ce20869bedad__-f8AKKd9FMjtWgaMcmjIcdkAt8zEaE1JoRZCCO7PZrtumsoVpZXFB4bhNrI0zKuKtCprP-OAkM8QaHV6jAG0VS4l1ocID0GQoVHAj70CdgPTIDkjBYBnoEbuMLl0OsZFT7uAvjB.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F6051a4f93b34ce20869bedad__-f8AKKd9FMjtWgaMcmjIcdkAt8zEaE1JoRZCCO7PZrtumsoVpZXFB4bhNrI0zKuKtCprP-OAkM8QaHV6jAG0VS4l1ocID0GQoVHAj70CdgPTIDkjBYBnoEbuMLl0OsZFT7uAvjB.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Not only did I learn about that an article can be pinned, I also learned from the suggested search that parsing article was an important feature of article&lt;/p&gt;

&lt;h2&gt;
  
  
  Sharing authentication code
&lt;/h2&gt;

&lt;p&gt;How do you prevent unauthorized access? How do you reset a user password? How do we prevent unauthorized access?&lt;br&gt;&lt;br&gt;
In most applications, authentication is spread out around in many files due to its complexity. The Winds app is no different.  &lt;/p&gt;

&lt;p&gt;Sharing one snippet of code is not enough. That’s why Quod AI supports the concepts of collections. Collections are like a YouTube playlist of code snippets (without the music and copyright infringement).   &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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F6051a4fa76d2b6b70236c226_q8oa1wb-QoHN4gy_mc_2gu4T9XiQPpEmfEPRWgVAutoCNelzUnEbz4D_223VL3O9mjSci5WkdbROd5zmnZN0eZrRr55W0Hj6_VeCjz4RgiYlihhs1LgotOROGLmIoClE3gVZwwlF.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F6051a4fa76d2b6b70236c226_q8oa1wb-QoHN4gy_mc_2gu4T9XiQPpEmfEPRWgVAutoCNelzUnEbz4D_223VL3O9mjSci5WkdbROd5zmnZN0eZrRr55W0Hj6_VeCjz4RgiYlihhs1LgotOROGLmIoClE3gVZwwlF.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I created the &lt;a href="https://beta.quod.ai/github/GetStream/Winds/collections/GetStream%2Fauthentication?active_section=570380" rel="noopener noreferrer"&gt;authentication&lt;/a&gt; collection in 5 minute. All I had to do was to find and collect snippets. Yet my documentation for authentication is fairly comprehensive because the code is automatically augmented with questions and tags.  &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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F6051a4fb43a4928048384b35_1jzVpAQKYx6Q3AXiZc0ArUvzHq96fGqB7LOmZNLAAGgL3sO4oqHmE0ai6pY5AaUHonIyg0a7W21sLi3ROZKNpOS1FuQoW29MvanWcVVq5QS6JwFJugP2hmNrHUdg4p_q5es0e4-q.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F6051a4fb43a4928048384b35_1jzVpAQKYx6Q3AXiZc0ArUvzHq96fGqB7LOmZNLAAGgL3sO4oqHmE0ai6pY5AaUHonIyg0a7W21sLi3ROZKNpOS1FuQoW29MvanWcVVq5QS6JwFJugP2hmNrHUdg4p_q5es0e4-q.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sometimes, code is not enough and you need to contextualize the code. In that situation, you can simply comment on the code. When sharing a collection, your team can read the code with the added context of your comment.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Sharing environment configuration
&lt;/h2&gt;

&lt;p&gt;How do I configure the database for Winds? Which port is Redis using?&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F6051a4fa76d2b6113036c227_KwGOyNbqnGKyX37hIG34KJVTGAZ8NLBg82pE5wANa1zpDfYu-oYRyspZ4lkeDo7slUgDQaKcGR3-MJBwnmq-GkdjbEE9R88uWpB1GY91XIxpf-pnlg3ph8oLOU3RN42bKe_XzlVl.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F6051a4fa76d2b6113036c227_KwGOyNbqnGKyX37hIG34KJVTGAZ8NLBg82pE5wANa1zpDfYu-oYRyspZ4lkeDo7slUgDQaKcGR3-MJBwnmq-GkdjbEE9R88uWpB1GY91XIxpf-pnlg3ph8oLOU3RN42bKe_XzlVl.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Winds has most of its environment configuration centralized into one file. But for ease of readability, I created a collection to show the dev, test and production configurations. Check out &lt;a href="https://beta.quod.ai/github/GetStream/Winds/collections/GetStream%2Fconfiguration" rel="noopener noreferrer"&gt;how to configure Winds’ external dependencies&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trace code history for Podcast schema
&lt;/h2&gt;

&lt;p&gt;“Podcast” is one of the most important concepts of Winds. Naturally, it’s one of the most viewed code files.  Who’s the best person to review this code? Who can help me understand this code?  &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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F6051a4fb2290478f19bdab77_wyhSy2doSElGKw6j3mvVkD4360t7f8GMQN0LmGgXSadQCkqkfz00trSAcL8hEuMMDfq-CVXGRpEjbiZ6VjfuqPpbFRu1qqEvqOChyEAy1hupGm0e6LrKOHsCmGLs0TZm_34XLibp.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F6051a4fb2290478f19bdab77_wyhSy2doSElGKw6j3mvVkD4360t7f8GMQN0LmGgXSadQCkqkfz00trSAcL8hEuMMDfq-CVXGRpEjbiZ6VjfuqPpbFRu1qqEvqOChyEAy1hupGm0e6LrKOHsCmGLs0TZm_34XLibp.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To answer this, we can go directly to &lt;a href="https://beta.quod.ai/github/GetStream/Winds/answers/details?open_file=api%2Fsrc%2Fmodels%2Fpodcast.js&amp;amp;state=%7B%22api%2Fsrc%2Fmodels%2Fpodcast.js%22%3A%7B%22range%22%3A%7B%22lineFrom%22%3A139%2C%22lineTo%22%3A149%7D%2C%22activeQuestionId%22%3A1719%7D%7D" rel="noopener noreferrer"&gt;models/podcast.js&lt;/a&gt; in Quod AI’s smart Code Browser. The automatic context tab gives us information about who are the key contributors to a specific snippet.  &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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F6051a4fb353bec6e46f21fb4_7kI32_ojrDnNRsulhzASK4UwThp1tYtk2Wwl4VBJ2iqtFk5E1srj4xRl93rE99_ePGl5nCO0qwOUsQbKyRtelhMH0n4bDgpU4CtL7NNpIKdjQu07wLM2hTA0KIadXR4pivo5uTLW.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F6051a4fb353bec6e46f21fb4_7kI32_ojrDnNRsulhzASK4UwThp1tYtk2Wwl4VBJ2iqtFk5E1srj4xRl93rE99_ePGl5nCO0qwOUsQbKyRtelhMH0n4bDgpU4CtL7NNpIKdjQu07wLM2hTA0KIadXR4pivo5uTLW.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What were the last changes and which ones were impactful? Quod AI can answer this automatically as it resurfaces the latest commits with an impact score. A low impact commit is a commit that reformats the code and doesn’t change the behavior of the code for example.  &lt;/p&gt;

&lt;p&gt;That’s it! Documentation was and still is an essential part of software development. It’s just changing. &lt;/p&gt;

&lt;p&gt;Quod AI is code search and navigation on steroids. We turn code into documentation that developers actually use. Do follow us on twitter &lt;a href="https://twitter.com/quod_ai" rel="noopener noreferrer"&gt;@quod_ai&lt;/a&gt; for updates on our product and DEVs community content. Check our app at: &lt;a href="https://beta.quod.ai/" rel="noopener noreferrer"&gt;beta.quod.ai&lt;/a&gt;&lt;/p&gt;

</description>
      <category>documentation</category>
      <category>docs</category>
      <category>readme</category>
      <category>codesearch</category>
    </item>
    <item>
      <title>How to use Firestore: A deep dive into Todoist clone</title>
      <dc:creator>Quod AI</dc:creator>
      <pubDate>Fri, 05 Mar 2021 09:02:21 +0000</pubDate>
      <link>https://dev.to/quod_ai/how-to-use-firestore-a-deep-dive-into-todoist-clone-2bfc</link>
      <guid>https://dev.to/quod_ai/how-to-use-firestore-a-deep-dive-into-todoist-clone-2bfc</guid>
      <description>&lt;p&gt;This article was originally posted at: &lt;a href="https://quod.ai/post/how-to-use-firestore-a-deep-dive-into-todoist-clone" rel="noopener noreferrer"&gt;https://quod.ai/post/how-to-use-firestore-a-deep-dive-into-todoist-clone&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Todoist is one of the most popular to-do-list applications in the market today. It came out way back in 2007 and currently has over 25 million users worldwide. Today, we will take a deep dive into Firebase Collections and will use the Todoist Clone repository as a reference point. Do note that this is not going to focus on the React side of things, and assumes you have a basic understanding of custom hooks, state management, etc. Here’s a brief of what we’re going to cover today.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Set up the Todoist clone in your system&lt;/li&gt;
&lt;li&gt;  Integrate Firebase with the application&lt;/li&gt;
&lt;li&gt;  Firestore Basics - Queries, documents, and collections&lt;/li&gt;
&lt;li&gt;  Why Firestore?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’re not going to bore you further with our introduction. Let’s dive straight in.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Set up the Todoist clone in your system&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Building a clone of an app such as Todoist from scratch would mean long hours of setup. We want to help you get the right stuff, the best possible way and for that, we already have a GitHub repository with the code required. You can download the source code from here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/karlhadwen/todoist" rel="noopener noreferrer"&gt;https://github.com/karlhadwen/todoist&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clone this code to your system using HTTPS or SSH:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/karlhadwen/todoist.git" rel="noopener noreferrer"&gt;https://github.com/karlhadwen/todoist.git&lt;br&gt;&lt;br&gt;
&lt;/a&gt;&lt;a href="//mailto:git@github.com"&gt;git@github.com&lt;/a&gt;:karlhadwen/todoist.git &lt;/p&gt;

&lt;p&gt;Once you clone the code, fire up your favorite code editor, ours is Visual Studio Code. Run the following command to download all the dependencies mentioned in the package.json file. You can use either yarn or npm to do this. Since we have npm that comes along with the &lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;node&lt;/a&gt; executable, we will be using that. After executing the command, you should see something similar to this.&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F60409b77978117b66cfa10db_CHEq2FycTRBeFc40gUy8zlVScrt-wnliqLcAPmc43WArS4doppORDXwauIy9p-jkLB8EFWLihhl16pVC5UqUOg5ZgWflZivsB9-KQ5pxWoCZy1da5xvWhCrH2PtczuN0nBq4MBJh.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F60409b77978117b66cfa10db_CHEq2FycTRBeFc40gUy8zlVScrt-wnliqLcAPmc43WArS4doppORDXwauIy9p-jkLB8EFWLihhl16pVC5UqUOg5ZgWflZivsB9-KQ5pxWoCZy1da5xvWhCrH2PtczuN0nBq4MBJh.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To run a React application using npm, we can use the npm start command and the application will be set up at localhost:3000. You can also use the yarn start command to do the exact same thing. If you run the application right now, you will be greeted with an error message saying that ‘firebase’ is missing. To rectify this, we need to integrate Firebase with our application. But before we do that, let’s just take a look at the folder structure to understand what we’re dealing with.&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F60409b7816a2733eda0d6aa9_YRMOk-Id1DHckfRAG6VbsqvEXbwjq0uY9XYLCIkL_5xuMdVa3K822VzqqL7jQKaLVi9yU5x8F7NxzpZIRBAE8vAGQEB_eI2sQf1wGcTQszMtu4xXqBWeJ1k-fWykQsXYDzxWObh_.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F60409b7816a2733eda0d6aa9_YRMOk-Id1DHckfRAG6VbsqvEXbwjq0uY9XYLCIkL_5xuMdVa3K822VzqqL7jQKaLVi9yU5x8F7NxzpZIRBAE8vAGQEB_eI2sQf1wGcTQszMtu4xXqBWeJ1k-fWykQsXYDzxWObh_.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;├── __tests__ - Contains the test files&lt;/p&gt;

&lt;p&gt;├── components - Houses all the components present within the application&lt;/p&gt;

&lt;p&gt;├── constants - Constants, store some of the constants that we need within the application&lt;br&gt;&lt;br&gt;
├── context - Context is used to store the programming context&lt;/p&gt;

&lt;p&gt;├── helpers - Helpers contain all of the helper functions that we will commonly use&lt;/p&gt;

&lt;p&gt;├── hooks - This folder contains the custom React Hooks&lt;/p&gt;

&lt;p&gt;├── App.js&lt;/p&gt;

&lt;p&gt;├── App.scss&lt;/p&gt;

&lt;p&gt;├── index.js&lt;/p&gt;

&lt;p&gt;We have replaced App.css with App.scss. Do note that several files that come up when we create a basic React app have been removed. This includes App.test.js, index.css, serviceWorker.js, logo.svg, App.css, logo192.png, logo512.png, favicon.ico, manifest.json, and robots.txt. We will be focusing on the Firebase elements in this application, so let’s get started.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Integrate Firebase with the application&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Integrating Firebase with our web application is extremely simple and straightforward. You can use your Google account to log in to Firebase. Then, head over to the Firebase Console and create a new project.&lt;/p&gt;

&lt;p&gt;‍&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F60409b77427cb2f59f731157_xuEyR6h3IM0oTxNq9FpJ-btKdWE5zKO2Femozig6cgR0RUaUp9kzBrxzfJmyybb6S9mXeJ2CXBre2LWmkA-TbPxjsTcv460FB_KQQnTqL2g5HOfYZYuLrTvK67li4GnU93ZRf4IX.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F60409b77427cb2f59f731157_xuEyR6h3IM0oTxNq9FpJ-btKdWE5zKO2Femozig6cgR0RUaUp9kzBrxzfJmyybb6S9mXeJ2CXBre2LWmkA-TbPxjsTcv460FB_KQQnTqL2g5HOfYZYuLrTvK67li4GnU93ZRf4IX.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will open up a project creation wizard that has just two easy steps. The first step is to enter a project name.&lt;/p&gt;

&lt;p&gt;‍&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F60409b7763a2e05f8c6d11bc_TW1crnuPlmWN0scK06QImMZf4QLqO-LEeKTZO9t9uo077k-wPpGPT2IdLackQ08EWec4hgq2Cpha_n9bgf-BI2OVSQv07a9VzSQiKRJyHB8rOIqvg9sbx1cWofhOpEeZTN0CstdF.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F60409b7763a2e05f8c6d11bc_TW1crnuPlmWN0scK06QImMZf4QLqO-LEeKTZO9t9uo077k-wPpGPT2IdLackQ08EWec4hgq2Cpha_n9bgf-BI2OVSQv07a9VzSQiKRJyHB8rOIqvg9sbx1cWofhOpEeZTN0CstdF.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you enter the name and hit enter, you will be asked whether you want to use Google Analytics for your project. We can disable this for now.&lt;/p&gt;

&lt;p&gt;‍&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F60409b781acdda2597091392_57D4FR3Ilf3gyvH8M6Hsd_YIIsbcL4_K_35gJ40xgbhA9FM19Sd2f4xBJNHBKj3DlgIDMn1qmdBj445XIHYGpqf9DLrvedgGVsaubrxlo4qE1hYA4QlokeqNKdL7WeN4iFh7mbSk.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F60409b781acdda2597091392_57D4FR3Ilf3gyvH8M6Hsd_YIIsbcL4_K_35gJ40xgbhA9FM19Sd2f4xBJNHBKj3DlgIDMn1qmdBj445XIHYGpqf9DLrvedgGVsaubrxlo4qE1hYA4QlokeqNKdL7WeN4iFh7mbSk.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you disable Google Analytics, you can directly create the project after step 2. Otherwise, you will have one more step to go through. Hit the ‘Create Project’ button now and you’re all set to go.    &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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F60409b782ceaa452be60fe0b_ArUsM4oak02I532EUlAwTzI7m0JSs8r2CSn-0r9vL46ScPhHKzpBRUfpbqdj4s7ayZ7x01OlH0f7xV9XEecvMpOOa5c0V_tcYJfadnXKMxe-Dlb3jnilYtw8wwZilGFLOh-1kwvV.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F60409b782ceaa452be60fe0b_ArUsM4oak02I532EUlAwTzI7m0JSs8r2CSn-0r9vL46ScPhHKzpBRUfpbqdj4s7ayZ7x01OlH0f7xV9XEecvMpOOa5c0V_tcYJfadnXKMxe-Dlb3jnilYtw8wwZilGFLOh-1kwvV.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will be greeted with this page that says the project has been successfully created. Once you hit Continue, you will be at the project dashboard. The next step is to add Firebase to your project.  &lt;/p&gt;

&lt;p&gt;‍&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F60409b78427cb2dfe2731158_D5dlcyd9SHuMkVlDWfYpWPtG2GqQQ8w0lvhukJLDilqHSi9ch-FnZXmrxXSMsFGE4LsZmkmvZ-pZ4PH2ZrbuqYMROpcAScMl_21BhUlc0OG-_JFwKSEknhcgIzw5vrdKvaRpXbCH.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F60409b78427cb2dfe2731158_D5dlcyd9SHuMkVlDWfYpWPtG2GqQQ8w0lvhukJLDilqHSi9ch-FnZXmrxXSMsFGE4LsZmkmvZ-pZ4PH2ZrbuqYMROpcAScMl_21BhUlc0OG-_JFwKSEknhcgIzw5vrdKvaRpXbCH.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the ‘&amp;lt;/&amp;gt;’ button that indicates a web application. The following screen will give you all the configuration information that is required. For us, we just need to copy the 6 lines of code marked below.  &lt;/p&gt;

&lt;p&gt;‍&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F60409b781e63903785c6eaac_CFfmY_xgXa2CsmfGOzmg31zu11e97C1IQuwj75i-0_iuE551dFB5aCOm5owyr0UFcGRqRyy-Q0z5jG8kMvA3VsmUd1udiKYVj5FCfgvlEyyf2PP1hfsPD0kwsiozwHjexfZ7awF9.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F60409b781e63903785c6eaac_CFfmY_xgXa2CsmfGOzmg31zu11e97C1IQuwj75i-0_iuE551dFB5aCOm5owyr0UFcGRqRyy-Q0z5jG8kMvA3VsmUd1udiKYVj5FCfgvlEyyf2PP1hfsPD0kwsiozwHjexfZ7awF9.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To integrate Firebase into our Todoist application, we will need to create a file named firebase.js inside the src folder. This config file is then imported into all the other components as and when Firebase is required in the application.&lt;/p&gt;

&lt;p&gt;‍&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import firebase from 'firebase/app';
import 'firebase/firestore';


const firebaseConfig = firebase.initializeApp({
    apiKey: "$YOUR_API_KEY_HERE",
    authDomain: "$YOUR_AUTH_DOMAIN",
    projectId: "$YOUR_PROJECT_ID",
    storageBucket: "$YOUR_STORAGE_BUCKET",
    messagingSenderId: "$YOUR_MESSAGE_SENDER_ID",
    appId: "$YOUR_APP_ID"
});


export { firebaseConfig as firebase };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Line 1-2:&lt;/strong&gt; These are the two imports that we need. One is for Firebase and the next is for Firestore.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Line 4:&lt;/strong&gt; We create a constant named firebaseConfig. Here we call the initialize app function on the firebase object that we imported earlier and pass in the configuration information.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Line 5-10:&lt;/strong&gt; This is where you paste the 6 lines that we copied from the Firebase Console.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Line 13:&lt;/strong&gt; We then import the firebaseConfig constant as firebase, so that we can use it everywhere in the project.&lt;/p&gt;

&lt;p&gt;With that, we have successfully integrated Firebase within our application. To use Firestore in our application, we simply import this file and call the firestore() method. This will initialize an instance of Firestore with the configuration information that we provided. This instance will be used to query the db, retrieve data and make updates. We will look deeper into this aspect of Firestore in the next section and go through queries, documents, and collections.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Firestore Basics: Queries, documents, and collections&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;The great thing about the Todoist clone project is that even though it is feature-rich and looks complex, the underlying functionality can be easily implemented. Firestore is Firebase's NoSQL database that allows us to store information from our application like users, tasks, projects, etc. Other NoSQL databases in the market include MongoDB, CouchDB, Cassandra, Amazon DynamoDB and HBase. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Todoist Clone: Database Model&lt;/strong&gt;
&lt;/h2&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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F60409dd99177d612d58f9488_XIP701YwMt4i6yS3eNOLZvYq2sQhat7VVqH_3fdSj-BsdGK7EqbjeCK70mdK6H5Ge-FvCLzvCZIHlj_JPGCaR5T6Q3B_5UjE3o5-PCxhyf0XUZn2GSCwxBPvJM1HFCO9fSL3bIwR.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%2Fuploads-ssl.webflow.com%2F5e733294d7b5a568ffa60a00%2F60409dd99177d612d58f9488_XIP701YwMt4i6yS3eNOLZvYq2sQhat7VVqH_3fdSj-BsdGK7EqbjeCK70mdK6H5Ge-FvCLzvCZIHlj_JPGCaR5T6Q3B_5UjE3o5-PCxhyf0XUZn2GSCwxBPvJM1HFCO9fSL3bIwR.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is a snapshot from the Firebase Console. For the todoist clone, we just have two entities in the database, projects and tasks. Tasks contain five fields: archived, data, projectId, task and userId. The archived field is used to denote whether a task has been completed or not. The data field is used to set the task date. The projectId is used to link the task to a project (it can be empty also, if there’s no project associated with the task). The task field, denotes the name of the task and the userId, denotes the user who created the task. &lt;/p&gt;

&lt;p&gt;Projects contain three fields: name, projectId and userId. The name denotes the project name, projectId is the unique identifier that we generate using a helper function and the userId denotes the user who created the task. &lt;/p&gt;

&lt;p&gt;Firestore simplifies a lot of the operations that are usually cumbersome with traditional databases. It allows the frontend client app to make calls directly to the DB (no backend servers needed) and that is what we’re going to capitalize on. Most traditional database clients require a middleware to process the calls from the frontend. Firestore/FBRD allows you to directly query the database from the frontend app without having to have a Node/Express, Spring, Flask backend. Since it is a NoSQL database, meaning there is no rigid structure. It stores data in the form of JSON. Simple data is stored as documents and a series of related documents are stored as collections. Collections will have multiple documents present within them, with some kind of unique id linking each document to a collection. In the screenshot above, we can see that we have two collections: projects and tasks. Each of them have multiple documents present inside them referencing the collection using an id field. Instead of having multilevel JSONs to represent complex relationships, Firestore represents them as single-level JSONs with a unique ID linking them to other documents.&lt;/p&gt;

&lt;p&gt;Firestore is also highly optimized to have a lot of small documents in it and it allows us to listen to changes. This means that any change in the database is immediately reflected back to all the listeners. This makes it a perfect solution for a lot of real-time applications like reservation systems, online ticket booking, etc (where the chances of double booking are high). Imagine a scenario, where you’re trying to book a particular seat to a cinema on an online booking platform, and see that the seat turns gray because someone else books it right before you do. Firebase Realtime Database is another alternative that Firebase provides. But it is slightly more difficult to use and has less functionality when there is large amount of data to handle.Firebase Realtime Database (FBRD) stores data as a single large JSON file while Firestore provides better structure with bifurcation into documents and collections. Due to the indexing present in Firestore, querying will always be fast. This is because it depends only on the query result and not on the size of the dataset. Firestore also has a better billing method because it bills you based on the number of operations and not on the network bandwidth and storage.  &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Cloud Firestore - Basic Querying&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Queries are used in Firestore to access the data and for all the create/read/update/delete operations. It is important to know how these are constructed to get a better understanding of how data comes in and goes out of the application.&lt;strong&gt;‍&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import firebase from 'firebase/app';
firebase.firestore()
firebase.firestore().collection(‘subjects’)
firebase.firestore().collection(‘subjects’).doc('123')
firebase.firestore().collection(‘subjects’).where(‘subjectName’, '==', ‘Mathematics’)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Line 1:&lt;/strong&gt; This is the import statement that is needed to use firebase within our app.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Line 2:&lt;/strong&gt; This creates a Firestore instance with the config information that we have provided.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Line 3:&lt;/strong&gt; This is how we reference a collection.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Line 4:&lt;/strong&gt; This is how we reference a particular document in the collection.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Line 5:&lt;/strong&gt; Last line shows how we can query a document that satisfies a particular condition. &lt;/p&gt;

&lt;p&gt;The last line has three parts. ‘subjectName’, '==', ‘Mathematics’. This is how every query is constructed. It has the field which we are referring to, the relational operation (‘&amp;lt;’, ‘&amp;lt;=’, ‘&amp;gt;’, ‘&amp;gt;=’, ‘==’), and lastly the value to compare. We can also chain queries using multiple where() blocks but do note that we are not allowed to use range operators on different fields while chaining. The end product of this line of code is a ref and it doesn't actually execute the queries. Refs are references to documents or collections. They can be &lt;a href="https://firebase.google.com/docs/reference/js/firebase.firestore.DocumentReference" rel="noopener noreferrer"&gt;DocumentReference&lt;/a&gt; or a &lt;a href="https://firebase.google.com/docs/reference/js/firebase.firestore.CollectionReference" rel="noopener noreferrer"&gt;CollectionReference&lt;/a&gt;. To get the contents, we need to call the get() method at the end that returns a promise.  &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Cloud Firestore - Document/Query Snapshots&lt;/strong&gt;
&lt;/h2&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const subject = await firebase.firestore().collection(‘subjects’).doc('123').get();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Line 1:&lt;/strong&gt; This line returns a promise, but we still need to resolve it to get the data. This is known as the DocumentSnapshot (in case of documents) or a CollectionSnapshot (in case of collections).&lt;/p&gt;

&lt;p&gt;You might think that the const variable will now store the key-value pairs that are present in a particular document. But it actually returns a DocumentSnapshot. This object stores certain metadata of the document along with the data present itself. So, we need to access this by calling the data() method on the snapshot returned.&lt;strong&gt;‍&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const snapshot = await firebase.firestore().collection(‘subjects’).doc('123').get();
const data = snapshot.data();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Line 1:&lt;/strong&gt; We store the return value of the get() method into a constant called snapshot.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Line 2:&lt;/strong&gt; We use the data() method from the snapshot to get the actual data.  &lt;/p&gt;

&lt;p&gt;In case we query for something that returns multiple documents, we don't get a DocumentSnapshot, but a QuerySnapshot. We need to access the docs property on the QuerySnapshot to get the array of documents and then use something like an arrow function to map it to a constant, calling the data() method on each document. Snapshots allow us to listen for database changes. For instance, if you see a reservation for a seat in a cinema hall, and if another person books it, you will see it turning to gray in real-time showing that it is unavailable.&lt;/p&gt;

&lt;p&gt;Another advantage with Firestore is that documents are automatically indexed. This means that even if there’s an increase in the size of documents to be fetched the time taken to retrieve them doesn’t linearly increase.  &lt;/p&gt;

&lt;p&gt;Let’s take a look at another code snippet from the Todoist clone that explains how we can retrieve the tasks from the to-do list.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const useProjects = () =&amp;gt; {
  const [projects, setProjects] = useState([]);


  useEffect(() =&amp;gt; {
    firebase
      .firestore()
      .collection('projects')
      .where('userId', '==', 'jlIFXIwyAL3tzHMtzRbw')
      .orderBy('projectId')
      .get()
      .then(snapshot =&amp;gt; {
        const allProjects = snapshot.docs.map(project =&amp;gt; ({
          ...project.data(),
          docId: project.id,
        }));


        if (JSON.stringify(allProjects) !== JSON.stringify(projects)) {
          setProjects(allProjects);
        }
      });
  }, [projects]);


  return { projects, setProjects };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://beta.quod.ai/github/aswinrajeevofficial/todoist/answers/details?open_file=src%2Fhooks%2Findex.js&amp;amp;state=%7B%22src%2Fhooks%2Findex.js%22%3A%7B%22range%22%3A%7B%22lineFrom%22%3A54%2C%22lineTo%22%3A77%7D%2C%22activeQuestionId%22%3A180%7D%7D" rel="noopener noreferrer"&gt;index.js&lt;/a&gt; in context at &lt;a href="https://quod.ai" rel="noopener noreferrer"&gt;Quod AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1:&lt;/strong&gt; This is a custom React Hook that we are using to get the list of the projects.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Line 2:&lt;/strong&gt; This contains the project's state as well as the setProjects used to update the state if there’s a change. We use the useState() hook to make it a stateful component.           &lt;br&gt;&lt;br&gt;
&lt;strong&gt;Line 4-10:&lt;/strong&gt; This is where the actual magic happens. We use the useEffect() hook to allow our component to use lifecycle hooks in React, which was earlier only possible for class components. We then use a query to retrieve all the projects for the specific userId and order them by their project ids.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Line 11-23:&lt;/strong&gt; As we said earlier, when we use the get() method, we get a QuerySnapshot, and we iterate through all of them using an arrow operator and store the data into the constant allProjects. It is interesting to note that we compare it with the existing list of projects and change state only if there’s any difference between the two. Finally, we return the array of projects and the setProjects method.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Cloud Firestore - Create/Update/Delete Operations&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Similar to the query we saw in the example above, we can also create, update or delete in the exact same way. All of these return promises, and we can use async/await along with these. We will look at code snippets where we can create a new project, delete a project as well as update a task.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const addProject = () =&amp;gt;
    projectName &amp;amp;&amp;amp;
    firebase
      .firestore()
      .collection('projects')
      .add({
        projectId,
        name: projectName,
        userId: 'jlIFXIwyAL3tzHMtzRbw',
      })
      .then(() =&amp;gt; {
        setProjects([...projects]);
        setProjectName('');
        setShow(false);
      });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://beta.quod.ai/github/aswinrajeevofficial/todoist/answers/details?open_file=src%2Fcomponents%2FAddProject.js&amp;amp;state=%7B%22src%2Fcomponents%2FAddProject.js%22%3A%7B%22range%22%3A%7B%22lineFrom%22%3A14%2C%22lineTo%22%3A28%7D%2C%22activeQuestionId%22%3A161%7D%7D" rel="noopener noreferrer"&gt;AddProject.js&lt;/a&gt; in context at &lt;a href="https://quod.ai" rel="noopener noreferrer"&gt;Quod AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1-15:&lt;/strong&gt; This is the snippet used to add a new project. We reference the collection using, firebase().firestore().collection(‘projects’) and then call the add() method to add a project to the collection. The projectId is generated using a function and is a random set of characters and numbers. You can take a look at src/helpers/index.js for the function (generatePushId). The project name is what we type into the text box and the userId is a predefined string to identify the user. You can use any predefined string here, but make sure to use the same string throughout.&lt;strong&gt;‍&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const archiveTask = () =&amp;gt; {
    firebase.firestore().collection('tasks').doc(id).update({
      archived: true,
    });
  };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://beta.quod.ai/github/aswinrajeevofficial/todoist/answers/details?open_file=src%2Fcomponents%2FCheckbox.js&amp;amp;state=%7B%22src%2Fcomponents%2FCheckbox.js%22%3A%7B%22range%22%3A%7B%22lineFrom%22%3A6%2C%22lineTo%22%3A10%7D%2C%22activeQuestionId%22%3A20%7D%7D" rel="noopener noreferrer"&gt;Checkbox.js&lt;/a&gt; in context at &lt;a href="https://quod.ai" rel="noopener noreferrer"&gt;Quod AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1-5:&lt;/strong&gt; This is a very short snippet to showcase the update functionality of Firestore. Similar to the create operation, we reference the collection using firebase().firestore().collection(), passing in the collection name. But since we need to update a specific document, we need to pass the document id, which is passed as an argument to the doc() method. To update, we simply call the update() method on this document, and set the property that we want to the new value. In this case, the archived field is set to true. On setting archived to true, the item on the todo list is removed indicating that it has been already completed.  &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const deleteProject = (docId) =&amp;gt; {
    firebase
      .firestore()
      .collection('projects')
      .doc(docId)
      .delete()
      .then(() =&amp;gt; {
        setProjects([...projects]);
        setSelectedProject('INBOX');
      });
  };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View &lt;a href="https://beta.quod.ai/github/aswinrajeevofficial/todoist/answers/details?open_file=src%2Fcomponents%2FIndividualProject.js&amp;amp;state=%7B%22src%2Fcomponents%2FIndividualProject.js%22%3A%7B%22range%22%3A%7B%22lineFrom%22%3A12%2C%22lineTo%22%3A22%7D%2C%22activeQuestionId%22%3A13%7D%7D" rel="noopener noreferrer"&gt;IndividualProject.js&lt;/a&gt; in context at &lt;a href="https://quod.ai" rel="noopener noreferrer"&gt;Quod AI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1-5:&lt;/strong&gt; We delete a project by passing in the document ID associated with the project, each time we click on the delete button. This is then used along with the query to select the particular document to delete. Similar to the retrieval, we call the firebase object’s firestore() method, reference the collection, projects, then pass in the document ID to the doc() method.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 6-11:&lt;/strong&gt; Then we call the delete() method which returns a promise and we resolve it by setting the projects array with the new one and set the selected project as ‘INBOX’, which will show the Inbox view to the user.&lt;/p&gt;

&lt;p&gt;Checkout all the firebase functions in context in Quod AI’s &lt;a href="https://beta.quod.ai/github/karlhadwen/todoist/collections/karlhadwen%2Ffirestore-queries-and-collections" rel="noopener noreferrer"&gt;firebase collection for todoist&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Why Firestore?&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;The main reason to use Firestore is the fact that anyone without previous experience with Firebase can get up and running in no time. The fact that we were able to integrate Firebase into our web application, hook up the database and start querying it in very little time is a testament to how easy it is to use. Also, Firebase has come a long way since its inception and is perfect for hobby projects as well as commercial applications. Their billing is very flexible and is a great entry point for your next big application.&lt;/p&gt;

&lt;p&gt;Phew! That was a long one. But we really hope that you now have a better understanding of Firestore and how you can integrate it with your web application. We saw how easy it is to use Firestore to store, retrieve and perform operations on our application data. The fact that everything happens in real-time makes it all the more exciting!&lt;/p&gt;

&lt;p&gt;Checkout todoist source code: &lt;a href="https://github.com/karlhadwen/todoist" rel="noopener noreferrer"&gt;https://github.com/karlhadwen/todoist&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Want to easily and quickly onboard and contribute to todoist? Checkout &lt;a href="https://beta.quod.ai/github/karlhadwen/todoist/collections/karlhadwen%2Ffirestore-queries-and-collections" rel="noopener noreferrer"&gt;todoist on Quod AI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Quod AI is code search and navigation on steroids. We turn code into documentation that developers actually use. Check our app free at: &lt;a href="https://beta.quod.ai/" rel="noopener noreferrer"&gt;beta.quod.ai&lt;/a&gt;&lt;/p&gt;

</description>
      <category>firebase</category>
      <category>opensource</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>The ultimate README for effective remote onboarding </title>
      <dc:creator>Quod AI</dc:creator>
      <pubDate>Fri, 26 Feb 2021 09:07:43 +0000</pubDate>
      <link>https://dev.to/quod_ai/the-ultimate-readme-for-effective-remote-onboarding-2990</link>
      <guid>https://dev.to/quod_ai/the-ultimate-readme-for-effective-remote-onboarding-2990</guid>
      <description>&lt;p&gt;Getting someone new on a team is always exciting. Developer teams have shifted to Slack and Zoom and it has been quite challenging. We’ve seen collaboration &lt;a href="https://doi.org/10.1080/12460125.2020.1861772"&gt;slow down 3x&lt;/a&gt; during WFH. Yet, a solid README could &lt;a href="https://services.google.com/fh/files/misc/state-of-devops-2019.pdf"&gt;increase developer's productivity by 1.7x&lt;/a&gt;. This could lead to informed questions by new teammates on Slack and Zoom and better pull requests.&lt;/p&gt;

&lt;p&gt;This article was originally posted at: &lt;a href="https://quod.ai/post/the-ultimate-readme-for-remote-onboarding"&gt;https://quod.ai/post/the-ultimate-readme-for-remote-onboarding&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What’s onboarding? It’s the ultimate knowledge transfer. getting someone new from knowing nothing to pushing code in production.&lt;/p&gt;

&lt;p&gt;The goal of this post is to establish a template for the ultimate README.&lt;/p&gt;

&lt;p&gt;Sections of the README should be easy and helpful for both readers (new developers) and writers (more experienced developers):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Easy to write &amp;amp; update&lt;/li&gt;
&lt;li&gt;  A powerful orientation guide for new developers&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  How to onboard onto complex code
&lt;/h1&gt;

&lt;p&gt;Onboarding onto large code is not about understanding a lot of code. It’s about understanding the structure, concepts and abstractions of the system.&lt;/p&gt;

&lt;p&gt;There are basically 2 approaches to onboarding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Top down: from a high level system down to specific code. &lt;/li&gt;
&lt;li&gt;  Bottom up: from specific code up to the layers of the system. We navigate from code to layers of abstractions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Onboarding is about mapping what your new developer doesn't know (unknown unknowns).&lt;/p&gt;

&lt;p&gt;When onboarding, you need both. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The top down approach is more about the big picture. This is helpful to avoid pitfalls and side effects of the system (what you don’t know you don’t know - unknowns unknowns). It won't help close tickets but is tedious to self teach.&lt;/li&gt;
&lt;li&gt;  The bottom up approach is more pragmatic. Give someone a ticket and starting point in the code and let your new developer navigate to the answer. The risk is that your new developer may not be aware of unknown unknowns… his code  could have unintended consequences (like side effects).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--afzICqnW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://uploads-ssl.webflow.com/5e733294d7b5a568ffa60a00/603819bec1894e58cc275880_5Als8FQkwa1nCGqxboKpxLhU15-nbXHl-DQOuyXSS8nSSHCf0Yy7G_HSFbST6UK43T7jOODgqZT9WOZ7GBlUe0BzZWQ5p4sdN0vx2Hp7FH5exII6_QN3LnplL7nULNid58bO2qb8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--afzICqnW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://uploads-ssl.webflow.com/5e733294d7b5a568ffa60a00/603819bec1894e58cc275880_5Als8FQkwa1nCGqxboKpxLhU15-nbXHl-DQOuyXSS8nSSHCf0Yy7G_HSFbST6UK43T7jOODgqZT9WOZ7GBlUe0BzZWQ5p4sdN0vx2Hp7FH5exII6_QN3LnplL7nULNid58bO2qb8.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A good README is about giving a top down approach and pointing your new developers to the starting point of the bottom up approach (specific code locations).&lt;/p&gt;

&lt;p&gt;Your new developer is successful when he pushes his first code to production. The goal of a good onboarding guide is to help  him to be effective in that process.&lt;/p&gt;

&lt;p&gt;So how do we pave the path for your new developer's success?&lt;/p&gt;

&lt;h1&gt;
  
  
  What makes a good README?
&lt;/h1&gt;

&lt;p&gt;So how do we set up your new developer for success? &lt;/p&gt;

&lt;p&gt;A good README explains what’s already in place: the existing code, the processes and the team with the goal that your new developer can evolve it. Here are some of the high characteristics of a good README:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YKdyiyUV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://uploads-ssl.webflow.com/5e733294d7b5a568ffa60a00/60386c4ad49e8f3cf890349d_Characteristics%2520of%2520a%2520good%2520README.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YKdyiyUV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://uploads-ssl.webflow.com/5e733294d7b5a568ffa60a00/60386c4ad49e8f3cf890349d_Characteristics%2520of%2520a%2520good%2520README.png" alt="characteristics of a good README: Explains how the team works Points your new developer to the right code or what code to search for Answers what your new developer knows he doesn’t know Raises awareness about what your new developer doesn’t know he doesn’t know"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  What should a README answer?
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MrvQeLqF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://uploads-ssl.webflow.com/5e733294d7b5a568ffa60a00/60382a0b7490ec1dc4de1683_Good%2520README%2520Should%2520Answer.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MrvQeLqF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://uploads-ssl.webflow.com/5e733294d7b5a568ffa60a00/60382a0b7490ec1dc4de1683_Good%2520README%2520Should%2520Answer.png" alt="App How to get it up and running? How to use it? How to configure the app? Code organization How is the code organized? How can I find code? How does the team write code? What conventions and patterns should I be using? Team processes How to submit a PR? How to deploy in production?"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  The ultimate README template
&lt;/h1&gt;

&lt;p&gt;So here goes the template. It should be quick to write from scratch if you know your repo.&lt;/p&gt;

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


&lt;h1&gt;
  
  
  The ultimate README for nodetube
&lt;/h1&gt;

&lt;p&gt;One of the problems with nodetube’s README is that it is aimed towards users and not contributors.&lt;/p&gt;

&lt;p&gt;Known unknowns about nodetube:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  It’s a web app but I don’t know how the front end, API, DB architecture are organized&lt;/li&gt;
&lt;li&gt;  It can host videos but I don’t know how the hosting is managed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unknowns unknowns: we hope to clarify by applying our README template&lt;/p&gt;

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


</description>
      <category>nodetube</category>
      <category>readme</category>
      <category>remote</category>
      <category>onboarding</category>
    </item>
  </channel>
</rss>
