<?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: Israel Ayanwola</title>
    <description>The latest articles on DEV Community by Israel Ayanwola (@devvspaces).</description>
    <link>https://dev.to/devvspaces</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F867847%2Fae5d69c6-e5d0-4b0f-a167-40e2505c46d2.png</url>
      <title>DEV Community: Israel Ayanwola</title>
      <link>https://dev.to/devvspaces</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/devvspaces"/>
    <language>en</language>
    <item>
      <title>Streamlining Big Number Calculations in C using GMP</title>
      <dc:creator>Israel Ayanwola</dc:creator>
      <pubDate>Sat, 29 Jul 2023 11:01:29 +0000</pubDate>
      <link>https://dev.to/devvspaces/streamlining-big-number-calculations-in-c-programming-using-gmp-215c</link>
      <guid>https://dev.to/devvspaces/streamlining-big-number-calculations-in-c-programming-using-gmp-215c</guid>
      <description>&lt;p&gt;Nowadays, technologies like Cryptography need computers to compute complex mathematical operations. These algorithms need the CPU to perform arithmetic operations on large numbers with high precision.&lt;/p&gt;

&lt;p&gt;The amount of data a processor can execute at once depends on its number of virtual memory addresses. The maximum integer representation a 32-bit processor can work with is 4,294,967,295 (2^32 − 1), while for a 64-bit processor is 18,446,744,073,709,551,615 (2^64 − 1). These bit constraints affect C standard integer and float data types.&lt;/p&gt;

&lt;p&gt;Most high-level languages, like Python, allows programmers to work with larger numbers. Allowing programmers to write programs for processing numbers larger than what the CPU can handle. It's possible to write programs for calculating big numbers in C, but it can get very complex and confusing.&lt;/p&gt;

&lt;p&gt;GMP, GNU Multiple Precision Arithmetic Library, streamlines the complexity of working with big numbers in C. This article covers how you can use the GMP Library to perform basic mathematical operations on various kinds of numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To follow this article, you need to have;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A basic understanding of C,&lt;/li&gt;
&lt;li&gt;GCC installed - for compiling C programs,&lt;/li&gt;
&lt;li&gt;Basic understanding of GCC,&lt;/li&gt;
&lt;li&gt;Access to the internet - for installing GMP, and&lt;/li&gt;
&lt;li&gt;A text editor was installed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is GMP?
&lt;/h2&gt;

&lt;p&gt;GMP is a free library for arbitrary precision arithmetic, operating on signed integers, rational numbers, and floating-point numbers. There is no practical limit to the precision except the ones implied by the available memory in the machine GMP runs on. GMP has a rich set of functions, and the functions have a regular interface. - gmplib.org&lt;/p&gt;

&lt;p&gt;GMP allows you to calculate big numbers of many kinds with high precision. It represents numbers in its program as strings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing GMP
&lt;/h2&gt;

&lt;p&gt;To install GMP library, you can follow this informative guide. It explains how you can download, configure and build the library on Window, Mac and Linux. &lt;/p&gt;

&lt;h2&gt;
  
  
  Performing Arithmetical Operations Using GMP
&lt;/h2&gt;

&lt;p&gt;After installing the library, you need to include the GMP header file in your program to use the library for calculations. &lt;/p&gt;

&lt;h3&gt;
  
  
  Addition
&lt;/h3&gt;

&lt;p&gt;For adding two integers, you need to declare and initialize the variables in a special way before calculations.&lt;/p&gt;

&lt;p&gt;Include GMP library header. This allows you to access the types and macros declared in the header file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;gmp.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Declare and initialize the variables for the result, and the numbers to add together.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;mpz_t&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/* Initializing integers */&lt;/span&gt;
&lt;span class="n"&gt;mpz_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;mpz_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_a&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;mpz_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Initializing the variables using &lt;code&gt;mpz_init&lt;/code&gt; function tells GMP to allocate memory space to the variables. Then you can assign any large number to the initialized variables.&lt;/p&gt;

&lt;p&gt;The lines below assigns &lt;code&gt;3479349783486297692763769376273723897236&lt;/code&gt; to &lt;code&gt;num_a&lt;/code&gt; and &lt;code&gt;9223372036854775807&lt;/code&gt; to &lt;code&gt;num_b&lt;/code&gt;. There is no limit to the amount of precision you get when using GMP for calculations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* Assigning integers */&lt;/span&gt;
&lt;span class="n"&gt;mpz_set_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"3479349783486297692763769376273723897236"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;mpz_set_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"9223372036854775807"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;mpz_set_str&lt;/code&gt; function takes the first argument as the variable to assign a value. The second argument is the string representation of the integer you want to assign. The third argument represents the base of the integer (which, in this case, is the second argument). In the above example, the integers are in base 10, meaning decimal numbers. &lt;/p&gt;

&lt;p&gt;Now you can add the number together using the &lt;code&gt;mpz_add&lt;/code&gt; function from the GMP library. The function sets &lt;code&gt;res&lt;/code&gt; to &lt;code&gt;num_a + num_b&lt;/code&gt;. Then you can use &lt;code&gt;gmp_printf&lt;/code&gt; to print the values. It works like C standard library printf function. The only difference is that &lt;code&gt;gmp_printf&lt;/code&gt; allows you to format larger numbers. The &lt;code&gt;%Zd&lt;/code&gt; flag in the format string for &lt;code&gt;gmp_printf&lt;/code&gt; is to format large integers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* Addition */&lt;/span&gt;
&lt;span class="n"&gt;mpz_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;gmp_printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Addition:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;%Zd + %Zd = %Zd&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you need to clear the variables. Clearing the variables frees the memory allocated for the variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* Clearing memory */&lt;/span&gt;
&lt;span class="n"&gt;mpz_clear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;mpz_clear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_a&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;mpz_clear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The full program should look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// main.c&lt;/span&gt;

&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;gmp.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mpz_t&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="cm"&gt;/* Initializing integers */&lt;/span&gt;
    &lt;span class="n"&gt;mpz_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;mpz_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_a&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;mpz_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="cm"&gt;/* Assigning integers */&lt;/span&gt;
    &lt;span class="n"&gt;mpz_set_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"3479349783486297692763769376273723897236"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;mpz_set_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"9223372036854775807"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="cm"&gt;/* Addition */&lt;/span&gt;
    &lt;span class="n"&gt;mpz_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;gmp_printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Addition:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;%Zd + %Zd = %Zd&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="cm"&gt;/* Clearing memory */&lt;/span&gt;
    &lt;span class="n"&gt;mpz_clear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;mpz_clear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_a&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;mpz_clear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You need to link the GMP library when compiling your program. You can only link the dynamic or static library if you have installed GMP on your machine. If you haven’t, go back to the installation section above.&lt;/p&gt;

&lt;p&gt;Run the command below to build your program. The &lt;code&gt;-lgmp&lt;/code&gt; flag tells gcc to search for the GMP library when linking. GCC will search the list of standard directories to find the library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcc main.c &lt;span class="nt"&gt;-o&lt;/span&gt; main &lt;span class="nt"&gt;-lgmp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it could not find the gmp library on your machine. Try with the build flags below. The &lt;code&gt;-L~/gmp-6.2.1/.libs&lt;/code&gt; flag tells gcc to also check the &lt;code&gt;~/gmp-6.2.1/.libs&lt;/code&gt; directory if it could not find the library using the standard list. For you, this path is the location you installed GMP.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcc main.c &lt;span class="nt"&gt;-o&lt;/span&gt; main &lt;span class="nt"&gt;-L&lt;/span&gt;~/gmp-6.2.1/.libs &lt;span class="nt"&gt;-lgmp&lt;/span&gt; &lt;span class="nt"&gt;-static&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That covers how you can add large numbers in C and build your program.&lt;/p&gt;

&lt;h3&gt;
  
  
  Subtraction
&lt;/h3&gt;

&lt;p&gt;You can use the &lt;code&gt;mpz_sub&lt;/code&gt; function from the GMP library to substract large numbers. Ensure you initialize the variables and assign their integers respectively.&lt;/p&gt;

&lt;p&gt;This subtracts &lt;code&gt;num_b&lt;/code&gt; from &lt;code&gt;num_a&lt;/code&gt; and assigns the result to &lt;code&gt;res&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* Subtraction */&lt;/span&gt;
&lt;span class="n"&gt;mpz_sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;gmp_printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Substraction:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;%Zd - %Zd = %Zd&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your full program might look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// main.c&lt;/span&gt;

&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;gmp.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mpz_t&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="cm"&gt;/* Initializing integers */&lt;/span&gt;
    &lt;span class="n"&gt;mpz_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;mpz_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_a&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;mpz_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="cm"&gt;/* Assigning integers */&lt;/span&gt;
    &lt;span class="n"&gt;mpz_set_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"3434234245245245252452452452"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;mpz_set_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"9999943444444434344444444434232323232322"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="cm"&gt;/* Subtraction */&lt;/span&gt;
    &lt;span class="n"&gt;mpz_sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;gmp_printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Substraction:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;%Zd - %Zd = %Zd&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="cm"&gt;/* Clearing memory */&lt;/span&gt;
    &lt;span class="n"&gt;mpz_clear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;mpz_clear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_a&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;mpz_clear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Multiplication
&lt;/h3&gt;

&lt;p&gt;For multiplying integers, use &lt;code&gt;mpz_mul&lt;/code&gt; function from the GMP library.&lt;/p&gt;

&lt;p&gt;This multiplies &lt;code&gt;num_a&lt;/code&gt; and &lt;code&gt;num_b&lt;/code&gt; and assigns result to &lt;code&gt;res&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* Multiplication */&lt;/span&gt;
&lt;span class="n"&gt;mpz_mul&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;gmp_printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Multiplication:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;%Zd x %Zd = %Zd&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Division
&lt;/h3&gt;

&lt;p&gt;For division, things will look a little different. Instead of using the type &lt;code&gt;mpz_t&lt;/code&gt; to declare integers as you have seen before, you will use &lt;code&gt;mpf_t&lt;/code&gt; instead to declare floats.&lt;/p&gt;

&lt;p&gt;To divide large numbers using GMP you need to declare and initialize floats and not integers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;mpf_t&lt;/span&gt; &lt;span class="n"&gt;div_res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;div_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;div_b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you initialize the variables using &lt;code&gt;mpf_init&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* Initializing floats */&lt;/span&gt;
&lt;span class="n"&gt;mpf_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;div_res&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;mpf_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;div_a&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;mpf_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;div_b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assign values you want to the variables. They can be as large as needed. The last argument to &lt;code&gt;mpf_set_str&lt;/code&gt; tells GMP that the string is in a decimal format.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* Assign floats */&lt;/span&gt;
&lt;span class="n"&gt;mpf_set_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;div_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"7347973477376467734.34322335550000000000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;mpf_set_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;div_b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"489384838948848.4783873847"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Divide and print out the results using the functions below. The GMP function &lt;code&gt;mpf_div&lt;/code&gt; divides &lt;code&gt;div_a&lt;/code&gt; by &lt;code&gt;div_b&lt;/code&gt; and assigns the result to &lt;code&gt;div_res&lt;/code&gt;. Then prints out the formatted string.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* Division */&lt;/span&gt;
&lt;span class="n"&gt;mpf_div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;div_res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;div_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;div_b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;gmp_printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Division:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;%Ff / %Ff = %Ff&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;div_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;div_b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;div_res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your final code should look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// main.c&lt;/span&gt;

&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;gmp.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mpf_t&lt;/span&gt; &lt;span class="n"&gt;div_res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;div_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;div_b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="cm"&gt;/* Initializing floats */&lt;/span&gt;
    &lt;span class="n"&gt;mpf_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;div_res&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;mpf_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;div_a&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;mpf_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;div_b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="cm"&gt;/* Assign floats */&lt;/span&gt;
    &lt;span class="n"&gt;mpf_set_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;div_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"7347973477376467734.34322335550000000000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;mpf_set_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;div_b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"489384838948848.4783873847"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="cm"&gt;/* Division */&lt;/span&gt;
    &lt;span class="n"&gt;mpf_div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;div_res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;div_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;div_b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;gmp_printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Division:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;%Ff / %Ff = %Ff&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;div_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;div_b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;div_res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="cm"&gt;/* Clearing memory */&lt;/span&gt;
    &lt;span class="n"&gt;mpf_clear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;div_res&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;mpf_clear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;div_a&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;mpf_clear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;div_b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Square root
&lt;/h3&gt;

&lt;p&gt;Ensure you declare and initialize the float variables. Then calculate the square root of that variable using &lt;code&gt;mpf_sqrt&lt;/code&gt; function. This function only accepts two arguments. The variable to square root and the variable to assign the result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* Squre root */&lt;/span&gt;
&lt;span class="n"&gt;mpf_sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;div_res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;div_a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;gmp_printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Square root:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;sqrt(%Ff) = %Ff&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;div_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;div_res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;You can perform other arithmetical operations that are not covered in this article using GMP. Check out the resources section below for their documentation to learn more. It covers how you can perform more Arithmetical operations with Logical and Bitwise operations. Also you can calculate using C int types and rational numbers.&lt;/p&gt;

&lt;p&gt;Use the resources provided below to learn more about working with big numbers in C using the GMP library. If you are looking for a challenge try writing a C function to add two large numbers.&lt;/p&gt;

&lt;p&gt;Thanks for reading this article. 😊&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Linking libraries using GCC Compiler - &lt;a href="https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html"&gt;https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Installing GMP from the official website - &lt;a href="https://gmplib.org/#DOWNLOAD"&gt;https://gmplib.org/#DOWNLOAD&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Guide to installing GMP on any machine - &lt;a href="http://rstudio-pubs-static.s3.amazonaws.com/493124_a46782f9253a4b8193595b6b2a037d58.html"&gt;http://rstudio-pubs-static.s3.amazonaws.com/493124_a46782f9253a4b8193595b6b2a037d58.html&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Mastering Django CI/CD using GitHub Actions</title>
      <dc:creator>Israel Ayanwola</dc:creator>
      <pubDate>Sun, 02 Jul 2023 03:23:10 +0000</pubDate>
      <link>https://dev.to/devvspaces/mastering-django-cicd-using-github-actions-2912</link>
      <guid>https://dev.to/devvspaces/mastering-django-cicd-using-github-actions-2912</guid>
      <description>&lt;p&gt;Testing and delivery is a common repetitive cycle in application development. This cycle consumes more time and resources as we fix or add more features to our application. Automating this repetitive process will reduce the time spent in application development.&lt;/p&gt;

&lt;p&gt;Testing and Deployment are part of the cycle discussed earlier. We build, deploy and test our applications a lot. Doing this every time is vulnerable to human error. Automating our tests guarantees that every commit undergoes testing.&lt;/p&gt;

&lt;p&gt;This article covers how we can use GitHub Actions to automatically test our Django applications.&lt;/p&gt;

&lt;p&gt;Let’s dive in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To follow through with this article, we need the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Basic knowledge of Django, Git, and GitHub&lt;/li&gt;
&lt;li&gt;A GitHub account&lt;/li&gt;
&lt;li&gt;Python3 and Django installed on our operating system&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setup Demo Django Application
&lt;/h2&gt;

&lt;p&gt;We need a Django application that has tests to understand how GitHub actions work. We can work with this &lt;a href="https://github.com/devvspaces/simple-django-testcase" rel="noopener noreferrer"&gt;demo Django project&lt;/a&gt;, which includes tests. &lt;/p&gt;

&lt;p&gt;GitHub actions run on GitHub repositories and not on our machines. Only the owner of the repository can manage workflow runs. Later in the article, we will cover what Workflows are.&lt;/p&gt;

&lt;p&gt;We need to fork the repository and clone it.&lt;/p&gt;

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

git clone &amp;lt;REPOSITORY_URL&amp;gt;


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

&lt;/div&gt;

&lt;p&gt;We should set up a new virtual environment.&lt;/p&gt;

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


&lt;span class="c"&gt;# linux and mac&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; &amp;lt;PROJECT_DIR&amp;gt;
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv
&lt;span class="nb"&gt;source &lt;/span&gt;venv/bin/activate


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

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


# windows
cd &amp;lt;PROJECT_DIR&amp;gt;
python3 -m venv venv
venv/Scripts/activate  # &amp;lt;-- difference


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

&lt;/div&gt;

&lt;p&gt;Now we need to install the project dependencies. Run this command in the project directory. This will install all the dependencies specified in &lt;code&gt;requirements.txt&lt;/code&gt; file.&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;Now that our application setup is complete. Let’s run our tests will. The tests confirm the reliability of our application.&lt;/p&gt;

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

&lt;span class="nb"&gt;cd &lt;/span&gt;project
python manage.py &lt;span class="nb"&gt;test&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The tests are successful. We can now go ahead and automate this process using GitHub actions.😊&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Automated tests don’t only work when we use Django’s built-in test runners. We can write automation for any kind of test runners we are using. One popular test runner in the Python community is Pytest.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What are GitHub Actions?
&lt;/h2&gt;

&lt;p&gt;To get started, we need to define a &lt;a href="https://docs.github.com/en/actions/using-workflows/about-workflows" rel="noopener noreferrer"&gt;workflow&lt;/a&gt;. A workflow is a configurable automated process that will run one or more jobs. A step is a command or action that performs a basic task. An Action is a collection of steps, which makes an action reusable. A Job is an operation in a workflow that contains steps. Jobs can run in parallel or in sequence.&lt;/p&gt;

&lt;p&gt;We define workflows by using a &lt;code&gt;YAML&lt;/code&gt; file checked in the repository. A workflow will execute when triggered by an event in the same repository it exists. &lt;/p&gt;

&lt;p&gt;GitHub workflows listen to many events, examples are push and pull requests. The events configured into our &lt;code&gt;YAML&lt;/code&gt; file trigger our workflow. For example, when we push a new commit to the master branch, this can trigger a testing workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating A Testing Workflow
&lt;/h2&gt;

&lt;p&gt;Let’s create a workflow that executes our Django application tests.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Workflows are not for testing but for executing jobs which can be anything. An example of this is running tests. Our tests are already defined. We configure workflows to execute them. Other use cases are deployments and closing pull requests.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Create a new directory called .github/workflows in the root directory. Create a new file called &lt;code&gt;test.yml&lt;/code&gt; in the .github/workflows directory. This file will be our workflow &lt;code&gt;YAML&lt;/code&gt; configuration.&lt;/p&gt;

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


&lt;span class="c1"&gt;# test.yml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Django Tests&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;master&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test-django-app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;fail-fast&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.9"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;fetch-depth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up Python ${{ matrix.python-version }}&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-python@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ matrix.python-version }}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;python -m pip install --upgrade pip&lt;/span&gt;
          &lt;span class="s"&gt;if [ -f requirements.txt ]; then pip install -r requirements.txt; fi&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Django test&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;cd project&lt;/span&gt;
          &lt;span class="s"&gt;python manage.py test&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Let’s break down what each syntax means and how this executes the application tests.&lt;/p&gt;

&lt;p&gt;We start by defining the workflow name by using the name syntax.&lt;/p&gt;

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

name: Run Django Tests


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

&lt;/div&gt;

&lt;p&gt;The workflow name helps us identify the workflow in our repository’s GitHub Actions tab.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The GitHub Actions tab helps us to manage workflow runs. See how to manage a workflow run on GitHub.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Next, we define the event that triggers the workflow.&lt;/p&gt;

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

on:
  push:
    branches: [master]


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

&lt;/div&gt;

&lt;p&gt;By using the on &lt;a href="https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#on" rel="noopener noreferrer"&gt;syntax&lt;/a&gt;,  every commit we push to the master branch triggers the workflow run. We can specify many events and branches.&lt;/p&gt;

&lt;p&gt;Next, we have the &lt;a href="https://docs.github.com/en/actions/using-jobs/using-jobs-in-a-workflow" rel="noopener noreferrer"&gt;jobs syntax&lt;/a&gt;.&lt;/p&gt;

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

jobs:
  test-django-app:


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

&lt;/div&gt;

&lt;p&gt;A scenario to use this is when we want to deploy a web application after successful tests. We can create two jobs, one for testing and the other for deployment. Then configure the deployment to run after when tests are complete and successful.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The name of our job is test-django-app, we can name it anything. But make sure it’s descriptive, as it helps us identify the currently running job in the GitHub Actions tab.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Next, the &lt;a href="https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idruns-on" rel="noopener noreferrer"&gt;runs-on syntax&lt;/a&gt; defines what machine will run the job. Here we instructed it to use &lt;code&gt;ubuntu-latest&lt;/code&gt; version.&lt;/p&gt;

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

runs-on: ubuntu-latest


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

&lt;/div&gt;

&lt;p&gt;Next, the &lt;a href="https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategy" rel="noopener noreferrer"&gt;strategy syntax&lt;/a&gt; helps us define what Python versions we will use to test. In our workflow, we have defined only one version. The job will use each Python version declared in the list to execute itself in parallel.&lt;/p&gt;

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

strategy:
  fail-fast: false
  matrix:
    python-version: ["3.9"]


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

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;fail-fast&lt;/code&gt; applies to the entire matrix. If &lt;code&gt;fail-fast&lt;/code&gt; is set to &lt;code&gt;true&lt;/code&gt;, GitHub will cancel all in-progress and queued jobs in the matrix if any job in the matrix fails. This property defaults to &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Assuming that we built a Python package and set many Python versions. We can ensure the package undergoes testing across defined Python versions.&lt;/p&gt;

&lt;p&gt;Jobs contain a sequence of tasks called &lt;a href="https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idsteps" rel="noopener noreferrer"&gt;steps&lt;/a&gt;. Steps can run commands, set up docker, or run an action in our repository. These steps run one after the other based on their position in the &lt;code&gt;YAML&lt;/code&gt; definition.&lt;/p&gt;

&lt;p&gt;The following are the actions taken by each step in our workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Checkout the repository on the machine defined for the job,&lt;/li&gt;
&lt;li&gt;Setup Python using the current version from the strategy,&lt;/li&gt;
&lt;li&gt;Install pip and the project dependencies,&lt;/li&gt;
&lt;li&gt;Move into the project directory and run the tests.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We need to commit and push a new workflow to trigger our workflow.&lt;/p&gt;

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

git add .
git commit -m "Added tests automation using Github Actions"
git push


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

&lt;/div&gt;

&lt;p&gt;We should see a new running or completed workflow run on the GitHub actions tab in our forked repository.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F721sg5m1i926rksaw22x.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F721sg5m1i926rksaw22x.png" alt="GitHub workflow actions running page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This workflow would show us each job and the steps executed.&lt;/p&gt;

&lt;p&gt;![GitHub workflow job management tab(&lt;a href="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5tlk6am6n0dhwjn7s2mn.png" rel="noopener noreferrer"&gt;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5tlk6am6n0dhwjn7s2mn.png&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Now, any time we push a new commit to the master branch. Our workflow executes our Django application tests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions" rel="noopener noreferrer"&gt;Understanding GitHub Actions&lt;/a&gt; is a complete guide to learning actions, workflows, and jobs. Check it out to master project development automation.&lt;/p&gt;

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

&lt;p&gt;In this article, we have covered how GitHub actions execute Django application tests. Continuous Integration and Delivery is an important part of a modern development cycle. Automating development life cycles ensures we build reliable applications when working with collaborators.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions" rel="noopener noreferrer"&gt;Understanding GitHub Actions&lt;/a&gt; by GitHub&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/en-us/training/modules/introduction-to-github-actions/" rel="noopener noreferrer"&gt;Introduction to GitHub Actions Training&lt;/a&gt; by Microsoft&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.learnenough.com/blog/git-actions-tutorial" rel="noopener noreferrer"&gt;GitHub Actions Tutorial for Beginners&lt;/a&gt; to Automate Your Workflow&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>programming</category>
      <category>tutorial</category>
      <category>github</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Dynamically Managing Dependencies In Your Python Projects</title>
      <dc:creator>Israel Ayanwola</dc:creator>
      <pubDate>Wed, 03 May 2023 08:28:43 +0000</pubDate>
      <link>https://dev.to/devvspaces/dynamically-managing-dependencies-in-your-python-projects-4pai</link>
      <guid>https://dev.to/devvspaces/dynamically-managing-dependencies-in-your-python-projects-4pai</guid>
      <description>&lt;p&gt;In today's software development landscape, ensuring successful project deployment can be challenging due to the variety of environments programmers use to build their projects. Each environment presents unique challenges to project deployment from Windows to ArchLinux, Mac to Ubuntu.&lt;/p&gt;

&lt;p&gt;One major challenge developers face is conflicting environment dependencies, which can cause project failure when deployed. Although Docker solves this problem, its complex setup requirements make it inaccessible to many developers.&lt;/p&gt;

&lt;p&gt;This tutorial offers a solution by demonstrating how to dynamically install Python dependencies based on the environment in which the project will run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;With only a basic understanding of Python and Git, any developer can follow the methods outlined in this tutorial to improve their project's deployment success.&lt;br&gt;
The only requirement to have installed for this tutorial is Python. To install Python, visit their official downloads page.&lt;/p&gt;
&lt;h2&gt;
  
  
  What is the problem?
&lt;/h2&gt;

&lt;p&gt;When using Postgres database with Django, psycopg2 database adapter is a required dependency for this to work. But there is a problem, psycopg2 will install successfully on a Windows environment but won't on a Linux environment, you will need to install psycopg2-binary instead.&lt;/p&gt;

&lt;p&gt;Well, if your development and deployment environment is similar or you use Docker, you won't have a problem with this situation. The problem occurs when you have differing environments or multiple collaborators working on the project with you. You don't want them editing the requirements.txt file so as not to cause git conflicts.&lt;/p&gt;
&lt;h2&gt;
  
  
  How can this problem be solved?
&lt;/h2&gt;

&lt;p&gt;Two major methods will be shared today to help you dynamically install Python dependencies based on your environment or Python version.&lt;/p&gt;
&lt;h2&gt;
  
  
  Conditional pip requirements syntax
&lt;/h2&gt;

&lt;p&gt;Suppose that the dependencies listed in your requirements.txt file are as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;requests==2.26.0
six==1.16.0
urllib3==1.26.7
psycopg2==2.9.6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That can be modified to ensure that when you install the requirements on a Linux environment, the required database adapter for Linux will be installed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;requests==2.26.0
six==1.16.0
urllib3==1.26.7
psycopg2-binary==2.9.3; sys_platform == "linux"
psycopg2==2.9.6; sys_platform == "win32"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also program the dependencies to be installed based on the Python version installed on the environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;requests==2.26.0; python_version &amp;gt; '3.0'
requests==2.26.0; python_version == '2.6'
six==1.16.0
urllib3==1.26.7
psycopg2-binary==2.9.3; sys_platform == "linux"
psycopg2==2.9.6; sys_platform == "win32"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They are defined in PEP 508 and PEP 0345 (Environment Markers), but the syntax appears to follow the draft PEP 0496.&lt;/p&gt;

&lt;p&gt;To know all the possible values for &lt;code&gt;sys_platform&lt;/code&gt;&lt;code&gt;,&lt;/code&gt; visit this StackOverflow answer.&lt;/p&gt;

&lt;p&gt;Now when you run &lt;code&gt;pip install -r requirements.txt&lt;/code&gt;, depending on your environment, the appropriate dependency and version will be installed.&lt;/p&gt;

&lt;p&gt;This is the easiest and recommended method for dynamically installing dependencies based on the environment or Python version.&lt;/p&gt;

&lt;h3&gt;
  
  
  Python install script
&lt;/h3&gt;

&lt;p&gt;You could create an install.py script to install dependencies based on the environment or Python version.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Create a file install.py in your project's root directory&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pip&lt;/span&gt;

&lt;span class="n"&gt;_all_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"requests==2.26.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"six==1.16.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"urllib3==1.26.7"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# All platforms
&lt;/span&gt;
&lt;span class="n"&gt;windows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"psycopg2==2.9.6"&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt;  &lt;span class="c1"&gt;# Windows
&lt;/span&gt;
&lt;span class="n"&gt;linux&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"psycopg2-binary==2.9.3"&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt;  &lt;span class="c1"&gt;# Linux
&lt;/span&gt;
&lt;span class="n"&gt;darwin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;  &lt;span class="c1"&gt;# MacOS
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;packages&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Installing packages: {}"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;packages&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;packages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;pip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s"&gt;'install'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;package&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'__main__'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;platform&lt;/span&gt;

    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Platform: {}"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;platform&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_all_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;platform&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'win32'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;windows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;platform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'linux'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;linux&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;platform&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'darwin'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;darwin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Completed installation of packages."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This script works by checking what platform the program is running on using the Python built-in sys package. So it installs the defined dependencies for that platform by calling &lt;code&gt;pip&lt;/code&gt; by script. This method is more complex and time-consuming, but it gives you more control and flexibility on the program control flow.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Run the program to install the packages&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python install.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;In conclusion, conflicting environment dependencies can be a huge headache for software developers when deploying their projects. Fortunately, several solutions are available, including Docker and the dynamic installation of dependencies based on the environment. In this article, we have provided two different methods for dynamically installing Python dependencies based on the environment, which can help avoid conflicts and ensure the project runs smoothly across different platforms. These methods allow developers to save time, reduce errors, and focus on building great software. I hope that this article has been helpful in providing useful tips and tricks for managing environment dependencies in your Python projects.&lt;/p&gt;

&lt;p&gt;Thanks for reading, I'd also love to connect with you at &lt;a href="https://twitter.com/netrobeweb"&gt;Twitter&lt;/a&gt; | &lt;a href="https://www.linkedin.com/in/ayomide-ayanwola/"&gt;LinkedIn&lt;/a&gt; | &lt;a href="http://github.com/devvspaces"&gt;GitHub&lt;/a&gt; | &lt;a href="https://netrobe.vercel.app/"&gt;Portfolio&lt;/a&gt;. 🤓&lt;/p&gt;

</description>
      <category>python</category>
      <category>pypi</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Building a Tech Course Curriculums Platform with MindsDB Models and Django</title>
      <dc:creator>Israel Ayanwola</dc:creator>
      <pubDate>Sun, 30 Apr 2023 22:59:14 +0000</pubDate>
      <link>https://dev.to/devvspaces/building-a-tech-course-curriculums-platform-with-mindsdb-models-and-django-f9b</link>
      <guid>https://dev.to/devvspaces/building-a-tech-course-curriculums-platform-with-mindsdb-models-and-django-f9b</guid>
      <description>&lt;p&gt;Introduction: As a developer, I often find myself overwhelmed by the abundance of free and paid online tech courses and resources. That's why I decided to build a platform that curates the best tech course curriculums and organizes them based on skill level, topic, and user feedback. To improve the user experience and accelerate app growth, I integrated MindsDB models for sentiment and text classification into the platform. In this tutorial, I'll walk you through how I used MindsDB models and Django for the backend and Next.js for the frontend to build this platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;I built this project for a hackathon with the goal of helping new programmers find quality tech courses and resources. The platform curates the best resources and organizes them into curriculums based on user feedback. I wanted to improve the user experience and accelerate app growth by implementing MindsDB models for sentiment and text classification.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TTik2LrH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1682895270482/477b644d-37d2-4d91-846c-ac34d1fc9da5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TTik2LrH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1682895270482/477b644d-37d2-4d91-846c-ac34d1fc9da5.png" alt="" width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How I used MindsDB Models
&lt;/h2&gt;

&lt;p&gt;I used MindsDB models for sentiment and text classification to classify user curriculum reviews. The sentiment model determines if the review is positive, negative, or neutral, while the text classification model determines the topic or subject of the review, such as the quality of the resources, the user experience, or the difficulty level of the curriculum. The models are trained on a dataset of user reviews and are able to accurately classify new reviews with high accuracy.&lt;/p&gt;

&lt;p&gt;To use MindsDB, I used some AI models from the Huggingface repository. I was able to utilize the models by using some SQL queries. I labeled the reviews based on their sentiment and topic and then used MindsDB to train the sentiment and text classification models on this labeled dataset. Once the models were trained, I integrated them into the backend API, which allows me to classify new user reviews in real-time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backend and Frontend Technologies
&lt;/h2&gt;

&lt;p&gt;I used Django for the backend of my platform. Django is a powerful and popular Python-based web framework that allowed me to rapidly build a scalable and secure web application. I used Django to handle user authentication, curriculum enrollment, and progress tracking. I also added quizzes to the curriculums, which allow users to test their knowledge and track their progress.&lt;/p&gt;

&lt;p&gt;For the frontend, I used Next.js, a React-based framework that allowed me to build high-performance and SEO-friendly web applications. I used Next.js to create a responsive and intuitive user interface that makes it easy for users to discover and enroll in the curated curriculums. I also used Next.js to integrate the MindsDB models into the platform, allowing me to classify user reviews in real-time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building The Project
&lt;/h2&gt;

&lt;p&gt;I will cover the project build-up from the DB design to the product mvp completion. The repository for the completed project is listed below;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/devvspaces/roadflow-api"&gt;Backend Repository&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/devvspaces/roadflow-web"&gt;Frontend Repository&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Database Design
&lt;/h3&gt;

&lt;p&gt;By using &lt;a href="https://dbdiagram.io/"&gt;diagram software&lt;/a&gt;, I designed a database diagram that I can follow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nSO0GF-M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/devvspaces/roadflow-api/raw/dev/Roadflow%2520DB.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nSO0GF-M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/devvspaces/roadflow-api/raw/dev/Roadflow%2520DB.png" alt="" width="800" height="1059"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This helped me get clarity on how I am going to structure the complex project. I could get tables that are related to each other and how to categorize the apps in Django. It saved me a lot of time instead of just jumping on the project without direction.&lt;/p&gt;

&lt;h3&gt;
  
  
  Application Design
&lt;/h3&gt;

&lt;p&gt;I designed the frontend application using NextJs, Redux, Formik, and Chakra. I mustn't try to rebuild the wheel for form validation or basic components. Chakra helped to move faster with design, I won't say the app design is perfect but it was amazing to build.&lt;/p&gt;

&lt;p&gt;I used redux to manage some of my states when working on the curriculum learning navigation. It was needed to send state changes to a parent component. I used redux for this purpose made it very easy to update the navigation based on the current tab being viewed by the learner.&lt;/p&gt;

&lt;h2&gt;
  
  
  Impact
&lt;/h2&gt;

&lt;p&gt;By using MindsDB models, I'm able to quickly and accurately classify user curriculum reviews, allowing me to identify and address areas for improvement. Using the MindsDb cloud made it easier to integrate AI into the application. Doing this the manual way is not easy to manage.&lt;/p&gt;

&lt;p&gt;This helps me to continually improve the platform and curate the best possible curriculums for users. Additionally, by using Django and Next.js, I'm able to build a scalable and secure platform that can handle a large number of users and provide a seamless user experience.&lt;/p&gt;

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

&lt;p&gt;In this tutorial, I showed you how to use MindsDB models and Django for the backend and Next.js for the frontend to build a tech course curriculums platform. By implementing MindsDB models for sentiment and text classification, you can quickly and accurately classify user curriculum reviews and improve the user experience of your platform. With the power of Django and Next.js, you can build a scalable and secure platform that provides a seamless user experience.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Create and Manage Cryptographically Strong Tokens with Python for Better Web Application Security</title>
      <dc:creator>Israel Ayanwola</dc:creator>
      <pubDate>Fri, 14 Apr 2023 20:48:01 +0000</pubDate>
      <link>https://dev.to/devvspaces/create-and-manage-cryptographically-strong-tokens-with-python-for-better-web-application-security-f5i</link>
      <guid>https://dev.to/devvspaces/create-and-manage-cryptographically-strong-tokens-with-python-for-better-web-application-security-f5i</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq7tm0x0u8otgy1a69irh.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq7tm0x0u8otgy1a69irh.jpeg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Secret key management is a crucial aspect of a software engineer's daily routine. In this article, you will explore how to create and manage cryptographically secure keys in Python using the popular Pypi cryptography module. You will also learn the importance of securely storing these keys to ensure maximum protection of sensitive data in your web applications and software.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;You must install Python on your machine if you don't have it installed. Its the only needed external requirement. You can install Python from their official &lt;a href="https://www.python.org/downloads/" rel="noopener noreferrer"&gt;downloads&lt;/a&gt; page. Its recommended to install the latest version of Python for this tutorial.&lt;/p&gt;

&lt;p&gt;To follow up with this tutorial, you are required to have some knowledge about writing simple Python programs. All the packages that will be discussed are from the Python standard library or Pypi package manager.&lt;/p&gt;

&lt;h2&gt;
  
  
  Secured Symmetrical Encryption Keys
&lt;/h2&gt;

&lt;p&gt;When it comes to encryption and decryption in Python, the Pypi cryptography module is a popular choice. One of the easiest and most secure ways to implement symmetric cryptography using this module is through Fernet symmetrical encryption. However, to use Fernet keys for symmetric encryption, they must be generated and stored securely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's dive in.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Start by creating a new Python project and set up your virtual environment to separate your project dependencies from your global dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv
&lt;span class="c"&gt;# or&lt;/span&gt;
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Python command above is possible with Python3. If you have any errors setting this up, check out Python's official &lt;a href="https://docs.python.org/3/library/venv.html#creating-virtual-environments" rel="noopener noreferrer"&gt;venv documentation&lt;/a&gt; to learn about creating a virtual environment.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Activate the created environment
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Windows: cmd.exe&lt;/span&gt;
venv&lt;span class="se"&gt;\S&lt;/span&gt;cript&lt;span class="se"&gt;\a&lt;/span&gt;ctivate

&lt;span class="c"&gt;# Linux: bash or Mac: zsh&lt;/span&gt;
&lt;span class="nb"&gt;source &lt;/span&gt;venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Depending on your shell, the command for activating your virtual environment will be different. Check this&lt;/em&gt; &lt;a href="https://docs.python.org/3/library/venv.html#how-venvs-work" rel="noopener noreferrer"&gt;&lt;em&gt;reference&lt;/em&gt;&lt;/a&gt; &lt;em&gt;for the command that will work for your shell.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Now you need to install &lt;code&gt;cryptography&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;cryptography
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you encounter any installation issues, you can check out its &lt;a href="https://cryptography.io/en/latest/installation/" rel="noopener noreferrer"&gt;installation guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Enter the Python shell and run the following commands to generate the key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;cryptography.fernet&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Fernet&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Fernet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_key&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;RAuFlYBGswBmBOccV13UNYXxJTi19LCGhUOLZOi6oFY=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The value &lt;code&gt;RAuFlYBGswBmBOccV13UNYXxJTi19LCGhUOLZOi6oFY=&lt;/code&gt; in the byte string is the important key. It's stored like that because that's what the cryptography library likes to work with. So, if you generate a new key in the future, you need to convert it to bytes before passing it to any hash function.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is Fernet.generate_key() cryptographically secure?
&lt;/h3&gt;

&lt;p&gt;The answer is a resounding &lt;strong&gt;YES!&lt;/strong&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%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1678703995808%2F4320fe8e-3dba-4eeb-a30f-2899445182d2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1678703995808%2F4320fe8e-3dba-4eeb-a30f-2899445182d2.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The implementation of Fernet.generate_key method uses the function os.urandom, which has more sufficient randomness than the random function from the built-in random module.&lt;/p&gt;

&lt;p&gt;Why? It's because os.urandom cannot be seeded like random and draws its source of entropy from many unpredictable sources, making it more random. For more understanding, you can check this StackOverflow &lt;a href="https://stackoverflow.com/a/47515179" rel="noopener noreferrer"&gt;answer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now you can use your securely generated key to encrypt and decrypt data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Initialize a Fernet object
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Fernet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Generate a cryptographically secure and url-safe fernet token
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hashnode Neptune is the best&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;gAAAAABkDv-R51WpztocZoMMat3UyKg8jz6KgCQgCq4g9SU36OF7kiPhqQwjLXPT-39lbb5cL-MlUWSmoDLKXlkOZo2Od_Icp_6jPFLDgF32f2r9agrRr50=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There you have it. You have generated a secure token that you can use to ensure your data security in your projects.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;If you don't want to use the generate_key function to create your Fernet tokens. You can use this&lt;/em&gt; &lt;a href="https://stackoverflow.com/a/72765116" rel="noopener noreferrer"&gt;&lt;em&gt;resource&lt;/em&gt;&lt;/a&gt; &lt;em&gt;to generate a more secure and strong token using the PBKDF2HMAC algorithm.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Securely Managing Your Secret Keys
&lt;/h2&gt;

&lt;p&gt;To ensure complete security, you must store your keys safely. Never share with anyone.&lt;/p&gt;

&lt;p&gt;One easy way to do this is to use Pypi &lt;a href="https://pypi.org/project/python-decouple/" rel="noopener noreferrer"&gt;decouple&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Let's start by installing it in our environment.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;python-decouple
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create a file &lt;code&gt;.env&lt;/code&gt; in your project directory. Add the key generated earlier to the file.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SECRET_KEY="RAuFlYBGswBmBOccV13UNYXxJTi19LCGhUOLZOi6oFY="
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Save the file.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new Python program, &lt;code&gt;main.py&lt;/code&gt;, in your project directory. Then paste the code added below into the file.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;decouple&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;

&lt;span class="n"&gt;SECRET_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SECRET_KEY&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SECRET_KEY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the &lt;code&gt;main.py&lt;/code&gt; python program.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python main.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The secret key stored in the environment file would be displayed. Decouple is a project used to store the environment and secret keys. You can read more at &lt;a href="https://pypi.org/project/python-decouple/" rel="noopener noreferrer"&gt;Pypi Decouple&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What makes this approach better than using an operating system environment? Because it makes it easier to share secrets when collaborating with others. They only need to clone the project and copy the &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Also, it eliminates the collision of similar keys on multiple projects on the same machine. As a bonus, you can create a file &lt;code&gt;env.example&lt;/code&gt;, this file will contain the keys from the actual .env file but with fake values.&lt;/p&gt;

&lt;p&gt;Your collaborator can then;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create their &lt;code&gt;.env&lt;/code&gt; file,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copy the contents of the &lt;code&gt;env.example&lt;/code&gt; file into their &lt;code&gt;.env&lt;/code&gt; file,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Generate a secret key,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Replace the sample (fake) key in the &lt;code&gt;.env&lt;/code&gt; file with the newly generated key.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Ensure you don't forget to add&lt;/em&gt; &lt;code&gt;.env&lt;/code&gt; &lt;em&gt;file to&lt;/em&gt; &lt;code&gt;.gitignore&lt;/code&gt; &lt;em&gt;so it doesn't get pushed to your GitHub repository, thereby exposing your keys. It's better to have a sample file like&lt;/em&gt; &lt;code&gt;env.example&lt;/code&gt; &lt;em&gt;which can be pushed to keep track of what keys a collaborator needs to create when running the project on their machine.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Using Python Built-in Secrets Library
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://docs.python.org/3/library/secrets.html#:~:text=The%20secrets%20module%20is%20used%20for%20generating%20cryptographically%20strong%20random%20numbers%20suitable%20for%20managing%20data%20such%20as%20passwords%2C%20account%20authentication%2C%20security%20tokens%2C%20and%20related%20secrets." rel="noopener noreferrer"&gt;From Python Documentation&lt;/a&gt;: The &lt;code&gt;secrets&lt;/code&gt; module is used for generating cryptographically strong random numbers suitable for managing data such as passwords, account authentication, security tokens, and related secrets.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Use the Secrets library for security purposes to generate something random, like random tokens, digits, or strings. Its randomness is cryptographically secure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating a secure hex token&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run your Python shell.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;secrets&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;token_hex&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20a3f7333abd0668e474d393870a0b47463a6935e2eb730343820767eaf77226&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a simple way to create a very secure token. The longer the token the more sufficient the randomness.&lt;/p&gt;

&lt;p&gt;The function &lt;code&gt;token_hex&lt;/code&gt; accepts a parameter, &lt;code&gt;n_bytes&lt;/code&gt;, for how long you want the token.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;secrets&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;token_hex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;
&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;5222cffc8c2881afcbf219c90c6e2f3a8b168c7547f790c2e852a047e9f4c8094577d8198a1d802ee053d13987e9111b317a7771c9ce87597a67203311afc69f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://docs.python.org/3/library/secrets.html" rel="noopener noreferrer"&gt;Read more in the Python Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you can use generate highly secure tokens for your projects. These tokens can be used as a secret key in any project, Django, NodeJS, Golang, etc.&lt;/p&gt;

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

&lt;p&gt;Securing web applications and software requires effective management of secret keys. Python offers libraries like cryptography and secrets that simplify the process of generating cryptographically secure tokens. To ensure maximum protection of sensitive data, it is crucial to store these keys securely using tools like Pypi Decouple and AWS Secrets Manager. By adhering to best practices for managing secret keys, developers can guarantee the security of their projects and prevent unauthorized access to sensitive information.&lt;/p&gt;

&lt;h1&gt;
  
  
  Read more
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://cryptography.io/en/latest/hazmat/primitives/" rel="noopener noreferrer"&gt;Cryptography Algorithms - Primitives&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.onelogin.com/learn/password-vaulting" rel="noopener noreferrer"&gt;Password Vaults&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html" rel="noopener noreferrer"&gt;AWS Secrets Manager&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Follow me on Twitter &lt;a href="https://twitter.com/netrobeweb" rel="noopener noreferrer"&gt;@netrobeweb&lt;/a&gt;, &lt;a href="https://hashnode.com/@netrobe" rel="noopener noreferrer"&gt;Hashnode&lt;/a&gt;, and &lt;a href="http://Dev.to" rel="noopener noreferrer"&gt;Dev.to&lt;/a&gt; where I post amazing projects and articles.&lt;/p&gt;

&lt;p&gt;Thanks for reading, 🤓😊&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1681504977071%2F055d4a54-dc80-47b1-8cc2-e7efcc42cf1c.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1681504977071%2F055d4a54-dc80-47b1-8cc2-e7efcc42cf1c.gif"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Build a Speech Authentication System with Django and Next JS - Part 1</title>
      <dc:creator>Israel Ayanwola</dc:creator>
      <pubDate>Fri, 07 Apr 2023 21:02:06 +0000</pubDate>
      <link>https://dev.to/devvspaces/how-to-build-a-speech-authentication-system-with-django-and-next-js-part-1-3lhj</link>
      <guid>https://dev.to/devvspaces/how-to-build-a-speech-authentication-system-with-django-and-next-js-part-1-3lhj</guid>
      <description>&lt;p&gt;Learn how to build a speech authentication system with Django in this comprehensive tutorial. With the help of a Python package that converts speech to text, users can enter their details by speaking. The system includes a registration and login page and once logged in, users will be greeted with a welcome voice. Follow the step-by-step guide to set up the backend API using Django and the frontend using Next.js and Chakra UI.&lt;/p&gt;

&lt;h3&gt;
  
  
  TL;DR
&lt;/h3&gt;

&lt;p&gt;The system includes a registration and login page and once logged in, users will be greeted with a welcome voice. Follow the step-by-step guide to set up the backend API using Django and the frontend using Next.js and Chakra UI. The article also covers the prerequisites, project setup, installations, and building of the API. The API includes endpoints for Registration, Login, JWT Token Refresh, User Retrieve, and Speech to Text.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Hey there! To make the most of this article, it would be helpful to have a solid understanding of &lt;a href="https://docs.djangoproject.com/en/4.1/intro/tutorial01/"&gt;Django&lt;/a&gt;, &lt;a href="https://www.django-rest-framework.org/tutorial/quickstart/"&gt;Django Rest Framework&lt;/a&gt;, and &lt;a href="https://nextjs.org/docs/getting-started"&gt;Next.js&lt;/a&gt;. Don't worry though, we'll do our best to explain things clearly and make it easy to follow along.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;First of all, we would work on the backend. Django will be used for the Backend and Next.js + Charkra UI for the front end. Django is used because we would be using a Python package that helps us convert speech to text.&lt;/p&gt;

&lt;h3&gt;
  
  
  Application Design
&lt;/h3&gt;

&lt;p&gt;The overall application design will be very simple. The backend will be an API which the frontend will consume.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A user's voice will be recorded on the frontend.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The frontend sends the recorded wav file to the backend in &lt;a href="https://en.wikipedia.org/wiki/Base64"&gt;Base64&lt;/a&gt; format.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The backend will process the data and convert it to text.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The text is returned to the frontend as a response,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;then text is entered into the UI input box.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it, very simple.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Setup
&lt;/h2&gt;

&lt;p&gt;This project is already available on &lt;a href="https://github.com/devvspaces/speech_to_text_auth"&gt;GitHub&lt;/a&gt;. Clone it and follow the installation guide in the &lt;a href="https://github.com/devvspaces/speech_to_text_auth#readme"&gt;Readme&lt;/a&gt; to set up the project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installations
&lt;/h3&gt;

&lt;p&gt;For building this project, we will need to have the following installed;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.python.org/downloads/"&gt;Python 3.9&lt;/a&gt; - This is used for the backend, and Django is used as the framework.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.npmjs.com/downloading-and-installing-node-js-and-npm"&gt;NodeJs &amp;amp; NPM&lt;/a&gt; - This is used for the frontend.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Building the API
&lt;/h2&gt;

&lt;p&gt;Let's clone the project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/devvspaces/speech_to_text_auth
cd speech_to_text_auth

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

&lt;/div&gt;



&lt;p&gt;For now, we would be working on the API. Move into the &lt;code&gt;api&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Set up your virtual environment&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python -m venv venv
# Or python3 if you have that installed
python3 -m venv venv

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

&lt;/div&gt;



&lt;p&gt;Check out this &lt;a href="https://docs.python.org/3/library/venv.html"&gt;python documentation&lt;/a&gt; to learn about virtual environments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Activate the environment.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# windows: cmd.exe
venv\Scripts\activate

# bash or zsh
source venv/bin/activate

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

&lt;/div&gt;



&lt;p&gt;If the above commands don't work, check out this &lt;a href="https://docs.python.org/3/library/venv.html"&gt;python documentation&lt;/a&gt; for help activating virtual environments. If you encounter an issue activating your virtual environment, here is a &lt;a href="https://docs.python.org/3/library/venv.html#how-venvs-work"&gt;list of commands for common shells&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Installing requirements&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# This will install the requirements in the requirements.txt file
pip install -r requirements.txt

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

&lt;/div&gt;



&lt;p&gt;Move into the &lt;code&gt;src&lt;/code&gt; directory. There we have the account application, config, tests, and utils directories.&lt;/p&gt;

&lt;p&gt;Now we need to create our &lt;code&gt;.env&lt;/code&gt; file. This is where our secret configurations are kept. &lt;a href="https://pypi.org/project/python-decouple/"&gt;Decouple&lt;/a&gt; is used for accessing this file in our config files e.g &lt;code&gt;manage.py&lt;/code&gt;, &lt;code&gt;wsgi.py&lt;/code&gt;, etc.&lt;/p&gt;

&lt;p&gt;Create a new file, &lt;code&gt;.env&lt;/code&gt; and copy the contents of &lt;code&gt;.env.example&lt;/code&gt; into it.&lt;/p&gt;

&lt;p&gt;Now we need to create a Postgres DB for our project. By default, the project uses PostgreSQL but can be changed in the settings file. We can also create a DB for tests if we want to run tests. It's customary to have a separate database for development and testing because well testing uses autogenerated data which we don't want in our development database.&lt;/p&gt;

&lt;p&gt;The config folder is where our settings are located. This directory contains a settings directory which contains two Python files, &lt;code&gt;base.py&lt;/code&gt; and &lt;code&gt;test.py&lt;/code&gt;. Having our settings file arranged like this helps us to write separate settings for different environments.&lt;/p&gt;

&lt;p&gt;We could&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;develop using the &lt;code&gt;base.py&lt;/code&gt;,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;test using the &lt;code&gt;test.py&lt;/code&gt;,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;maybe create a file &lt;code&gt;staging.py&lt;/code&gt; for our staging environment in a live server&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;and &lt;code&gt;production.py&lt;/code&gt; for our production environment.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The tests folder contains our tests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accounts Application
&lt;/h3&gt;

&lt;p&gt;This is the only application on the project and the most important because we will store users' data here. The API views, models, and serializers are designed here.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/devvspaces/speech_to_text_auth/blob/master/api/src/account/models.py"&gt;&lt;strong&gt;models.py&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a basic Django custom user &lt;a href="https://docs.djangoproject.com/en/4.1/topics/db/models/"&gt;model&lt;/a&gt; implementation. By inheriting the Django AbstractBaseUser model, we can build our User model and make email required.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--J3Fb1abo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1680898951819/ef93ab84-3dd3-4edd-b349-84b24c7deca3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--J3Fb1abo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1680898951819/ef93ab84-3dd3-4edd-b349-84b24c7deca3.png" alt="" width="800" height="519"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the DBML structure used for the diagram above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Use DBML to define your database structure
// Docs: https://www.dbml.org/docs
// DB Diagram tool: https://dbdiagram.io/home

Table users {
  pk integer [primary key]
  email varchar
  active boolean
  staff boolean
  admin boolean
  created timestamp
}

Table profile {
  pk integer [primary key]
  user_id integer
  fullname varchar
  sex varchar
  phone varchar
  country varchar
}

Ref: profile.user_id - users.pk // one-to-one

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

&lt;/div&gt;



&lt;p&gt;The User model has a &lt;a href="https://docs.djangoproject.com/en/4.2/topics/db/examples/one_to_one/"&gt;one-to-one relationship&lt;/a&gt; with the Profile model. This is a very common way to design a User table. The reason for this is to make sure that when there is a change in business logic that will slightly affect how the User is created. We will update the Profile model instead so that we won't have migration issues with the User model.&lt;/p&gt;

&lt;p&gt;When a user is created, we automatically create its profile by listening to the &lt;code&gt;post_save&lt;/code&gt; signal. Learn more about &lt;a href="https://docs.djangoproject.com/en/4.1/topics/signals/"&gt;Django Signals&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/devvspaces/speech_to_text_auth/blob/master/api/src/account/forms.py"&gt;&lt;strong&gt;forms.py&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We need a custom user registration form because we need a way to make the Django admin create a User correctly. This form allows the admin to enter the user's profile data when creating the user. The default Django admin form will have only fields for the User model.&lt;/p&gt;

&lt;p&gt;By overriding the model form &lt;a href="https://github.com/devvspaces/speech_to_text_auth/blob/master/api/src/account/forms.py#:~:text=def%20save(self%2C%20commit%3DTrue)%3A"&gt;save method&lt;/a&gt;, we get the validated profile data and populate the already created user profile. As soon as the &lt;code&gt;user.save()&lt;/code&gt; is invoked, the profile will be created by the &lt;code&gt;post_save&lt;/code&gt; signal from earlier.&lt;/p&gt;

&lt;p&gt;Learn more about creating &lt;a href="https://docs.djangoproject.com/en/4.1/topics/forms/modelforms/"&gt;Django Model Form&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/devvspaces/speech_to_text_auth/blob/master/api/src/account/admin.py"&gt;&lt;strong&gt;admin.py&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One important thing here is, we create a UserAdmin class for overriding the default that will be created by Django. Read more about &lt;a href="https://docs.djangoproject.com/en/4.1/ref/contrib/admin/"&gt;Customizing Django Model Admin&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Django &lt;code&gt;BaseUserAdmin&lt;/code&gt; is a special ModelAdmin that allows us to override the form used for creating a new User instance in the admin. So we pass the form we created earlier here.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/devvspaces/speech_to_text_auth/blob/master/api/src/config/settings/base.py"&gt;&lt;strong&gt;config/settings/base.py&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An important thing to note here is that after creating a Custom Django User Model we need to tell Django we want to use it instead of the default.&lt;/p&gt;

&lt;p&gt;The line below tells Django to use our new Custom User Model instead of its default User Model. This is a very common implementation in Django, here is a &lt;a href="https://github.com/devvspaces/django-restframework-template"&gt;Django Rest Framework GitHub template&lt;/a&gt; that we can use as a project boilerplate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AUTH_USER_MODEL = 'account.User'

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

&lt;/div&gt;



&lt;p&gt;Decouple is used to access your environment keys, &lt;code&gt;.env&lt;/code&gt;. This &lt;a href="https://pypi.org/project/python-decouple/#example-how-do-i-use-it-with-django"&gt;documentation&lt;/a&gt; shares how to effectively use decouple with Django.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/devvspaces/speech_to_text_auth/blob/master/api/src/account/api/base/views.py"&gt;&lt;strong&gt;Views&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;and&lt;/strong&gt; &lt;a href="https://github.com/devvspaces/speech_to_text_auth/blob/master/api/src/account/api/base/serializers.py"&gt;&lt;strong&gt;Serializers&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we will cover the Django rest framework views and serializers. We need the following endpoints;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Registration [POST],&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Login [POST],&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;JWT Token Refresh [POST],&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;User Retrieve [GET], and&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Speech to Text [POST].&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Registration [POST]&lt;/strong&gt;: The endpoint will be used to create a new user. The data that will be received through all the endpoints will be in JSON format. The endpoint uses the imported RegisterSerializer to convert post data into native Python datatypes and validate them. An important thing to note here is that we are using &lt;a href="https://jwt.io/introduction"&gt;JSON Web Token (JWT)&lt;/a&gt; for authenticating our users. As soon as a new account is created, new access and refresh tokens are included in the response. Read more about &lt;a href="https://django-rest-framework-simplejwt.readthedocs.io/en/latest/"&gt;Simple JWT&lt;/a&gt;, A JSON Web Token authentication plugin for the Django REST Framework.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Login [POST]&lt;/strong&gt;: Validates the user data and returns a response that contains the tokens and logged-in user data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JWT Token Refresh [POST]&lt;/strong&gt;: This is used to get a new access token using a valid refresh token. As JWT is a stateless authentication method, meaning there is no session stored for the user. Every 5 mins the access token previously generated is expired which requires the user to generate a new access token using the refresh token which is valid for 24 hours. The validation time for both the access and refresh tokens can be edited from the settings.py file. Learn more about this at &lt;a href="https://django-rest-framework-simplejwt.readthedocs.io/en/latest/settings.html#access-token-lifetime"&gt;Simple JWT&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;User Retrieve [GET]&lt;/strong&gt;: We need to be able to get the data of the currently authenticated user. This endpoint returns the data of the authenticated user.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Speech to Text [POST]&lt;/strong&gt;: This endpoint used the &lt;a href="https://pypi.org/project/SpeechRecognition/"&gt;SpeechRecognition package&lt;/a&gt;, to convert audio binary to text. This package supports Google, IBM, and Microsoft Speech-to-text APIs and many more. Here we are using Google Speech-to-text. Because of the abstraction, the package brings, we don't need to call any actual API to upload our audio files for processing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class SpeechToTextView(APIView):

    @swagger_auto_schema(
        request_body=serializers.SpeechBody,
    )
    def post(self, request, *args, **kwargs):
        """
        Convert speech to text, using Google Speech Recognition API
        Accepts a base64 encoded string of audio data
        Returns:
            Response: Response object with text
        """
        try:
            record: str = self.request.data.get('record')
            decoded_b64 = base64.b64decode(record)

            # Convert decoded_b64 to in-memory bytes buffer
            r = sr.Recognizer()
            with sr.AudioFile(io.BytesIO(decoded_b64)) as source:
                # listen for the data (load audio to memory)
                audio_data = r.record(source)
                # recognize (convert from speech to text)
                text = r.recognize_google(audio_data)

            return Response(data={'text': text})
        except Exception:
            return Response(
                data={'message': "Error converting speech to text"},
                status=status.HTTP_400_BAD_REQUEST)

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

&lt;/div&gt;



&lt;p&gt;The data that will be passed to this endpoint will be in base64 format because it's faster and easier to transfer and process in this form.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;decoded_b64 = base64.b64decode(record)

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

&lt;/div&gt;



&lt;p&gt;This takes the data received and decodes it using the built-in &lt;a href="https://docs.python.org/3/library/base64.html"&gt;base64&lt;/a&gt; library. The decoded data returned is in binary form. This is done so that we can convert it into a &lt;a href="https://docs.python.org/3/library/io.html#buffered-streams"&gt;Buffered stream&lt;/a&gt; in memory using &lt;code&gt;io.BytesIO(decoded_b64)&lt;/code&gt; , the built-in &lt;code&gt;io&lt;/code&gt; library which is used for working with Input and Output (I/O) streams.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What are Buffered I/O streams in Python?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Buffered I/O streams in Python's &lt;a href="https://docs.python.org/3/library/io.html"&gt;&lt;code&gt;io&lt;/code&gt; module&lt;/a&gt; are classes that help improve the performance of I/O operations by buffering data in memory. Think of buffering as a way of temporarily storing data in a queue so that it can be accessed more efficiently later on. &lt;a href="https://medium.com/dev-bits/ultimate-guide-for-working-with-i-o-streams-and-zip-archives-in-python-3-6f3cf96dca50"&gt;Read more&lt;/a&gt; on Buffered streams to deeply understand how it works.&lt;/p&gt;

&lt;p&gt;When working with objects like Buffers, Files, or Database connections in Python &lt;a href="https://realpython.com/python-with-statement/"&gt;Context Managers&lt;/a&gt; are used to gain access to these objects because the connection is closed automatically even if there is an unhandled exception in the context manager.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;with sr.AudioFile(io.BytesIO(decoded_b64)) as source:
    # listen for the data (load audio to memory)
    audio_data = r.record(source)
    # recognize (convert from speech to text)
    text = r.recognize_google(audio_data)

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

&lt;/div&gt;



&lt;p&gt;If an error occurs while trying to record the audio source, which is the Buffer we created earlier in the memory, the I/O connection will be closed safely. This &lt;a href="https://towardsdatascience.com/why-you-should-use-context-managers-in-python-4f10fe231206#:~:text=What%20is%20a%20Context%20Manager,we%20are%20done%20with%20it."&gt;article explains why it's important to use Context Managers&lt;/a&gt; when dealing with objects like this.&lt;/p&gt;

&lt;p&gt;So the buffer is recorded and passed to google for speech-to-text processing. If all is well, we return the text in the response else we raise a BadRequest error.&lt;/p&gt;

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

&lt;p&gt;In conclusion, this article provides a comprehensive tutorial on how to build a speech authentication system with Django. The system allows users to enter their details by speaking and includes a registration and login page. The article covers the step-by-step guide to setting up the backend API using Django. The article also covers the necessary installations, project setup, and the design of the application. Overall, this article is a great resource for developers looking to build a speech authentication system.&lt;/p&gt;

&lt;p&gt;To make this article brief the next part which is Building the Frontend with Next.js will be covered in another article.&lt;/p&gt;

&lt;p&gt;You can follow me on &lt;a href="https://twitter.com/netrobeweb"&gt;Twitter&lt;/a&gt;, &lt;a href="https://hashnode.com/@netrobe"&gt;Hashnode&lt;/a&gt;, &lt;a href="https://dev.to/devvspaces"&gt;Dev.to&lt;/a&gt;, and &lt;a href="http://github.com/devvspaces"&gt;Github&lt;/a&gt;, where I post amazing projects and articles.&lt;/p&gt;

&lt;p&gt;Thanks for reading, 😉.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Streamline Your File Uploads with Cloudinary and NestJS</title>
      <dc:creator>Israel Ayanwola</dc:creator>
      <pubDate>Thu, 23 Mar 2023 10:06:02 +0000</pubDate>
      <link>https://dev.to/devvspaces/streamline-your-file-uploads-with-cloudinary-and-nestjs-12p3</link>
      <guid>https://dev.to/devvspaces/streamline-your-file-uploads-with-cloudinary-and-nestjs-12p3</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kl1Kp26q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1679565949785/a8a106ae-e262-4889-af79-20917851bf46.png%3Fw%3D1600%26h%3D840%26fit%3Dcrop%26crop%3Dentropy%26auto%3Dcompress%2Cformat%26format%3Dwebp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kl1Kp26q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1679565949785/a8a106ae-e262-4889-af79-20917851bf46.png%3Fw%3D1600%26h%3D840%26fit%3Dcrop%26crop%3Dentropy%26auto%3Dcompress%2Cformat%26format%3Dwebp" alt="" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cloudinary is a powerful serverless cloud-based storage infrastructure that allows easy file uploading for NestJS projects. In this article, we will explore the various methods of file uploading to Cloudinary and how to set it up in your NestJS project. Whether you are uploading file buffers, file URLs, or Base64 encoded strings, the Cloudinary NodeJS SDK and the steps outlined in this article make it easy to incorporate advanced file uploading into your NestJS project.&lt;/p&gt;

&lt;p&gt;If you don't know how to handle file upload in NestJs, this &lt;a href="https://dev.to/devvspaces/mastering-file-upload-and-validation-in-nestjs-with-multer-3266-temp-slug-661845"&gt;article&lt;/a&gt; explains how to efficiently incorporate file upload and validation into your NestJS project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Cloudinary Module
&lt;/h2&gt;

&lt;p&gt;One way to easily set it up in your NestJs projects is by creating a module for it. This allows you to use Dependency Injection design to use it in other providers or controllers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Installation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Install Cloudinary NodeJs SDK&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install cloudinary

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

&lt;/div&gt;



&lt;p&gt;Create a new module, &lt;code&gt;cloudinary&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Create file &lt;code&gt;constants.ts&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const CLOUDINARY = 'Cloudinary';

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

&lt;/div&gt;



&lt;p&gt;Add file &lt;code&gt;cloudinary.provider.ts&lt;/code&gt;, paste the code below into the file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
import { ConfigService } from '@nestjs/config';
import { v2 } from 'cloudinary';
import { CLOUDINARY } from './constants';

export const CloudinaryProvider = {
  provide: CLOUDINARY,
  useFactory: (config: ConfigService) =&amp;gt; {
    return v2.config({
      cloud_name: config.get('CLOUDINARY_CLOUD_NAME'),
      api_key: config.get('CLOUDINARY_API_KEY'),
      api_secret: config.get('CLOUDINARY_API_SECRET'),
    });
  },
  inject: [ConfigService],
};

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://docs.nestjs.com/techniques/configuration"&gt;ConfigService&lt;/a&gt; is used to assess keys in your secret file. For example, a &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Don't know how to set up env configurations in NestJs? &lt;a href="https://docs.nestjs.com/techniques/configuration"&gt;Read more&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Don't know how to create factory providers in NestJs? &lt;a href="https://docs.nestjs.com/fundamentals/custom-providers#factory-providers-usefactory"&gt;Read more&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;CloudinaryProvider&lt;/code&gt; provider is a Factory Provider. The &lt;code&gt;useFactory&lt;/code&gt; allows you to create providers dynamically. You can also inject other module-imported services into the &lt;code&gt;useFactory&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create the Cloudinary Service Injectable&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Add a new file, &lt;code&gt;cloudinary.service.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Injectable } from '@nestjs/common';

@Injectable()
export class CloudinaryService {   
}

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

&lt;/div&gt;



&lt;p&gt;This service will contain methods for uploading files to Cloudinary.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create the module file&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Add a new file, &lt;code&gt;cloudinary.module.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { CloudinaryProvider } from './cloudinary.provider';
import { CloudinaryService } from './cloudinary.service';

@Module({
    imports: [ConfigModule],
    providers: [CloudinaryProvider, CloudinaryService],
    exports: [CloudinaryProvider, CloudinaryService],
})
export class CloudinaryModule {}

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

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;ConfigModule&lt;/code&gt; is added to the module imports because &lt;code&gt;ConfigService&lt;/code&gt; in the &lt;code&gt;CloudinaryProvider&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setup .env file&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; in your root folder. Depending on how you structure your project, a general root folder could be the folder containing your &lt;code&gt;package.json&lt;/code&gt; file or where you run the command to start your server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CLOUDINARY_CLOUD_NAME=test
CLOUDINARY_API_KEY=test
CLOUDINARY_API_SECRET=test

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

&lt;/div&gt;



&lt;p&gt;Now you need to &lt;a href="https://cloudinary.com/documentation/how_to_integrate_cloudinary"&gt;create a free Cloudinary account&lt;/a&gt;. After creating your account, you can follow this &lt;a href="https://cloudinary.com/documentation/how_to_integrate_cloudinary#:~:text=during%20Q1%202023.-,Product%20Environment%20Credentials,-The%20Product%20Environment"&gt;guide&lt;/a&gt; to get your API key, secret and cloud name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setup ConfigModule&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In your &lt;code&gt;app.module.ts&lt;/code&gt; you will need to configure the &lt;code&gt;ConfigModule&lt;/code&gt;. This makes sure it finds the &lt;code&gt;.env&lt;/code&gt; file and populate itself with the keys and values, thereby making you access them with &lt;code&gt;ConfigService&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {
  Module,
  NestModule,
} from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule } from '@nestjs/config';

@Module({
  imports: [
    ConfigModule.forRoot(),
  ],
  controllers: [AppController],
  providers: [
    AppService,
  ],
})
export class AppModule implements NestModule {
}

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using Form data - File Buffers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Single File Upload
&lt;/h3&gt;

&lt;p&gt;Now that you have your &lt;code&gt;CloudinaryService&lt;/code&gt;. When you create a route that &lt;a href="https://thecodeway.hashnode.dev/mastering-file-upload-and-validation-in-nestjs-with-multer#heading-accepting-files"&gt;accepts file buffers&lt;/a&gt; using Multer. You can upload this file using the service. You just have to integrate the upload method from the Cloudinary package.&lt;/p&gt;

&lt;p&gt;Add the method below to your service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async uploadFile(
  file: Express.Multer.File,
): Promise&amp;lt;UploadApiResponse | UploadApiErrorResponse&amp;gt; {
  return new Promise((resolve, reject) =&amp;gt; {
    v2.uploader.upload_stream(
      {
        resource_type: 'auto',
      },
      (error, result) =&amp;gt; {
        if (error) return reject(error);
        resolve(result);
      }
    ).end(file.buffer)
  })
}

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

&lt;/div&gt;



&lt;p&gt;This simple method uses &lt;code&gt;v2.uploader.upload_stream&lt;/code&gt; to upload your file to Cloudinary in chunks, which is good for uploading large files in chunks instead of one long request.&lt;/p&gt;

&lt;p&gt;An &lt;code&gt;UploadApiResponse&lt;/code&gt; or &lt;code&gt;UploadApiErrorResponse&lt;/code&gt; is returned by the function. You can use this to know if the file was successfully uploaded or not.&lt;/p&gt;

&lt;p&gt;To access your uploaded file URL, use the example of a route for single file upload below to understand the process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { UploadedFile, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';

@Post('upload/single')
@UseInterceptors(FileInterceptor('file'))
@ApiOkResponse({ description: 'Upload image', type: String })
public async uploadSingleImage(@UploadedFile() file: Express.Multer.File) {
  const result = await this.cloudinaryService.uploadFile(file);
  return result.secure_url;
}

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

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;secure_url&lt;/code&gt; property is the URL for the file uploaded.&lt;/p&gt;

&lt;h3&gt;
  
  
  Uploading multiple file buffers
&lt;/h3&gt;

&lt;p&gt;Loop through all the files and upload each one after the other. The response is the list of secure URLs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async uploadFiles(
  files: Express.Multer.File[],
) {
  const urls = await Promise.all(files.map(async (file): Promise&amp;lt;string&amp;gt; =&amp;gt; {
    const { secure_url } = await this.uploadFile(file);
    return secure_url;
  }));
  return urls
}

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

&lt;/div&gt;



&lt;p&gt;The files were &lt;a href="https://www.w3schools.com/jsref/jsref_map.asp"&gt;mapped over&lt;/a&gt; and uploaded, and their URLs were returned by the &lt;a href="https://www.w3schools.com/jsref/jsref_map.asp"&gt;map callback function&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Uploading File with URLs
&lt;/h2&gt;

&lt;p&gt;What if you have a file URL and not a file buffer? It's simpler to upload that using Cloudinary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async uploadFileFromUrl(
  url: string,
): Promise&amp;lt;UploadApiResponse | UploadApiErrorResponse&amp;gt; {
  return v2.uploader.upload(url)
}

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

&lt;/div&gt;



&lt;p&gt;The URL passed to this would be uploaded to Cloudinary, which will then return a response containing the &lt;code&gt;secure_url&lt;/code&gt; if successful.&lt;/p&gt;

&lt;h3&gt;
  
  
  Uploading multiple file urls
&lt;/h3&gt;

&lt;p&gt;By following the same idea from uploading multiple file buffers. You can map through the urls, upload each and return the &lt;code&gt;secure_url&lt;/code&gt; for each. Then the function will return a list of URLs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async uploadFilesFromUrl(
  urls: string[],
) {
  return Promise.all(urls.map(async (url: string): Promise&amp;lt;string&amp;gt; =&amp;gt; {
    const { secure_url } = await this.uploadFileFromUrl(url);
    return secure_url;
  }));
}

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Uploading Base64 encoded strings
&lt;/h2&gt;

&lt;p&gt;Base64 is a binary-to-text encoding scheme that represents binary data in an American Standard Code for Information Interchange (ASCII) string format. An example of binary data is an image. Base64 can be uploaded too as a file, it's a string and not a buffer, which makes it easier to parse and upload to Cloudinary than file buffers.&lt;/p&gt;

&lt;p&gt;By utilizing the &lt;code&gt;upload&lt;/code&gt; function from the Cloudinary package, a base64 string can be uploaded to Cloudinary and get a URL for the uploaded file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async uploadFileFromBase64(
  data: string,
): Promise&amp;lt;UploadApiResponse | UploadApiErrorResponse&amp;gt; {
  return v2.uploader.upload(data)
}

async uploadManyBase64(
  files: string[],
) {
  const urls = await Promise.all(files.map(async (file): Promise&amp;lt;string&amp;gt; =&amp;gt; {
    const { secure_url } = await this.uploadFileFromBase64(file);
    return secure_url;
  }));
  return urls
}

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

&lt;/div&gt;



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

&lt;p&gt;In conclusion, Cloudinary is a powerful tool for file uploading and storage in NestJS projects. With the help of the Cloudinary NodeJS SDK and the steps outlined in this article, developers can easily set up a module for Cloudinary and upload files using various available methods including file buffers, file URLs, and Base64 encoded strings. While Cloudinary is free to set up initially, developers may need to pay for used services once they start using it past some limit.&lt;/p&gt;

&lt;p&gt;I'd love to connect with you on &lt;a href="https://twitter.com/netrobeweb"&gt;&lt;strong&gt;Twitter&lt;/strong&gt;&lt;/a&gt; | &lt;a href="https://www.linkedin.com/in/ayomide-ayanwola/"&gt;&lt;strong&gt;LinkedIn&lt;/strong&gt;&lt;/a&gt; | &lt;a href="http://github.com/devvspaces"&gt;&lt;strong&gt;GitHub&lt;/strong&gt;&lt;/a&gt; | &lt;a href="https://netrobe.vercel.app/"&gt;&lt;strong&gt;Portfolio&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;See you in my next blog article. Take care!!!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Creating Admin Panels for NestJs and Prisma Made Easy with AdminJS</title>
      <dc:creator>Israel Ayanwola</dc:creator>
      <pubDate>Tue, 21 Mar 2023 12:52:51 +0000</pubDate>
      <link>https://dev.to/devvspaces/creating-admin-panels-for-nestjs-and-prisma-made-easy-with-adminjs-j8g</link>
      <guid>https://dev.to/devvspaces/creating-admin-panels-for-nestjs-and-prisma-made-easy-with-adminjs-j8g</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6hj03inworxng3wucxh8.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6hj03inworxng3wucxh8.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Are you tired of spending too much time creating admin panels for your NestJs and Prisma applications? Look no further than AdminJS! This powerful framework allows you to create a fully functional admin dashboard with just a few lines of code. With its compatibility with various ORM and ODM models, it simplifies the process of performing CRUD operations on your models.&lt;/p&gt;

&lt;p&gt;Plus, with customization options available, you can tailor the dashboard to meet your specific project needs. Keep reading to learn how to get started with AdminJS and take control of your application's data management.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is ORM
&lt;/h3&gt;

&lt;p&gt;Object-relational mapping (ORM, O/RM, and O/R mapping tool) in computer science is a programming technique for converting data between incompatible type systems using object-oriented programming languages.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is ODM?
&lt;/h3&gt;

&lt;p&gt;Object Document Mapper (ODM) is a library that helps you to work with MongoDB databases. It provides an abstraction layer between the database and the application code. It allows you to use the object-oriented paradigm to work with the database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;AdminJs/NestJs =&amp;gt; AdminJs/Prisma =&amp;gt; Resources and Customizations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Above is a very simple flow that describes the process of setting up AdminJs on your NestJs project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Install Requirements&lt;/strong&gt;&lt;/p&gt;

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

yarn add adminjs @adminjs/nestjs @adminjs/express express-session express-formidable



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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;app.module.ts&lt;/strong&gt;&lt;/p&gt;

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

import { Module } from '@nestjs/common'
import { AdminModule } from '@adminjs/nestjs'

import { AppController } from './app.controller'
import { AppService } from './app.service'

const DEFAULT_ADMIN = {
  email: 'admin@example.com',
  password: 'password',
}

const authenticate = async (email: string, password: string) =&amp;gt; {
  if (email === DEFAULT_ADMIN.email &amp;amp;&amp;amp; password === DEFAULT_ADMIN.password) {
    return Promise.resolve(DEFAULT_ADMIN)
  }
  return null
}

@Module({
  imports: [
    AdminModule.createAdminAsync({
      useFactory: () =&amp;gt; ({
        adminJsOptions: {
          rootPath: '/admin',
          resources: [],
        },
        auth: {
          authenticate,
          cookieName: 'adminjs',
          cookiePassword: 'secret'
        },
        sessionOptions: {
          resave: true,
          saveUninitialized: true,
          secret: 'secret'
        },
      }),
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}



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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Don't want authentication?
&lt;/h3&gt;

&lt;p&gt;You might want your admin panel to not require authentication depending on the project you are working on. By removing the &lt;code&gt;auth&lt;/code&gt; and &lt;code&gt;sessionOptions&lt;/code&gt; from the object returned by the &lt;a href="https://docs.nestjs.com/fundamentals/custom-providers#factory-providers-usefactory" rel="noopener noreferrer"&gt;factory provider&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

...
AdminModule.createAdminAsync({
  useFactory: () =&amp;gt; ({
    adminJsOptions: {
      rootPath: '/admin',
      resources: [],
    },
  }),
}),
...



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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Start your server&lt;/strong&gt;&lt;/p&gt;

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

nest start --watch
# OR
nest start



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

&lt;/div&gt;

&lt;p&gt;Visit &lt;code&gt;127.0.0.1:&amp;lt;your port&amp;gt;/admin&lt;/code&gt; . If you have authentication enabled it will automatically redirect you to the login page.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frqx0ze6l4gvj5szyoke2.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frqx0ze6l4gvj5szyoke2.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enter the details from the &lt;code&gt;DEFAULT_ADMIN&lt;/code&gt; object in the &lt;code&gt;app.module.ts&lt;/code&gt; program.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdsn3rlphuq0lfng8y1go.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdsn3rlphuq0lfng8y1go.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding Database models
&lt;/h3&gt;

&lt;p&gt;Upon logging in, if you're unable to locate your models on the dashboard, resources can be of great help. AdminJs leverages the resources added to its options to effectively showcase, evaluate, and utilize them.&lt;/p&gt;

&lt;p&gt;Assuming you have this Prisma schema,&lt;/p&gt;

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

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url = env("DATABASE_URL")
}

model User {
  pk Int @id @default(autoincrement())
  id String @unique @default(uuid()) @db.Uuid
  email String @unique
  password String
  active Boolean @default(true)
  staff Boolean @default(false)
  admin Boolean @default(false)
  profile Profile?

  @@unique([pk, id])
  @@map("users")
}

model Profile {
  pk Int @id @default(autoincrement())
  id String @unique @default(uuid()) @db.Uuid
  firstName String? @map("first_name")
  lastName String? @map("last_name")
  userPk Int @unique @map("user_pk")
  userId String @unique @map("user_id") @db.Uuid
  user User @relation(fields: [userPk, userId], references: [pk, id], onDelete: Cascade, onUpdate: Cascade)

  @@unique([pk, id])
  @@unique([userPk, userId])
  @@map("profiles")
}



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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;app.module.ts&lt;/strong&gt;&lt;/p&gt;

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

import { Module } from '@nestjs/common'
import { AdminModule } from '@adminjs/nestjs'
import { Database, Resource } from '@adminjs/prisma';
import AdminJS from 'adminjs'
import { DMMFClass } from '@prisma/client/runtime';
import { PrismaService } from '@database/prisma.service';
import { DatabaseModule } from '@database/database.module';

import { AppController } from './app.controller'
import { AppService } from './app.service'

const DEFAULT_ADMIN = {
  email: 'admin@example.com',
  password: 'password',
}

const authenticate = async (email: string, password: string) =&amp;gt; {
  if (email === DEFAULT_ADMIN.email &amp;amp;&amp;amp; password === DEFAULT_ADMIN.password) {
    return Promise.resolve(DEFAULT_ADMIN)
  }
  return null
}

AdminJS.registerAdapter({ Database, Resource });

@Module({
  imports: [
    AdminModule.createAdminAsync({
      imports: [DatabaseModule],
      useFactory: (prisma: PrismaService) =&amp;gt; {
        const dmmf = (prisma as any)._baseDmmf as DMMFClass;

        return {
          adminJsOptions: {
            rootPath: '/admin',
            resources: [
              {
                resource: { model: dmmf.modelMap['User'], client: prisma },
                options: {},
              },
              {
                resource: { model: dmmf.modelMap['Profile'], client: prisma },
                options: {},
              },
            ],
          },
          auth: {
            authenticate,
            cookieName: 'adminjs',
            cookiePassword: 'secret'
          },
          sessionOptions: {
            resave: true,
            saveUninitialized: true,
            secret: 'secret'
          },
        }
      },
      inject: [PrismaService],
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}



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

&lt;/div&gt;

&lt;p&gt;Explore the basic Resource object format and effortlessly add multiple resources to your project.&lt;/p&gt;

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

{
  resource: { model: dmmf.modelMap[{Model name here}], client: prisma },
  options: {},
}



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

&lt;/div&gt;

&lt;p&gt;Make sure you replace &lt;code&gt;{Model name here}&lt;/code&gt; with the name of the model you want to use. For example, if you have a model &lt;code&gt;Post&lt;/code&gt;, you would replace &lt;code&gt;{Model name here}&lt;/code&gt; with &lt;code&gt;Post&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  How does this work?
&lt;/h4&gt;

&lt;p&gt;The Database Model Mapper (DMMF) object comprises a comprehensive depiction of your database schema. Its functionality extends to facilitating the extraction of your model from Prisma. The DMMF achieves this by mapping model names to their respective model objects. For example, to retrieve the User model from the map, one can utilize the syntax &lt;code&gt;dmmf.modelMap['User']&lt;/code&gt;. Once the model object is obtained, it can be assigned to the resource's model property.&lt;/p&gt;

&lt;p&gt;The Prisma client serves as the client property, facilitating connectivity to the database for conducting CRUD operations.&lt;/p&gt;

&lt;p&gt;You can add as many resources as you need. For example, if you have a &lt;code&gt;Post&lt;/code&gt; model in your Prisma schema that you want to be displayed in the Admin Dashboard. You just need to add it to the resources array;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;app.module.ts&lt;/strong&gt;&lt;/p&gt;

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

...
{
  resource: { model: dmmf.modelMap['Post'], client: prisma },
  options: {},
},
...



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

&lt;/div&gt;

&lt;p&gt;Now restart your server if it's not on fast reload.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fom62qrr343hndjytbl38.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fom62qrr343hndjytbl38.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Simplify adding resources
&lt;/h3&gt;

&lt;p&gt;When managing a substantial number of database models, it is common to encounter the need for duplicating codes while incorporating new resources for each model.&lt;/p&gt;

&lt;p&gt;Did you know that the &lt;a href="https://en.wikipedia.org/wiki/Builder_pattern#:~:text=The%20builder%20pattern%20is%20a,Gang%20of%20Four%20design%20patterns." rel="noopener noreferrer"&gt;Builder pattern&lt;/a&gt; can help you add multiple resources to your code without repeating the same code? This makes your code more efficient and easier to maintain. So why not give it a try?&lt;/p&gt;

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

import { Module } from '@nestjs/common'
import { AdminModule } from '@adminjs/nestjs'
import { Database, Resource } from '@adminjs/prisma';
import AdminJS from 'adminjs'
import { DMMFClass } from '@prisma/client/runtime';
import { PrismaService } from '@database/prisma.service';
import { DatabaseModule } from '@database/database.module';
import { ResourceWithOptions, ResourceOptions } from 'adminjs/types/src';

import { AppController } from './app.controller'
import { AppService } from './app.service'

const DEFAULT_ADMIN = {
  email: 'admin@example.com',
  password: 'password',
}

const authenticate = async (email: string, password: string) =&amp;gt; {
  if (email === DEFAULT_ADMIN.email &amp;amp;&amp;amp; password === DEFAULT_ADMIN.password) {
    return Promise.resolve(DEFAULT_ADMIN)
  }
  return null
}

AdminJS.registerAdapter({ Database, Resource });

class CResource {
  model: any;
  options: ResourceOptions;

  constructor(model: any, options?: ResourceOptions) {
    this.model = model;
    this.options = options || {};
  }
}

class CResourceBuilder {
  private readonly resources: Array&amp;lt;CResource&amp;gt; = [];
  dmmf: DMMFClass;

  constructor(private readonly prisma: PrismaService) {
    this.dmmf = ((prisma as any)._baseDmmf as DMMFClass)
  }

  /**
   * Adds a resource to the builder
   * 
   * @param resource string
   * @param options ResourceOptions
   * @returns this
   */
  public addResource(resource: string, options?: ResourceOptions): this {
    const obj = new CResource(this.dmmf.modelMap[resource], options);
    this.resources.push(obj);
    return this;
  }

  /**
   * Compiles the resources into an array of objects
   * that can be passed to the AdminJS module
   * 
   * @returns Array&amp;lt;ResourceWithOptions | any&amp;gt;
   */
  public build(): Array&amp;lt;ResourceWithOptions | any&amp;gt; {
    return this.resources.map((resource) =&amp;gt; {
      return {
        resource: {
          model: resource.model,
          client: this.prisma,
        },
        options: resource.options,
      }
    })
  }
}

@Module({
  imports: [
    AdminModule.createAdminAsync({
      imports: [DatabaseModule],
      useFactory: (prisma: PrismaService) =&amp;gt; {
        const dmmf = (prisma as any)._baseDmmf as DMMFClass;

        return {
          adminJsOptions: {
            rootPath: '/admin',

            // updated here
            resources: new CResourceBuilder(prisma)
              .addResource('User')
              .addResource('Profile')
              .addResource('Post')
              .build(),
          },
          auth: {
            authenticate,
            cookieName: 'adminjs',
            cookiePassword: 'secret'
          },
          sessionOptions: {
            resave: true,
            saveUninitialized: true,
            secret: 'secret'
          },
        }
      },
      inject: [PrismaService],
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule { }



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

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;You can always export the classes, functions and objects from an external file.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Mastering AdminJs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.adminjs.co/basics/resource" rel="noopener noreferrer"&gt;More options for resources&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.adminjs.co/ui-customization/writing-your-own-components" rel="noopener noreferrer"&gt;Customizing your Admin Dashboard&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;In conclusion, AdminJS is a powerful tool for creating admin dashboards for NestJS and Prisma applications. With its adapters for various ORM and ODM models, it simplifies the process of performing CRUD operations on models. It also provides customization options for the dashboard, making it easy to tailor it to specific project needs. By following the steps outlined in the article, developers can quickly set up AdminJS and start using it to manage their application's data.&lt;/p&gt;

&lt;p&gt;Follow me on Twitter &lt;a href="https://twitter.com/netrobeweb" rel="noopener noreferrer"&gt;@netrobeweb&lt;/a&gt; and &lt;a href="https://hashnode.com/@netrobe" rel="noopener noreferrer"&gt;Hashnode&lt;/a&gt; where I post amazing projects and articles.&lt;/p&gt;

&lt;p&gt;Thanks for reading, 😉.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Mastering File Upload and Validation in NestJS with Multer</title>
      <dc:creator>Israel Ayanwola</dc:creator>
      <pubDate>Sat, 18 Mar 2023 12:04:39 +0000</pubDate>
      <link>https://dev.to/devvspaces/mastering-file-upload-and-validation-in-nestjs-with-multer-cm5</link>
      <guid>https://dev.to/devvspaces/mastering-file-upload-and-validation-in-nestjs-with-multer-cm5</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gCrDTy4Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1679054576314/bb731ed7-bf84-4398-a48e-95e226440017.jpeg%3Fw%3D1600%26h%3D840%26fit%3Dcrop%26crop%3Dentropy%26auto%3Dcompress%2Cformat%26format%3Dwebp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gCrDTy4Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.hashnode.com/res/hashnode/image/upload/v1679054576314/bb731ed7-bf84-4398-a48e-95e226440017.jpeg%3Fw%3D1600%26h%3D840%26fit%3Dcrop%26crop%3Dentropy%26auto%3Dcompress%2Cformat%26format%3Dwebp" alt="" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This guide will show you how to efficiently incorporate file upload and validation into your NestJS project. The tutorial will walk you through the steps of receiving and verifying files using the Multer middleware package with the Express Adapter. By following this guide, you can create a personalized file upload and validation process that works best for your NestJS application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accepting files
&lt;/h2&gt;

&lt;p&gt;File processing in NestJs is handled with Multer. It has a built-in Multer middleware package for Express Adapter. The only required package to install is &lt;code&gt;@types/multer&lt;/code&gt;, which is for better type safety.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i -D @types/multer @nestjs/platform-express

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

&lt;/div&gt;



&lt;p&gt;Start by creating an endpoint for single file uploads.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Post, UploadedFile, UseInterceptors, Controller } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';

@Controller('files')
export class FileController {
    @Post('upload')
    @UseInterceptors(FileInterceptor('file'))
    uploadFile(@UploadedFile() file: Express.Multer.File) {
        console.log(file);
    }
}

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Make sure to use &lt;code&gt;@nestjs/common: "^9.0.0"&lt;/code&gt;, it's required to use &lt;code&gt;UploadedFile&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you use swagger, you can specify &lt;code&gt;ApiConsumes&lt;/code&gt; decorator to &lt;code&gt;multipart/form-data&lt;/code&gt;. This tells swagger that this route accepts form data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Post, UploadedFile, UseInterceptors, Controller } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { ApiConsumes, ApiTags } from '@nestjs/swagger';

@ApiTags('Uploding Files')
@Controller('files')
@ApiConsumes('multipart/form-data')
export class FileController {
    @Post('upload')
    @UseInterceptors(FileInterceptor('file'))
    uploadFile(@UploadedFile() file: Express.Multer.File) {
        console.log(file);
    }
}

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

&lt;/div&gt;



&lt;p&gt;When it comes to filing storage, Multer has a default memory setting. While this is a viable choice, it may not suit your needs if you plan to bypass disk storage and instead upload files directly to external storage solutions like Cloudinary or AWS S3.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to Save Data to Disk Storage
&lt;/h3&gt;

&lt;p&gt;To upload your files to disk storage, you can provide the file destination in the &lt;code&gt;FileInterceptor&lt;/code&gt;. The interceptor accepts &lt;a href="https://github.com/expressjs/multer#multeropts"&gt;Multer Options&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const UPLOAD_DIR = './upload/files/';

@ApiTags('Uploding Files')
@Controller('files')
@ApiConsumes('multipart/form-data')
export class FileController {
    @Post('upload')
    @UseInterceptors(FileInterceptor('file', { dest: UPLOAD_DIR }))
    uploadFile(@UploadedFile() file: Express.Multer.File) {
        console.log(file);
    }
}

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

&lt;/div&gt;



&lt;p&gt;The upload directory path is relative to your root directory.&lt;/p&gt;

&lt;p&gt;Hey there! When dealing with a lot of users, we want to make sure we avoid any issues that might come up with file names. To prevent this from happening, we recommend assigning a separate folder for each upload. That way, everything stays organized and everyone can easily find what they need.&lt;/p&gt;

&lt;p&gt;There is a helpful tip to share with you. Are you aware that every user can have their unique folder in the upload directory? What's more, you can enhance this feature by configuring a storage engine for Multer, which allows you to create a dynamic upload path. Why not give it a try?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Post, UploadedFile, UseInterceptors, Controller } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { ApiConsumes, ApiTags } from '@nestjs/swagger';
import { Request } from 'express';
import { diskStorage } from 'multer';
import * as path from 'path';

const UPLOAD_DIR = './upload/files/';

// User interface of the authenticated user
interface User {
  id: string;
}

/**
 * You can use this function to generate a unique filename for each file
 * User id is used to generate a unique filename
 * The User object can be attached to the request object in the auth middleware
 */
const defaultConfig = diskStorage({
  destination: UPLOAD_DIR,
  filename: (req: Request &amp;amp; { user: User }, file, cb) =&amp;gt; {
    const uid = req.user.id;
    cb(null, `${uid}${path.extname(file.originalname)}`)
  }
})

@ApiTags('Uploding Files')
@Controller('files')
@ApiConsumes('multipart/form-data')
export class FileController {

  @Post('upload')
  @UseInterceptors(FileInterceptor('file', { storage: defaultConfig }))
  uploadFile(@UploadedFile() file: Express.Multer.File) {
    console.log(file);
  }

}

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

&lt;/div&gt;



&lt;p&gt;In this example, the user object could be attached to the request manually in the auth &lt;a href="https://docs.nestjs.com/middleware"&gt;middleware&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is a perfect example of how to accept files and save them in a super cool and unique path!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The file would be saved to disk before &lt;code&gt;console.log(file)&lt;/code&gt; runs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The next section provides a way of adding file processing like validation of files uploaded.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validate Your Files with ParseFilePipe and ParseFilePipeBuilder
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Using ParseFilePipe with Validator classes
&lt;/h3&gt;

&lt;p&gt;NestJs Pipes offer an efficient way to validate files. To perform file validation, simply create a validator class such as MaxFileSizeValidator or FileNameValidator, and pass it to the ParseFilePipe.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { ..., ParseFilePipe } from '@nestjs/common';

...

@Post('upload')
@UseInterceptors(FileInterceptor('file', { storage: defaultConfig }))
uploadFile(
  @UploadedFile(
    new ParseFilePipe({
      validators: [
        // ... Set of file validator instances here
      ]
    })
  )
  file: Express.Multer.File
) {
  console.log(file);
}

...

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

&lt;/div&gt;



&lt;p&gt;Create a &lt;code&gt;FileValidator&lt;/code&gt; class to use with &lt;code&gt;ParseFilePipe&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { FileValidator } from '@nestjs/common';

class MaxFileSize extends FileValidator&amp;lt;{ maxSize: number }&amp;gt;{
  constructor(options: { maxSize: number }) {
    super(options)
  }

  isValid(file: Express.Multer.File): boolean | Promise&amp;lt;boolean&amp;gt; {
    const in_mb = file.size / 1000000
    return in_mb &amp;lt;= this.validationOptions.maxSize
  }
  buildErrorMessage(): string {
    return `File uploaded is too big. Max size is (${this.validationOptions.maxSize} MB)`
  }
}

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

&lt;/div&gt;



&lt;p&gt;The interface&lt;code&gt;FileValidator&lt;/code&gt; has two methods needed to create its class. The method &lt;code&gt;isValid&lt;/code&gt; and &lt;code&gt;buildErrorMessage&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The method, &lt;code&gt;isValid&lt;/code&gt; will contain your logic that defines if the file is valid or not depending on the options passed in the constructor.&lt;/p&gt;

&lt;p&gt;From the constructor definition, &lt;code&gt;maxSize&lt;/code&gt; can be passed as an option and is used in the &lt;code&gt;isValid&lt;/code&gt; method to know what is considered the maximum file size.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**
 * Builds an error message in case the validation fails.
 * @param file the file from the request object
 */
abstract buildErrorMessage(file: any): string;

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

&lt;/div&gt;



&lt;p&gt;Above is the interface of the &lt;code&gt;buildErrorMessage&lt;/code&gt; function. It's used to build unique or general error messages for uploaded files.&lt;/p&gt;

&lt;p&gt;Pass an instance of the &lt;code&gt;MaxFileSize&lt;/code&gt; class in the &lt;code&gt;ParseFilePipe&lt;/code&gt;. The &lt;code&gt;maxSize&lt;/code&gt; can be passed to the constructor during instantiation.&lt;br&gt;
&lt;/p&gt;

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

const MAX_UPLOAD_SIZE = 10; // in MB
...

@Post('upload')
@UseInterceptors(FileInterceptor('file', { storage: defaultConfig }))
uploadFile(
  @UploadedFile(
    new ParseFilePipe({
      validators: [
        // ... Set of file validator instances here
        new MaxFileSize({
          maxSize: MAX_UPLOAD_SIZE
        }),
      ]
    })
  )
  file: Express.Multer.File
) {
  console.log(file);
}

...

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

&lt;/div&gt;



&lt;p&gt;The code should look like this now&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Post, UploadedFile, UseInterceptors, Controller, ParseFilePipe } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { ApiConsumes, ApiTags } from '@nestjs/swagger';
import { Request } from 'express';
import { diskStorage } from 'multer';
import * as path from 'path';
import { FileValidator } from '@nestjs/common';

const UPLOAD_DIR = './upload/files/';
const MAX_UPLOAD_SIZE = 10; // in MB

// User interface of the authenticated user
interface User {
  id: string;
}

class MaxFileSize extends FileValidator&amp;lt;{ maxSize: number }&amp;gt;{
  constructor(options: { maxSize: number }) {
    super(options)
  }

  isValid(file: Express.Multer.File): boolean | Promise&amp;lt;boolean&amp;gt; {
    const in_mb = file.size / 1000000
    return in_mb &amp;lt;= this.validationOptions.maxSize
  }
  buildErrorMessage(): string {
    return `File uploaded is too big. Max size is (${this.validationOptions.maxSize} MB)`
  }
}

/**
 * You can use this function to generate a unique filename for each file
 * User id is used to generate a unique filename
 * The User object can be attached to the request object in the auth middleware
 */
const defaultConfig = diskStorage({
  destination: UPLOAD_DIR,
  filename: (req: Request &amp;amp; { user: User }, file, cb) =&amp;gt; {
    const uid = req.user.id;
    cb(null, `${uid}${path.extname(file.originalname)}`)
  }
})

@ApiTags('Uploding Files')
@Controller('files')
@ApiConsumes('multipart/form-data')
export class FileController {

  @Post('upload')
  @UseInterceptors(FileInterceptor('file', { storage: defaultConfig }))
  uploadFile(
    @UploadedFile(
      new ParseFilePipe({
        validators: [
          // ... Set of file validator instances here
          new MaxFileSize({
            maxSize: MAX_UPLOAD_SIZE
          }),
        ]
      })
    )
    file: Express.Multer.File
  ) {
    console.log(file);
  }

}

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;If your validators are getting much, you can create them in a separate file and import them here as a named constant like &lt;code&gt;myValidators.&lt;/code&gt; - &lt;a href="https://docs.nestjs.com/techniques/file-upload#:~:text=.File%2C-,HINT,-If%20the%20number"&gt;NestJs Docs&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Using ParseFilePipeBuilder
&lt;/h3&gt;

&lt;p&gt;Wow, this is amazing! It's so much better because it comes with built-in validators for file size and type! Plus, there's a way to add even more validators using the addValidator method for complex file validation! How cool is that?!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { ..., ParseFilePipeBuilder, HttpStatus } from '@nestjs/common';
...

@Post('upload')
@UseInterceptors(FileInterceptor('file', { storage: defaultConfig }))
uploadFile(
  @UploadedFile(
    new ParseFilePipeBuilder()
      .addFileTypeValidator({
        fileType: /(jpg|jpeg|png|gif)$/,
      })
      .addMaxSizeValidator({
        maxSize: 1000
      })
      .addValidator(
        new MaxFileSize({
          maxSize: MAX_UPLOAD_SIZE
        }),
      ) 
      .build({
        errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY
      })
  )
  file: Express.Multer.File
) {
  console.log(file);
}

...

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

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;errorHttpStatusCode&lt;/code&gt; is the HTTP status code you want to be returned when validation fails.&lt;/p&gt;

&lt;p&gt;Simplify the process of file validation with the help of ParseFilePipeBuilder. For straightforward validations like file types and sizes, this tool is highly recommended. However, for more intricate validations, it's best to create file validator classes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optional File Uploads
&lt;/h2&gt;

&lt;p&gt;File upload parameters can be made optional or not required by passing an extra option in the &lt;code&gt;ParseFilePipeBuilder&lt;/code&gt; build method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new ParseFilePipeBuilder()
.addFileTypeValidator({
  fileType: "png",
})
.build({
  fileIsRequired: false // It's required by default
})

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Accepting multiple files
&lt;/h2&gt;

&lt;p&gt;Simply change the file interceptor and upload the file decorator.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { UploadedFiles } from '@nestjs/common';
import { FilesInterceptor } from '@nestjs/platform-express';

const MAX_FILES_COUNT = 10;

...

@Post('upload/multiple')
@UseInterceptors(
  FilesInterceptor('files', MAX_FILES_COUNT, { storage: defaultConfig })
)
uploadFiles(
  @UploadedFiles(
    new ParseFilePipeBuilder()
      .addFileTypeValidator({
        fileType: /(jpg|jpeg|png|gif)$/,
      })
      .addMaxSizeValidator({
        maxSize: 1000
      })
      .addValidator(
        new MaxFileSize({
          maxSize: MAX_UPLOAD_SIZE
        }),
      ) 
      .build({
        errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY
      })
  )
  files: Express.Multer.File[]
) {
  console.log(files);
}

...

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

&lt;/div&gt;



&lt;p&gt;It's now &lt;code&gt;UploadedFiles&lt;/code&gt; and &lt;code&gt;FilesInterceptor&lt;/code&gt;. &lt;code&gt;FilesInterceptor&lt;/code&gt; accepts max files number that can be uploaded through the endpoint.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Make sure to accept files as an argument, not just file.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Below, you can find the complete code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Post, UploadedFile, UseInterceptors, Controller, ParseFilePipe, ParseFilePipeBuilder, HttpStatus, UploadedFiles } from '@nestjs/common';
import { FileInterceptor, FilesInterceptor } from '@nestjs/platform-express';
import { ApiConsumes, ApiTags } from '@nestjs/swagger';
import { Request } from 'express';
import { diskStorage } from 'multer';
import * as path from 'path';
import { FileValidator } from '@nestjs/common';

const UPLOAD_DIR = './upload/files/';
const MAX_UPLOAD_SIZE = 10; // in MB
const MAX_FILES_COUNT = 10; // Maximum number of files that can be uploaded at once

// User interface of the authenticated user
interface User {
  id: string;
}

class MaxFileSize extends FileValidator&amp;lt;{ maxSize: number }&amp;gt;{
  constructor(options: { maxSize: number }) {
    super(options)
  }

  isValid(file: Express.Multer.File): boolean | Promise&amp;lt;boolean&amp;gt; {
    const in_mb = file.size / 1000000
    return in_mb &amp;lt;= this.validationOptions.maxSize
  }
  buildErrorMessage(): string {
    return `File uploaded is too big. Max size is (${this.validationOptions.maxSize} MB)`
  }
}

/**
 * You can use this function to generate a unique filename for each file
 * User id is used to generate a unique filename
 * The User object can be attached to the request object in the auth middleware
 */
const defaultConfig = diskStorage({
  destination: UPLOAD_DIR,
  filename: (req: Request &amp;amp; { user: User }, file, cb) =&amp;gt; {
    const uid = req.user.id;
    cb(null, `${uid}${path.extname(file.originalname)}`)
  }
})

@ApiTags('Uploding Files')
@Controller('files')
@ApiConsumes('multipart/form-data')
export class FileController {

  @Post('upload')
  @UseInterceptors(FileInterceptor('file', { storage: defaultConfig }))
  uploadFile(
    @UploadedFile(
      new ParseFilePipeBuilder()
        .addFileTypeValidator({
          fileType: /(jpg|jpeg|png|gif)$/,
        })
        .addMaxSizeValidator({
          maxSize: 1000
        })
        .build({
          errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY
        })
    )
    file: Express.Multer.File
  ) {
    console.log(file);
  }

  @Post('upload/multiple')
  @UseInterceptors(
    FilesInterceptor('files', MAX_FILES_COUNT, { storage: defaultConfig })
  )
  uploadFiles(
    @UploadedFiles(
      new ParseFilePipeBuilder()
        .addFileTypeValidator({
          fileType: /(jpg|jpeg|png|gif)$/,
        })
        .addValidator(
          new MaxFileSize({
            maxSize: MAX_UPLOAD_SIZE
          }),
        )
        .build({
          errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY
        })
    )
    files: Express.Multer.File[]
  ) {
    console.log(files);
  }
}

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

&lt;/div&gt;



&lt;p&gt;For a comprehensive configuration of Multer file upload, refer to the NestJs File Upload &lt;a href="https://docs.nestjs.com/techniques/file-upload"&gt;Documentation&lt;/a&gt;. Read on to learn more.&lt;/p&gt;

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

&lt;p&gt;In conclusion, this article provides a comprehensive guide on how to implement file upload and validation in NestJS using the Multer middleware package for the Express Adapter. It covers accepting and validating files, saving files to disk storage, file validation with ParseFilePipe and ParseFilePipeBuilder, and accepting multiple files. By following the steps outlined in this article, developers can easily design their custom file upload and validation flow in NestJS.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Building an ECDSA wallet with JavaScript</title>
      <dc:creator>Israel Ayanwola</dc:creator>
      <pubDate>Sun, 29 Jan 2023 19:05:24 +0000</pubDate>
      <link>https://dev.to/devvspaces/building-an-ecdsa-wallet-with-javascript-g21</link>
      <guid>https://dev.to/devvspaces/building-an-ecdsa-wallet-with-javascript-g21</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk450mt2qpmwl2ximam1p.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk450mt2qpmwl2ximam1p.jpeg" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Blockchain&lt;/strong&gt; is an amazing technology to dive into. It has been around for some time now and powering very popular technologies like Ethereum.&lt;/p&gt;

&lt;p&gt;To make this article as simple as possible, the definitions and terminologies would be summarized to just key points needed for the project you will build in this article. But links to amazing educational articles will be provided for each.&lt;/p&gt;

&lt;p&gt;By the end of this article, you would understand Public Key Cryptography, Elliptic curve digital signatures and how they can be used to make the world a better place. I will take you one step at a time on how to build a blockchain node.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  What is Cryptography
&lt;/h2&gt;

&lt;p&gt;Cryptography is a way of securing a piece of information. It's the study of cryptographic hash functions.&lt;/p&gt;

&lt;p&gt;Cryptographic hash functions are mathematical functions that take an input of any size and convert it to a fixed-sized output. It's a one-way ticket, you can't get the input from the output.&lt;/p&gt;

&lt;p&gt;Cryptography is at the heart of blockchain and Web3. Here is a &lt;a href="[https://emn178.github.io/online-tools/sha256](https://emn178.github.io/online-tools/sha256)"&gt;link&lt;/a&gt; to an online tool containing lots of hash functions you can play with.&lt;/p&gt;

&lt;h3&gt;
  
  
  Public Key Cryptography
&lt;/h3&gt;

&lt;p&gt;It's the use of two keys, a public key (a key that is known to everyone), and a private key (a key that is kept secured). The private key can encrypt a message that can only be decrypted by the public key, verifying that the message was indeed sent by someone with the right private key and vice versa.&lt;/p&gt;

&lt;p&gt;Public key cryptography is also called &lt;strong&gt;asymmetric cryptography&lt;/strong&gt; because it uses a pair of related keys.&lt;/p&gt;

&lt;p&gt;RSA and ECDSA are two popular algorithms used for public cryptography. RSA is based on the idea that you can quickly find the product of two prime numbers, but extremely hard to factor out the prime numbers once you have the products. Read more about RSA on &lt;a href="[https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Example](https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Example)"&gt;Wikipedia&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;ECDSA (Elliptic curve digital signature algorithm) uses elliptic curves. Read more about it on &lt;a href="[https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm)"&gt;Wikipedia&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why use ECDSA
&lt;/h3&gt;

&lt;p&gt;ECDSA provides the same level of security as RSA but with small key sizes. RSA keys can be very large making it take a long to transfer over a network.&lt;/p&gt;

&lt;p&gt;ECDSA is the algorithm used by Bitcoin, which is the &lt;a href="[https://en.bitcoin.it/wiki/Secp256k1](https://en.bitcoin.it/wiki/Secp256k1)"&gt;secp256k1 curve&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building an ECDSA node
&lt;/h2&gt;

&lt;p&gt;This is an example of a blockchain node that uses the ECDSA signing algorithm. The project is a simple react frontend application that allows users to send money to each other. There will be a single server node, which makes this centralized but there will be an article later on how to deploy a program on Ethereum.&lt;/p&gt;

&lt;h2&gt;
  
  
  Goal
&lt;/h2&gt;

&lt;p&gt;The server would manage the balances of the users. The goal is to enable the server to verify who is sending the money to make sure that a person can only send money from their wallet.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Project prerequisites
&lt;/h3&gt;

&lt;p&gt;You will need to have a basic knowledge of React as it is used for the front end. With a basic understanding of Express.&lt;/p&gt;

&lt;h3&gt;
  
  
  Application Architecture
&lt;/h3&gt;

&lt;p&gt;There is the front end, which has the UI part of the project that allows users to enter their wallet addresses and attempt to send money to others. The Idea here is that, when a user tries to send money, we would generate a transaction for them to sign with their private key, then input the signed transaction which would be sent to the server with their public key (wallet address), address where money should be sent, and the amount of money to be sent.&lt;/p&gt;

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

&lt;p&gt;The server would take this signed transaction and the public key, then verify if the transaction was indeed signed using the right private key of the public key. If it's correct, it updates the users (sender and recipient) balances, else it returns an error message.&lt;/p&gt;

&lt;h3&gt;
  
  
  Client-Side React App
&lt;/h3&gt;

&lt;p&gt;We would use Vite for our front-end tooling.&lt;/p&gt;

&lt;p&gt;Create a new directory called &lt;code&gt;wallet-node&lt;/code&gt; and move into the directory.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;npm create vite@latest&lt;/code&gt;, enter &lt;code&gt;client&lt;/code&gt; as your project name, &lt;code&gt;react&lt;/code&gt; as the framework and &lt;code&gt;JavaScript&lt;/code&gt; as the variant.&lt;/p&gt;

&lt;p&gt;Move into the client directory just created by Vite. Run &lt;code&gt;npm i&lt;/code&gt; to install the packages from the template.&lt;/p&gt;

&lt;p&gt;Install Sass as a dev dependency using this command &lt;code&gt;npm i -D sass&lt;/code&gt;. This will install the sass package as we will be using sass for our CSS styling.&lt;/p&gt;

&lt;p&gt;The last installments are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Axios - &lt;code&gt;npm i axios&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ethereum Cryptography - &lt;code&gt;npm i ethereum-cryptography&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, edit the value of the title tag in the index.html file to &lt;code&gt;ECDSA Wallet&lt;/code&gt; or anything you want.&lt;/p&gt;

&lt;p&gt;Move into the &lt;code&gt;src&lt;/code&gt; directory, delete the &lt;code&gt;assets&lt;/code&gt; directory, &lt;code&gt;index.css&lt;/code&gt; and &lt;code&gt;App.css&lt;/code&gt; files.&lt;/p&gt;

&lt;p&gt;Edit the &lt;code&gt;main.jsx&lt;/code&gt; file, remove the line for &lt;code&gt;import './index.css'&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Edit &lt;code&gt;App.jsx&lt;/code&gt; by removing everything in it and pasting in the following code;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Wallet from "./Wallet";
import Transfer from "./Transfer";
import "./App.scss";
import { useState } from "react";

function App() {
  const [balance, setBalance] = useState(0);
  const [address, setAddress] = useState("");

  return (
    &amp;lt;div className="app"&amp;gt;
      &amp;lt;Wallet
        balance={balance}
        setBalance={setBalance}
        address={address}
        setAddress={setAddress}
      /&amp;gt;
      &amp;lt;Transfer setBalance={setBalance} address={address} /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default App;

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

&lt;/div&gt;



&lt;p&gt;We will create a Wallet and Transfer component, and our &lt;code&gt;App.scss&lt;/code&gt; file for the sass styles.&lt;/p&gt;

&lt;p&gt;From the above code, two stateful values were created, &lt;code&gt;balance&lt;/code&gt; and &lt;code&gt;address&lt;/code&gt;. The &lt;code&gt;balance&lt;/code&gt; will be used to keep track of and manage an address balance, while the &lt;code&gt;address&lt;/code&gt; will be used to share a user address among the &lt;code&gt;Wallet&lt;/code&gt; and &lt;code&gt;Transfer&lt;/code&gt; components.&lt;/p&gt;

&lt;p&gt;The transfer component accepts a prop &lt;code&gt;setBalance&lt;/code&gt; which would be used to set the state of the user's balance after the money has been transferred successfully.&lt;/p&gt;

&lt;p&gt;Create an &lt;code&gt;App.scss&lt;/code&gt; file in the &lt;code&gt;src&lt;/code&gt; directory, then paste the following code;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;body {
  font-family: "Muli", sans-serif;
  font-weight: 300;
  background-color: #e2e8f0;
  padding: 40px;
}

label {
  display: flex;
  flex-direction: column;
  letter-spacing: 0.05rem;
  font-size: .8em;
  font-weight: 400;
  color: #222;
}

.app {
  display: flex;
  max-width: 1400px;
  flex-wrap: wrap;
  gap: 12px;
  margin: 0 auto;
}

.container {
  flex-grow: 1;
  margin: 0 20px;
  background-color: #fff;
  border: 1px solid #cbd5e0;
  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
  border-radius: 0.375rem;
  padding: 40px;

  label {
    margin: 10px 0;
  }

  .button {
    margin-top: 10px;
  }
}

input {
  padding: 10px 0;
  border-radius: 0.125rem;
  border: 1px solid rgb(226, 232, 240);
  background-color: #fdfdfe;
  padding-inline-start: 0.75rem;
  font-size: 0.875rem;
}

.button {
  background-color: #319795;
  border-radius: 0.125rem;
  padding: 10px 20px;
  color: white;
  display: inline-flex;
  text-transform: uppercase;
  letter-spacing: 1px;
  font-weight: 400;
  font-size: .9em;
  &amp;amp;:hover {
    cursor: pointer;
  }
}

.wallet {
  display: flex;
  flex-direction: column;

  .balance {
    text-transform: uppercase;
    letter-spacing: 1px;
    font-weight: 400;
    font-size: .9em;
    display: inline-flex;
    margin-top: 10px;
    padding: 0.75rem;
    background-color: #f4f6f8;
  }
}

.transfer {
  display: flex;
  flex-direction: column;
}

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

&lt;/div&gt;



&lt;p&gt;Create a &lt;code&gt;server.js&lt;/code&gt; file and paste the code below;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import axios from "axios";

const server = axios.create({
  baseURL: "http://localhost:3042",
});

export default server;

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

&lt;/div&gt;



&lt;p&gt;This creates an Axios instance that uses &lt;code&gt;http://localhost:3042&lt;/code&gt; as the base URL, this is the URL our server will be listening on. The Axios instance is exported to be used by other services.&lt;/p&gt;

&lt;p&gt;Now we would need to create a very important function. Here we would use cryptographic functions 😁. Specifically, the &lt;code&gt;keccak256&lt;/code&gt; hash function, which would be used to hash our transaction messages.&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;services.js&lt;/code&gt; file, and paste the code below;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { keccak256 } from "ethereum-cryptography/keccak"
import { utf8ToBytes, toHex } from "ethereum-cryptography/utils"

export async function hashMessage(message){
    return toHex(keccak256(utf8ToBytes(message)))
}

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

&lt;/div&gt;



&lt;p&gt;Now let's talk about what is happening here.&lt;/p&gt;

&lt;p&gt;We have created a &lt;code&gt;hashMessage&lt;/code&gt; function, which accepts a message (string) and returns a hash (string).&lt;/p&gt;

&lt;p&gt;Keccak256, the function is imported from the Ethereum cryptography package installed earlier, it accepts bytes (Uint8Array) and returns a hash of fixed-sized output. The return type of this hash is a byte. The &lt;code&gt;utf8ToBytes&lt;/code&gt; converts the message passed to the function to bytes which are then passed to the &lt;code&gt;keccak256&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;Finally, the function, &lt;code&gt;toHex&lt;/code&gt;, takes the returned bytes from the &lt;code&gt;keccak256&lt;/code&gt; function and converts it to a hexadecimal string, which is then returned by the &lt;code&gt;hashMessage&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;Its purpose is to encrypt a transaction message which would then be sent to the user to sign with their private key 🔑.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating the Wallet Component&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The functionality of this component is to allow the user to input any address and see its balance. Create a &lt;code&gt;Wallet.jsx&lt;/code&gt; file in the &lt;code&gt;src&lt;/code&gt; directory, then copy and paste the code below into the file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import server from "./server";

function Wallet({ address, setAddress, balance, setBalance }) {
  async function onChange(evt) {
    const address = evt.target.value;
    setAddress(address);
    if (address) {
      const {
        data: { balance },
      } = await server.get(`balance/${address}`);
      setBalance(balance);
    } else {
      setBalance(0);
    }
  }

  return (
    &amp;lt;div className="container wallet"&amp;gt;
      &amp;lt;h1&amp;gt;Your Wallet&amp;lt;/h1&amp;gt;

      &amp;lt;label&amp;gt;
        Wallet Address
        &amp;lt;input placeholder="Type an address, for example: 0x1" value={address} onChange={onChange}&amp;gt;&amp;lt;/input&amp;gt;
      &amp;lt;/label&amp;gt;

      &amp;lt;div className="balance"&amp;gt;Balance: {balance}&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default Wallet;

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

&lt;/div&gt;



&lt;p&gt;Every time the input changes it will invoke the &lt;code&gt;onChange&lt;/code&gt; event handler which will request the address balance from the server. If successful it will update the balance state using the &lt;code&gt;setBalance&lt;/code&gt; action. The Balance and Address states are created from the &lt;code&gt;App.jsx&lt;/code&gt; App component because their states will be used by the Transfer component too.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Transfer Component&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This component will be used by the user to send any amount to any recipient. Create a &lt;code&gt;Transfer.jsx&lt;/code&gt; file in the &lt;code&gt;src&lt;/code&gt; directory, then copy and paste the code below into the file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useState } from "react";
import server from "./server";
import { hashMessage } from "./services"

function Transfer({ address, setBalance }) {
  const [sendAmount, setSendAmount] = useState("");
  const [recipient, setRecipient] = useState("");

  const setValue = (setter) =&amp;gt; (evt) =&amp;gt; setter(evt.target.value);

  async function getSignature(evt){
    evt.preventDefault();

    try {
      let data = {
        recipient,
        amount: parseInt(sendAmount)
      }
      let msgHex = await hashMessage(JSON.stringify(data))
      let signature = prompt(`Sign message (${msgHex}) and provide signature:`)
      if (signature === null){
        alert("You did not provided a signature")
        return
      }
      await transfer(signature)
    } catch (ex) {
      alert(ex.response.data.message);
    }

  }

  async function transfer(signature) {
    const {
      data: { balance },
    } = await server.post(`send`, {
      sender: address,
      amount: parseInt(sendAmount),
      recipient,
      signature,
    });
    setBalance(balance);
    alert("Funds transferred successfully!")
  }

  return (
    &amp;lt;form className="container transfer" onSubmit={getSignature}&amp;gt;
      &amp;lt;h1&amp;gt;Send Transaction&amp;lt;/h1&amp;gt;

      &amp;lt;label&amp;gt;
        Send Amount
        &amp;lt;input
          placeholder="1, 2, 3..."
          value={sendAmount}
          onChange={setValue(setSendAmount)}
        &amp;gt;&amp;lt;/input&amp;gt;
      &amp;lt;/label&amp;gt;

      &amp;lt;label&amp;gt;
        Recipient
        &amp;lt;input
          placeholder="Type an address, for example: 0x2"
          value={recipient}
          onChange={setValue(setRecipient)}
        &amp;gt;&amp;lt;/input&amp;gt;
      &amp;lt;/label&amp;gt;

      &amp;lt;input type="submit" className="button" value="Transfer" /&amp;gt;
    &amp;lt;/form&amp;gt;
  );
}

export default Transfer;

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

&lt;/div&gt;



&lt;p&gt;This is a lot, so let's break it down.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
function Transfer({ address, setBalance })
...

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

&lt;/div&gt;



&lt;p&gt;The transfer component accepts two values;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;address - state object which is the sender's (user's) address&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;setBalance - state action which will be used to update the user's balance&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const [sendAmount, setSendAmount] = useState("");
const [recipient, setRecipient] = useState("");

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

&lt;/div&gt;



&lt;p&gt;These states are used to set the amount to be sent and the recipient's address.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
const setValue = (setter) =&amp;gt; (evt) =&amp;gt; setter(evt.target.value);
...

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

&lt;/div&gt;



&lt;p&gt;This function takes in a callable, &lt;code&gt;setter&lt;/code&gt; as an argument and returns an event handler. The function of the event handler is to pass the target value of the event object as an argument to &lt;code&gt;setter&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It's used here;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
&amp;lt;label&amp;gt;
  Send Amount
  &amp;lt;input
    placeholder="1, 2, 3..."
    value={sendAmount}
    onChange={setValue(setSendAmount)}
  &amp;gt;&amp;lt;/input&amp;gt;
&amp;lt;/label&amp;gt;

&amp;lt;label&amp;gt;
  Recipient
  &amp;lt;input
    placeholder="Type an address, for example: 0x2"
    value={recipient}
    onChange={setValue(setRecipient)}
  &amp;gt;&amp;lt;/input&amp;gt;
&amp;lt;/label&amp;gt;
...

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

&lt;/div&gt;



&lt;p&gt;The function, &lt;code&gt;setValue&lt;/code&gt; , is used for the onChange events of both inputs above. Which updates the states of both amount and recipient with the values of their respective inputs.&lt;/p&gt;

&lt;p&gt;Now, the function, &lt;code&gt;getSignature&lt;/code&gt; , will be demystified. The goal here is that when the user enters a recipient address, the amount to be sent, and submits the form. A transaction object will be created which will contain the amount and recipient address, this transaction will then be displayed to the user so that they can sign it with their private key 🔑. Then the signature will be passed to the transfer function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
async function getSignature(evt){
  evt.preventDefault();

  try {
    let data = {
      recipient,
      amount: parseInt(sendAmount)
    }
    let msgHex = await hashMessage(JSON.stringify(data))
    let signature = prompt(`Sign message (${msgHex}) and provide signature:`)
    if (signature === null){
      alert("You did not provided a signature")
      return
    }
    await transfer(signature)
  } catch (ex) {
    alert(ex.response.data.message);
  }
}
...

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

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;transfer&lt;/code&gt; function;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
async function transfer(signature) {
  const {
    data: { balance },
  } = await server.post(`send`, {
    sender: address,
    amount: parseInt(sendAmount),
    recipient,
    signature,
  });
  setBalance(balance);
  alert("Funds transferred successfully!")
}
...

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

&lt;/div&gt;



&lt;p&gt;This sends the signature and the transaction data to the server. If the signature is valid for the transaction data, then the money will be transferred to the recipient's address.&lt;/p&gt;

&lt;p&gt;That's all for the client-side application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Server-Side NodeJS Application
&lt;/h3&gt;

&lt;p&gt;The backend will be an express application. It's going to have two simple handlers;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;GET /balance/:address - to get an address balance&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;POST /send - to transfer funds from one address to another.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, we would need to create some useful scripts for generating new random wallets and signing transactions. The latter is meant to help users sign transaction messages with their private key 🔑.&lt;/p&gt;

&lt;p&gt;Firstly, let's set up the server directory. If not already created, create a new directory, &lt;code&gt;server&lt;/code&gt; , in the root directory. Move into the directory, and run &lt;code&gt;npm init -y&lt;/code&gt; to initialize the default &lt;code&gt;package.json&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Copy and paste the content below into the &lt;code&gt;package.json&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "name": "server",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "generate": "node ./scripts/gen.js",
    "sign": "node ./scripts/signer.js",
    "test": "echo \"Error: no test specified\" &amp;amp;&amp;amp; exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "cors": "^2.8.5",
    "ethereum-cryptography": "^1.1.2",
    "express": "^4.18.1",
    "yargs": "^17.6.2"
  }
}

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

&lt;/div&gt;



&lt;p&gt;Then run &lt;code&gt;npm install&lt;/code&gt; to install dependencies.&lt;/p&gt;

&lt;p&gt;Before creating the scripts for &lt;code&gt;generate&lt;/code&gt; and &lt;code&gt;sign&lt;/code&gt;, we will be creating &lt;code&gt;services.js&lt;/code&gt; first to define shared functions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Services&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create a new file &lt;code&gt;service.js&lt;/code&gt; in the &lt;code&gt;server&lt;/code&gt; directory. Copy and paste the code below into it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const secp = require("ethereum-cryptography/secp256k1");
const { keccak256 } = require("ethereum-cryptography/keccak")
const { utf8ToBytes, toHex } = require("ethereum-cryptography/utils")

function extractPublicKey(fullKey){
    let kec = keccak256(fullKey.slice(1, fullKey.length));
    return toHex(kec.slice(kec.length - 20, kec.length))
}

function verifySignature(sig, msg, pubKey){
    const msgHash = keccak256(utf8ToBytes(msg));
    let actualSignature = sig.slice(0, sig.length - 1)
    let recoveryBit = parseInt(sig[sig.length - 1])
    const sigPubKey = secp.recoverPublicKey(msgHash, actualSignature, recoveryBit);
    const mainKey = extractPublicKey(sigPubKey);
    return mainKey == pubKey
}

module.exports = {
    verifySignature,
    extractPublicKey
}

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

&lt;/div&gt;



&lt;p&gt;The function, &lt;code&gt;extractPublicKey&lt;/code&gt;, accepts bytes array as an argument, this is the byte format of a full public key. Then hashes it with &lt;code&gt;keccak256&lt;/code&gt; and returns the hexadecimal string of the last 20 bytes of the hash. &lt;a href="[https://ethereum.org/en/developers/docs/accounts/#key-differences:~:text=The%20public%20key%20is%20generated%20from%20the%20private%20key%20using%20the%20Elliptic%20Curve%20Digital%20Signature%20Algorithm.%20You%20get%20a%20public%20address%20for%20your%20account%20by%20taking%20the%20last%2020%20bytes%20of%20the%20Keccak%2D256%20hash%20of%20the%20public%20key%20and%20adding%200x%20to%20the%20beginning](https://ethereum.org/en/developers/docs/accounts/#key-differences:~:text=The%20public%20key%20is%20generated%20from%20the%20private%20key%20using%20the%20Elliptic%20Curve%20Digital%20Signature%20Algorithm.%20You%20get%20a%20public%20address%20for%20your%20account%20by%20taking%20the%20last%2020%20bytes%20of%20the%20Keccak%2D256%20hash%20of%20the%20public%20key%20and%20adding%200x%20to%20the%20beginning)"&gt;Ethereum docs&lt;/a&gt; explains why it's required. It's to make it shorter 😉.&lt;/p&gt;

&lt;p&gt;The last function, &lt;code&gt;verifySignature&lt;/code&gt;, accepts a signature, a transaction message, and the sender's public key. All this data is required to verify that the transaction message was indeed signed using the private key of the owner of the public key.&lt;/p&gt;

&lt;p&gt;The function hashes the transaction message and used [recoverPublicKey](&lt;a href="https://github.com/ethereum/js-ethereum-cryptography#secp256k1-curve:~:text=%3A%20boolean%0Afunction-,recoverPublicKey,-(msgHash%3A)" rel="noopener noreferrer"&gt;https://github.com/ethereum/js-ethereum-cryptography#secp256k1-curve:~:text=%3A%20boolean%0Afunction-,recoverPublicKey,-(msgHash%3A&lt;/a&gt; to get the public key of the signer. After extracting the short format using &lt;code&gt;extractPublicKey&lt;/code&gt;, it compares it will the public key, &lt;code&gt;pubKey&lt;/code&gt;, passed to the function.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Script - generate:&lt;/strong&gt; Generating new random public and private key pairs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const secp = require("ethereum-cryptography/secp256k1")
const { toHex } = require('ethereum-cryptography/utils')
const { extractPublicKey } = require('../services')

let privateKey = secp.utils.randomPrivateKey();
let pubKey = secp.getPublicKey(privateKey)

pubKey = extractPublicKey(pubKey)

console.log("Private key:", toHex(privateKey))
console.log("Public key:", pubKey)

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

&lt;/div&gt;



&lt;p&gt;A new private key is generated using the &lt;a href="[https://github.com/ethereum/js-ethereum-cryptography#secp256k1-curve:~:text=We%20strongly%20recommend%20using%20utils.randomPrivateKey()%20to%20generate%20them](https://github.com/ethereum/js-ethereum-cryptography#secp256k1-curve:~:text=We%20strongly%20recommend%20using%20utils.randomPrivateKey()%20to%20generate%20them)"&gt;randomPrivatekey&lt;/a&gt; function. The public key is also extracted from the private key. The mathematical property that made this possible is so amazing. The private key can never be known from the public key.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Script usage example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run generate

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Console output:&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Script - sign:&lt;/strong&gt; Signing transaction messages&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const yargs = require('yargs/yargs')
const { hideBin } = require('yargs/helpers')
const secp = require('ethereum-cryptography/secp256k1')
const { toHex } = require("ethereum-cryptography/utils")

let args = yargs(hideBin(process.argv))
    .option('private_key', {
        alias: 'p',
        type: 'string',
        description: 'Your Private Key',
        demandOption: true
    })
    .option('data', {
        alias: 'd',
        type: 'string',
        description: 'Payload to sign',
        demandOption: true
    })
    .parse()

let privKey = args.private_key
let msgHash = args.data

secp.sign(secp.utils.hexToBytes(msgHash), privKey, { recovered: true }).then(data =&amp;gt; {
    const [signature, recovery_bit] = data
    let sig = toHex(signature);
    console.log("Your Signature:", sig)
    console.log("Your Recovery Bit:", recovery_bit)
    let fullSig = sig + recovery_bit.toString()
    console.log("Copy and paste this as the full signature, this has the recovery bit attached to the end:\n", fullSig)
})

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

&lt;/div&gt;



&lt;p&gt;This is more of a CLI tool. It accepts the private key and message hash as command-line arguments. The &lt;code&gt;sign&lt;/code&gt; function from the module, &lt;code&gt;ethereum-cryptography/secp256k1&lt;/code&gt; , is used to sign the message hash, &lt;code&gt;msgHash&lt;/code&gt;. The result of the &lt;code&gt;signature&lt;/code&gt; and &lt;code&gt;recovery_bit&lt;/code&gt; received from the data are later concatenated to form a single string, signature, which is logged to the console.&lt;/p&gt;

&lt;p&gt;The signature is expected in the component, &lt;code&gt;Transfer&lt;/code&gt; , in the client-side application.&lt;/p&gt;

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

&lt;p&gt;So the user can copy it from the console and paste it into the prompt.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Script usage example&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run sign -- -p 3ebefedbd43cbd88f0504acd101df139ddce0656da699b8350c1db9eaf193484 -d 3ebefedbd43cbd88f0504acd101df139ddce0656da699b8350c1db9eaf178970

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Console output:&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;Now create the &lt;code&gt;index.js&lt;/code&gt; file, which will contain our API routes and handlers, in the &lt;code&gt;src&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;Follow the steps below and paste the codes gradually.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require("express");
const app = express();
const cors = require("cors");
const port = 3042;
const { verifySignature } = require("./services")

app.use(cors());
app.use(express.json());

const balances = {
  "KEY_A": 100,
  "KEY_B": 50,
  "KEY_C": 75,
  // KEY_N: Any amount
};

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

&lt;/div&gt;



&lt;p&gt;The object, &lt;code&gt;balances&lt;/code&gt; , is currently acting as the database. The keys of the object will be public keys of different wallets, and the values will be their respective balance.&lt;/p&gt;

&lt;p&gt;New public and private key pairs can be generated using the &lt;code&gt;generate&lt;/code&gt; script. After creating any amount of key pairs, update the object, &lt;code&gt;balances&lt;/code&gt;, with the public keys. Make sure to save their respective private keys too, so they can be used later for signing transaction messages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GET - /balance/:address&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.get("/balance/:address", (req, res) =&amp;gt; {
  const { address } = req.params;
  const balance = balances[address] || 0;
  res.send({ balance });
});

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

&lt;/div&gt;



&lt;p&gt;This is the route used to get an address balance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;POST - /send&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.post("/send", (req, res) =&amp;gt; {
  const { sender, recipient, amount, signature } = req.body;

  const msg = JSON.stringify({
    recipient,
    amount
  })
  let isValid = verifySignature(signature, msg, sender);
  if (isValid === false){
    res.status(400).send({ message: "Invalid Signature!" })
    return
  }

  setInitialBalance(sender);
  setInitialBalance(recipient);

  if (balances[sender] &amp;lt; amount) {
    res.status(400).send({ message: "Not enough funds!" });
  } else {
    balances[sender] -= amount;
    balances[recipient] += amount;
    res.send({ balance: balances[sender] });
  }
});

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

&lt;/div&gt;



&lt;p&gt;This route verifies the amount and recipient, against the signature and public key of the sender. If the signature is valid, it tries to debit the sender, if this is successful it will update the recipient balance.&lt;/p&gt;

&lt;p&gt;Lastly,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.listen(port, () =&amp;gt; {
  console.log(`Listening on port ${port}!`);
});

function setInitialBalance(address) {
  if (!balances[address]) {
    balances[address] = 0;
  }
}

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

&lt;/div&gt;



&lt;p&gt;Start the server to listen on any given port.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If the port is changed, make sure it's also updated in the client application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The function, &lt;code&gt;setInitialBalance&lt;/code&gt;, checks if an address exists in the database. If the address does not exist, it adds the address to the database with a balance of zero. This is a very nice method, as we don't need to manually add new users to our database.&lt;/p&gt;

&lt;p&gt;Project codes are &lt;a href="[https://github.com/devvspaces/ecdsa-node](https://github.com/devvspaces/ecdsa-node)"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;Cryptographic tools for Ethereum - &lt;a href="[https://www.npmjs.com/package/ethereum-cryptography](https://www.npmjs.com/package/ethereum-cryptography)"&gt;Ethereum Cryptography&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Node CLI tool - &lt;a href="[https://www.npmjs.com/package/yargs](https://www.npmjs.com/package/yargs)"&gt;Yargs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Play with Cryptographic hashes - &lt;a href="[https://emn178.github.io/online-tools/sha256](https://emn178.github.io/online-tools/sha256)"&gt;SHA256 Online tool&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Public Key Cryptography - &lt;a href="[https://en.wikipedia.org/wiki/RSA_(cryptosystem)](https://en.wikipedia.org/wiki/RSA_(cryptosystem))"&gt;RSA Algorithm&lt;/a&gt; &amp;amp; &lt;a href="[https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm)"&gt;Elliptic Digital Curves (ECDSA)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cryptography in HTTPS - &lt;a href="[https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange](https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange)"&gt;Diffie Hellman Key Exchange&lt;/a&gt; &amp;amp; &lt;a href="[https://security.stackexchange.com/a/41226](https://security.stackexchange.com/a/41226)"&gt;TLS handshake for HTTPS&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;The idea presented in this article can also be used in several fields on technology to maintain data integrity when data is transferred between several components through a network.&lt;/p&gt;

&lt;p&gt;One flaw of the server built today is that it's a single node, which makes the database a centralized instance. This is where a blockchain ledger would be useful because it's managed by more nodes which are all bound by rules (consensus) making the whole system decentralized. An account with a public key, &lt;code&gt;TEST&lt;/code&gt;, on &lt;code&gt;node A&lt;/code&gt;, would have the same balance on &lt;code&gt;node B&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Building applications on the blockchain will be covered later in new articles, subscribe to the newsletter to receive notifications when new articles drop.&lt;/p&gt;

&lt;p&gt;Follow me on Twitter &lt;a href="[https://twitter.com/netrobeweb](https://twitter.com/netrobeweb)"&gt;@netrobeweb&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>programming</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Build an Online Bookshop with Xata and Cloudinary</title>
      <dc:creator>Israel Ayanwola</dc:creator>
      <pubDate>Wed, 23 Nov 2022 11:19:37 +0000</pubDate>
      <link>https://dev.to/hackmamba/build-an-online-bookshop-with-xata-and-cloudinary-4c6d</link>
      <guid>https://dev.to/hackmamba/build-an-online-bookshop-with-xata-and-cloudinary-4c6d</guid>
      <description>&lt;p&gt;Hi, there. Today,  We will learn how to use Xata and Cloudinary to build Bookay, which is Jamstack architecture. Bookay is a platform for techies in Nigeria to buy technical books and sell used ones. It's an online bookshop. With Bookay, you can purchase books from the comfort of your home or sell your used books to earn more profits.&lt;/p&gt;

&lt;p&gt;Xata is a serverless database platform with no need for servers. It's one of the features I love about this product. As a backend developer / DevOps engineer, managing relational databases daily can be very stressful. But by using Xata, You don't have to deal with database migrations again, database management, and performance tuning. You just need to focus on what you need to do and let Xata focus on Data.&lt;/p&gt;

&lt;p&gt;Cloudinary helps with images and videos. You can use it to manage image and video uploading, deliver images anywhere on the web, and transform them. An example of image transformation is converting an image to a thumbnail. Cloudinary is used in Bookay to easily upload book images and edit and deliver images to users searching for books. We would use Cloudinary pluggable image uploader available as a React component; this comes with out-of-the-box functionality to set up image uploading swiftly. Image transformation can happen right in the element used to display them. Book images can be uploaded once and transformed anytime, anywhere.&lt;/p&gt;

&lt;p&gt;This article will teach you how to build a web application where you can buy books and sell your books online. We would go through Bookay's architecture, teaching you how to use Xata's database-less platform and Cloudinary's image upload features to build your online bookshop. Building your applications using the platforms above, can make your application development less affected by changes in business logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Idea: Bookay
&lt;/h2&gt;

&lt;p&gt;Finding technical books is not easy in Nigeria. Books are available, but it's not easy to find. The idea behind Bookay, an online bookshop, is to make books ready and available online. It is a platform where you can easily find any available technical or non-technical books you want to buy. Bookay allows sellers to list their books on the forum, allowing buyers to search and buy books easily.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture Overview: Xata + Cloudinary + NextJs
&lt;/h3&gt;

&lt;p&gt;Using just NextJs, Bookay was built. Uploading of data to Xata is done with APIs. Xata comes with built-in automated full-text search functionality on all created tables ❤️. Images are uploaded to Cloudinary, from which you can quickly transform them while viewing it. For example, Image thumbnails can be used when displaying a list of books from search results, and larger images are used when showing a single book.&lt;/p&gt;

&lt;p&gt;Although, security is needed when working with APIs. NextJs allows developers to make API calls on the server side, secluding API authentication details from the client side. This is why NextJs can easily be the best framework for building Jamstack products. But, Xata does not depend on any language or framework, It is language-agnostic. You can use any of your favourite languages or frameworks to use Xata.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Bookay: Your Online Bookshop 🛩️
&lt;/h2&gt;

&lt;p&gt;Let's go through how you can build your own online bookshop. Bookay is already deployed on Vercel and it's Open source on GitHub.&lt;/p&gt;

&lt;p&gt;Let's get started by setting it up on our computer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Node v12.18.3 or higher,&lt;/li&gt;
&lt;li&gt;npm v6.14.6 or higher.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Dependencies
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Xata: Set up your database for free&lt;/li&gt;
&lt;li&gt;Cloudinary: Quickstart with Cloudinary React&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Installation:
&lt;/h3&gt;

&lt;p&gt;A step-by-step series of examples that tell you how to get a development env running.&lt;/p&gt;

&lt;p&gt;Clone the project and make sure you are in the project root directory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    git clone https://github.com/devvspaces/bookay
    &lt;span class="nb"&gt;cd &lt;/span&gt;bookay
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Installing dependencies&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above command would install all necessary dependencies to run Bookay on your computer.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Setting up your own Xata and Cloudinary account is needed. After installing the required dependencies, run the command,  &lt;code&gt;xata auth login&lt;/code&gt;, to authenticate with Xata and create your DB. For more information on using Xata CLI.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When starting your New project, Xata will automatically set up your development environment.&lt;/p&gt;

&lt;p&gt;Run your development server&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Visit your running server URL; this will likely be &lt;code&gt;http://localhost:3000&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Login / Register: This link allows you to log in or automatically create an account if it doesn't exist.&lt;/li&gt;
&lt;li&gt;Register as Seller: This allows you to create a seller account specifically.&lt;/li&gt;
&lt;li&gt;You can now add new books, update books, and view and delete books.&lt;/li&gt;
&lt;li&gt;You can check your sellers' store orders and normal orders for users.&lt;/li&gt;
&lt;li&gt;And the rest is history!&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Development 💪🏽
&lt;/h3&gt;

&lt;p&gt;The best feature of the project development is code reusability.&lt;/p&gt;

&lt;h4&gt;
  
  
  Models
&lt;/h4&gt;

&lt;p&gt;In this project, we will use write model classes. These are JavaScript objects that contain methods that serve as utility methods for interacting with a table on Xata. Model classes will use the Xata SDK API to read from or write to the database. Xata's concept revolves around tables. Tables can relate to one another like a relational database. Most of the data and business logic reside here. It also allows the code to be tested without calling Xata during tests. This can be achieved just by mocking the model classes and overriding their methods. An example of the test procedure can be found in my other repo, the Xata demo todo app.&lt;/p&gt;

&lt;p&gt;Features on your online bookshop made available by Xata are database CRUD management, full complete type safe typescript SDK, and full-text search. With these features, you are not limited to building only an online bookshop. The sky is your limit. &lt;/p&gt;

&lt;h4&gt;
  
  
  API Routes and Server Side Props.
&lt;/h4&gt;

&lt;p&gt;API routes and Server Side Props are the only communication methods with Xata API. This is the best and recommended way because it makes sure your Xata API requests are secured and hidden. So that API Keys won't get sniffed out. Data fetching in NextJs runs on the Server Side. This development pattern available with NextJs can help you build complete web applications with a single framework. Furthermore, the app will run most of its life cycle in the client's browsers, making it blazingly fast.&lt;/p&gt;

&lt;h4&gt;
  
  
  Cloudinary for Image Transformation
&lt;/h4&gt;

&lt;p&gt;As said earlier, this is the easiest to set up. You just install Cloudinary react components, and that's all. Using Cloudinary's documentation, you can easily set up your image book uploader and editor. It's right there in the documentation. It doesn't require complex requirements like API routes or Server Side Props. With React components, you can have a complete image upload and preview set up in 10 min.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deployment ❤️
&lt;/h3&gt;

&lt;p&gt;You can deploy your new online bookshop on Vercel or Netlify in minutes. Just connect the platform to your GitHub account. Give access to your project, and you will get a smooth developer experience for deployment. Deployment has never been this interesting and easy. It's fast. It's also pre-built with CI / CD integrations, allowing your online bookshop to automatically be redeployed to new URLs every time you update any branch. Tutorial to do that here.&lt;/p&gt;

&lt;p&gt;Book's source code is well documented; going through the code alone can help you learn more about the project. Installing, running, and testing the project on your computer can give you more practical experience in understanding the project's architecture. You will get more experience building Xata and Cloudinary applications by adding your features to the app.&lt;/p&gt;

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

&lt;p&gt;The developing experience of using frameworks or platforms is essential. Apart from making your development faster, It means you can develop web applications while paying less to no attention to the platform's inner workings. This is Xata and Cloudinary. Focus less on how you will set up that database or that user's profile image. They will handle it. Thanks for reading.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>jamstack</category>
      <category>cloudinary</category>
      <category>xata</category>
    </item>
    <item>
      <title>Working with strings effectively with Golang</title>
      <dc:creator>Israel Ayanwola</dc:creator>
      <pubDate>Sun, 09 Oct 2022 01:26:46 +0000</pubDate>
      <link>https://dev.to/devvspaces/working-with-strings-effectively-with-golang-48fi</link>
      <guid>https://dev.to/devvspaces/working-with-strings-effectively-with-golang-48fi</guid>
      <description>&lt;h1&gt;
  
  
  What are Strings? 🤔
&lt;/h1&gt;

&lt;p&gt;The way strings is stored in memory makes them immutable, making it difficult to perform simple operations like changing the value of an index in a string. For example you can't perform an index assignment operation on a string, but this is possible with arrays. Golang has a built-in library that can help us work with strings. We are able to read and manipulate strings in various ways.&lt;/p&gt;

&lt;p&gt;In this tutorial series, we would discuss about ways we can manipulate a string in Golang. By looking into&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Peeking,&lt;/li&gt;
&lt;li&gt;Traversing,&lt;/li&gt;
&lt;li&gt;Mutating, and&lt;/li&gt;
&lt;li&gt;Sorting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;of strings in Golang, you should be confident enough to work with them in any aspect of programming you come across.&lt;/p&gt;

&lt;h1&gt;
  
  
  Working with Strings 🛩
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Peeking
&lt;/h2&gt;

&lt;p&gt;In this use case Peeking means inspecting a string trying to find what it looks like. For example, checking the first character of a string, the character at an index, the characters in a range of two index, etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing the first and last characters of a string
&lt;/h3&gt;

&lt;p&gt;We can test what starts (prefixes) and ends (suffixes) a string.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "strings"
)

func main() {
    var str string = "Hashnode is a very easy tool to use for blogging"
    fmt.Printf("T/F? \nDoes the string \"%s\" have prefix %s? ", str, "Th")
    fmt.Printf("\n%t\n\n", strings.HasPrefix(str, "Th")) // Finding prefix

    fmt.Printf("Does the string \"%s\" have suffix %s? ", str, "ting")
    fmt.Printf("\n%t\n\n", strings.HasSuffix(str, "ing")) // Finding suffix
}

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://go.dev/play/p/OiVccenFYBa"&gt;Run code live here&lt;/a&gt;&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;T/F? 
Does the string "Hashnode is a very easy tool to use for blogging" have prefix Th? 
false

Does the string "Hashnode is a very easy tool to use for blogging" have suffix ting? 
true

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

&lt;/div&gt;



&lt;p&gt;From the output above, the function &lt;code&gt;HasPrefix&lt;/code&gt; checks whether the string in its first parameter starts with the &lt;code&gt;Th&lt;/code&gt;. The function &lt;code&gt;HasSuffix&lt;/code&gt; does the opposite of that, it checks the end of the string. The &lt;code&gt;HasPrefix&lt;/code&gt; function returns &lt;code&gt;false&lt;/code&gt; because the string in variable &lt;code&gt;str&lt;/code&gt; doesn't start with &lt;code&gt;Th&lt;/code&gt;. While &lt;code&gt;HasSuffix&lt;/code&gt; returned &lt;code&gt;true&lt;/code&gt; because the string &lt;code&gt;str&lt;/code&gt; ends with &lt;code&gt;ing&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The above methods show a simple way to test what starts and ends any string.&lt;/p&gt;

&lt;h3&gt;
  
  
  Indexing a string
&lt;/h3&gt;

&lt;p&gt;For beginners, indexing a string in Go for the first time will seem weird. When you index a string in Go you get a rune. The Go language defines the word rune as an alias for the type int32. &lt;a href="https://go.dev/blog/strings"&gt;Read more about string in Go&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take the following code sample as an example;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
)

func main() {
    var str string = "Hashnode is a very easy tool to use for blogging"
    fmt.Println(str[0])
}

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://go.dev/play/p/gdFkhGA5odB"&gt;Run code live here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Output&lt;br&gt;
&lt;/p&gt;

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

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

&lt;/div&gt;



&lt;p&gt;Converting the rune to a string gives the actual character at that index.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
)

func main() {
    var str string = "Hashnode is a very easy tool to use for blogging"
    fmt.Println(string(str[0]))
}

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://go.dev/play/p/PRn2PRv61sT"&gt;Run code live here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Output&lt;br&gt;
&lt;/p&gt;

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

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Testing if a string contains a substring
&lt;/h3&gt;

&lt;p&gt;To check if a string contains some string, do the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "strings"
)

func main() {
    var str = "I code Python, Golang, JavaScript, TypeScript and PHP"
    fmt.Println(strings.Contains(str, "Golang"))
    fmt.Println(strings.Contains(str, "Rust"))
}

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://go.dev/play/p/vjoYCSkhTyg"&gt;Run code live here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Output&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;true
false

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

&lt;/div&gt;



&lt;p&gt;The function &lt;code&gt;Contains&lt;/code&gt; returns &lt;code&gt;true&lt;/code&gt; if the second parameter is found in the first parameter. Otherwise, it returns &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Locating the index of a substring or character in a string
&lt;/h3&gt;

&lt;p&gt;We can locate the first or last occurrence of a substring or character in a string.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "strings"
)

func main() {
    var str string = "Hi, I'm Marc, Hi."
    fmt.Printf("The position of the first instance of\"Marc\" is: ")
    fmt.Printf("%d\n", strings.Index(str, "Marc")) // Finding first occurence
    fmt.Printf("The position of the first instance of \"Hi\" is: ")
    fmt.Printf("%d\n", strings.Index(str, "Hi")) // Finding first occurence
    fmt.Printf("The position of the last instance of \"Hi\" is: ")
    fmt.Printf("%d\n", strings.LastIndex(str, "Hi")) // Finding last occurence
    fmt.Printf("The position of the first instance of\"Burger\" is: ")
    fmt.Printf("%d\n", strings.Index(str, "Burger")) // Finding first occurence
    fmt.Printf("%d\n", strings.IndexRune(str, 'H')) // Finding first occurence
}

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://go.dev/play/p/hYHtGf04EHX"&gt;Run code live here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Output&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The position of the first instance of"Marc" is: 8
The position of the first instance of "Hi" is: 0
The position of the last instance of "Hi" is: 14
The position of the first instance of"Burger" is: -1
0

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

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Index&lt;/code&gt; returns the index of the first instance of the second parameter in the first parameter. &lt;code&gt;LastIndex&lt;/code&gt; searches from the end of the string, returning the index of the last occurrence of the character or substring in the searched string. IndexRune returns the index of the first instance of the Unicode code point &lt;code&gt;'H'&lt;/code&gt; in the string &lt;code&gt;str&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  To be continued
&lt;/h2&gt;

&lt;p&gt;Hope you learned something new today!. This part of the String series focuses on how you can test the values of a string in Go. You can practice more of the functions covered in this tutorial. To master and do more practice check out the Strings module documentation. Learn on your own how to use &lt;code&gt;strings.Count&lt;/code&gt; to count the number of occurences of a character or substring in a string.&lt;/p&gt;

&lt;p&gt;In the next part, we would look at ways a string can be manipulated in Go. Thanks for reading.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
