<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Edouard Bonlieu</title>
    <description>The latest articles on Forem by Edouard Bonlieu (@edouardb_).</description>
    <link>https://forem.com/edouardb_</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%2F426347%2F5ed10367-a4d0-4e9e-9796-1a1a8e26295b.jpg</url>
      <title>Forem: Edouard Bonlieu</title>
      <link>https://forem.com/edouardb_</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/edouardb_"/>
    <language>en</language>
    <item>
      <title>How to Deploy a Rails Application and Add Authentication using Devise</title>
      <dc:creator>Edouard Bonlieu</dc:creator>
      <pubDate>Wed, 09 Feb 2022 17:25:44 +0000</pubDate>
      <link>https://forem.com/koyeb/how-to-deploy-a-rails-application-and-add-authentication-using-devise-3dh7</link>
      <guid>https://forem.com/koyeb/how-to-deploy-a-rails-application-and-add-authentication-using-devise-3dh7</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Ruby on Rails is a Ruby web application framework that helps make building modern web applications an easy experience. It powers software created by companies like Airbnb, GitHub, Soundcloud, Shopify, and a host of other companies.&lt;/p&gt;

&lt;p&gt;User authentication is a common feature present in most software products. It is especially important in software products where the identity of a user is required before they are granted access to the system.&lt;/p&gt;

&lt;p&gt;In this tutorial, you will learn how to implement authentication in a Rails application by using Devise, an authentication solution for Rails. We will deploy this application on Koyeb and enjoy the platform's built-in autoscaling, automatic HTTPS, global load balancing, and more. With Koyeb's git-driven deployment, all changes you make to your application will be automatically built and promoted once the build and necessary healthchecks are complete.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;To successfully follow this tutorial, you need the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ruby programming language installed on your local development machine. This tutorial uses version 2.6.6 of Ruby.&lt;/li&gt;
&lt;li&gt;Ruby on Rails framework installed on your local development machine. This demo application in this tutorial is built with Rails 6.1&lt;/li&gt;
&lt;li&gt;Node.js 10.17 or higher installed on your local development machine.&lt;/li&gt;
&lt;li&gt;Yarn package manager installed on your local development machine.&lt;/li&gt;
&lt;li&gt;PostgreSQL installed on your local development machine. This tutorial uses version 13 of PostgreSQL.&lt;/li&gt;
&lt;li&gt;An &lt;a href="https://customer.elephantsql.com/login" rel="noopener noreferrer"&gt;ElephantSQL&lt;/a&gt; account to get a PostgreSQL database.&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://app.koyeb.com/" rel="noopener noreferrer"&gt;Koyeb&lt;/a&gt; account to deploy the demo application.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The steps to implementing authentication in a Rails application and deploying it to Production on Koyeb include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
Creating a new Rails application.&lt;/li&gt;
&lt;li&gt;
Setting up the database.&lt;/li&gt;
&lt;li&gt;
Creating the application homepage.&lt;/li&gt;
&lt;li&gt;
Adding messages to the application.&lt;/li&gt;
&lt;li&gt;
Integrate Authentication to the application with Devise.&lt;/li&gt;
&lt;li&gt;
Deploying the Rails application to Koyeb.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Creating A New Rails Application
&lt;/h2&gt;

&lt;p&gt;In this section, you will create a new Rails application. This demo application will contain messages that should be visible to only authenticated users.&lt;/p&gt;

&lt;p&gt;Rails provides a set of commands that make building web applications an easy experience. One such command is the &lt;code&gt;new&lt;/code&gt; command, used to generate a new Rails application. To create a new Rails application, open up a terminal window on your machine and run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails new secret_message &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;postgresql &lt;span class="nt"&gt;-T&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command above creates a new Rails application in a directory named &lt;code&gt;secret_message&lt;/code&gt; using the options passed to the &lt;code&gt;new&lt;/code&gt; command and installs all necessary dependencies. The options passed to the &lt;code&gt;new&lt;/code&gt; command specify the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;-d&lt;/code&gt; flag specifies the type of database to be set up for the application. The demo application for this tutorial will use a Postgres database.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;T&lt;/code&gt; flag ensures that dependencies required for writing tests are not installed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If run successfully, the command will return a bunch of output that ends with text similar to the one below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;├─ websocket-extensions@0.1.4
└─ ws@6.2.2
✨  Done &lt;span class="k"&gt;in &lt;/span&gt;13.84s.
Webpacker successfully installed 🎉 🍰
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the command is done running, move to the created &lt;code&gt;secret_message&lt;/code&gt; directory in your terminal by running:&lt;br&gt;
&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;secret_message
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;secret_message&lt;/code&gt; directory is the root directory of the demo application and is where subsequent commands will be run to build out the demo application. To see your new Rails application in the browser, run the command below in your terminal window:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;The command above fires up a Puma server, which is Rails' default web server, and serves the Rails application on port 3000. To see the application, navigate to &lt;code&gt;http://localhost:3000&lt;/code&gt; in your browser, and you will be greeted with Rails' default welcome 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%2Fi.imgur.com%2F6O54oUI.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%2Fi.imgur.com%2F6O54oUI.png" alt="Rails welcome page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To stop the Puma server at any time, press the &lt;code&gt;CTRL+C&lt;/code&gt; button in the terminal window where it is running. This will stop the running server, and the application will no longer be accessible in the browser.&lt;/p&gt;

&lt;p&gt;With the Rails application successfully created, it will be connected to a database in the next section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up The Database
&lt;/h2&gt;

&lt;p&gt;Your new Rails application needs a database to store the messages to be shown to authenticated users. In this section, you will connect the demo application to a PostgreSQL database.&lt;/p&gt;

&lt;p&gt;Rails offers the ability to set up a different database per software life cycle environment. The database config file found in &lt;code&gt;config/database.yml&lt;/code&gt; contains sections to provide database information for the development, test and production environment. The database config file comes pre-filled with database config values for each environment, and these values can be altered as preferred. The default database config for the demo application is shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;default&lt;/span&gt;
  &lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgresql&lt;/span&gt;
  &lt;span class="na"&gt;encoding&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unicode&lt;/span&gt;
  &lt;span class="na"&gt;pool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %&amp;gt;&lt;/span&gt;
&lt;span class="na"&gt;development&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*default&lt;/span&gt;
  &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;secret_message_development&lt;/span&gt;
&lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*default&lt;/span&gt;
  &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;secret_message_test&lt;/span&gt;
&lt;span class="na"&gt;production&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*default&lt;/span&gt;
  &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;secret_message_production&lt;/span&gt;
  &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;secret_message&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= ENV['SECRET_MESSAGE_DATABASE_PASSWORD'] %&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the sake of this tutorial, we will use the default database config provided by Rails. To set up a database for a Rails application using the database config values, Rails provides a &lt;code&gt;db:prepare&lt;/code&gt; command. This command creates databases using values set in the database config. While in the &lt;code&gt;secret_message&lt;/code&gt; directory in your terminal, run the following command to create the necessary databases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails db:prepare
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command creates a development and test database and returns the following output when run successfully:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Created database &lt;span class="s1"&gt;'secret_message_development'&lt;/span&gt;
Created database &lt;span class="s1"&gt;'secret_message_test'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that, you have successfully connected your Rails application to a PostgreSQL database. In the next section, you will create a homepage for the application.&lt;/p&gt;

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

&lt;p&gt;The demo application currently displays the Rails' welcome page as its home page, and in this section, you will replace that with a new homepage.&lt;/p&gt;

&lt;p&gt;Rails adopts the Model-View-Controller or MVC pattern of software design. A Rails controller sits between a view and a model, receiving requests and responses and passing them to their corresponding view or model. Creating a homepage for the demo application involves creating a controller and view to handle requests to view the homepage.&lt;/p&gt;

&lt;p&gt;For the demo application, requests to view the homepage as well as to view existing messages in the application will be handled using the same controller. Rails provides a &lt;code&gt;controller&lt;/code&gt; generator command for creating controllers. To create a controller for the homepage and messages, run the command below in the demo application's root directory in your terminal window:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails generate controller SecretMessages home index show &lt;span class="nt"&gt;--skip-assets&lt;/span&gt; &lt;span class="nt"&gt;--no-helper&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The controller generator command above accepts three actions; &lt;code&gt;home&lt;/code&gt;, &lt;code&gt;index&lt;/code&gt; and &lt;code&gt;show&lt;/code&gt;. Rails generates a controller action and a corresponding view file for each action passed to it. A controller action in Rails is a method in a controller class that matches a route. It contains the code to be executed when its matching route receives a request. Two additional options are passed to the generator command; the &lt;code&gt;--skip-asset&lt;/code&gt; option prevents the generation of CSS asset files for views, while the &lt;code&gt;--no-helper&lt;/code&gt; option prevents the creation of a controller helper file.&lt;/p&gt;

&lt;p&gt;Running the command generates four files in the project directory. They include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;secret_messages_controller.rb&lt;/code&gt; controller with three methods that correspond to the actions passed to the generator command.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;home.html.erb&lt;/code&gt; file which will be the view for the homepage.&lt;/li&gt;
&lt;li&gt;An &lt;code&gt;index.html.erb&lt;/code&gt; file which will be the view for displaying a list of messages in the application.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;show.html.erb&lt;/code&gt; file which will be the view for displaying individual messages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition to generating controller and view files, the command updates the routes file located at &lt;code&gt;config/routes.rb&lt;/code&gt;. It adds a &lt;code&gt;get&lt;/code&gt; route for each action passed to the command. The routes added to the routes file by the controller generator command need to be edited to specify the application's root route.&lt;/p&gt;

&lt;p&gt;A root route in Rails is a route that specifies the page to be displayed when users visit the root URL of a Rails application. In your preferred text editor, open the routes file located at &lt;code&gt;config/routes.rb&lt;/code&gt; and make the changes below to the three get routes in 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;- get 'secret_messages/home'
+ root 'secret_messages#home'
- get 'secret_messages/index'
+ get '/secret_messages', to: 'secret_messages#index'
- get 'secret_messages/show'
+ get '/secret_message/:id', to: 'secret_messages#show', as: :secret_message
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, changes are made to the routes generated by the controller generator command. With the &lt;code&gt;root&lt;/code&gt; keyword, the root route is mapped to the &lt;code&gt;home&lt;/code&gt; action of the &lt;code&gt;SecretMessages&lt;/code&gt; controller. With this, Rails routes requests made to the root URL (&lt;code&gt;/&lt;/code&gt;) of the application to the &lt;code&gt;home&lt;/code&gt; action of the &lt;code&gt;SecretMessages&lt;/code&gt; controller, and its corresponding view is displayed. Also, the &lt;code&gt;/secret_messages&lt;/code&gt; route is mapped to the index action of the secret messages controller, while an &lt;code&gt;id&lt;/code&gt; param is added to the last route, and it is mapped to the show action of the secret message controller. The route is also named &lt;code&gt;secret_message&lt;/code&gt; using the &lt;code&gt;as&lt;/code&gt; keyword. Make sure to save the file after making the changes.&lt;/p&gt;

&lt;p&gt;With the root route now set up, the application's homepage will no longer display Rails' default welcome page. Before viewing the new homepage, we will add &lt;a href="https://simplecss.org/" rel="noopener noreferrer"&gt;Simple.css&lt;/a&gt; to the application. Simple.css is a classless CSS framework that offers basic styles to semantic HTML.&lt;/p&gt;

&lt;p&gt;In your text editor, open the &lt;code&gt;application.html.erb&lt;/code&gt; file located at &lt;code&gt;app/views/layouts/application.html.erb&lt;/code&gt; and add the code below to the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; section of the HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  ...
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.simplecss.org/simple.min.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The link loads minified Simple.css styles into the application. Next, replace the markup in the homepage view located at &lt;code&gt;app/views/secret_messages/home.html.erb&lt;/code&gt; with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Secret Messages&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;figure&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Image"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://i.imgur.com/XZcDi6Q.jpeg"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"83%"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"auto"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;figcaption&amp;gt;&lt;/span&gt;Source: https://imgur.com/gallery/A3fia&lt;span class="nt"&gt;&amp;lt;/figcaption&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/figure&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Secret messages for your eyes only&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This adds an image and text for a customized homepage. With that change, save the file and start the Rails server in your terminal window by running &lt;code&gt;rails s&lt;/code&gt; and view the application in your browser at &lt;code&gt;http://localhost:3000&lt;/code&gt;. You will see the image below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FtmKGtJ3.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%2Fi.imgur.com%2FtmKGtJ3.png" alt="Application homepage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this section, you successfully set up a homepage for the demo application, and in the next section, you will add messages to the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Messages to the Application
&lt;/h2&gt;

&lt;p&gt;After setting up the demo application's homepage, you will create a model to handle messages in the application in this section.&lt;/p&gt;

&lt;p&gt;A Rails model is a class that represents an object, in this case, a message, and facilitates the creation and manipulation of said objects between the database and a Rails application. As with most tasks in a Rails application, Rails provides a &lt;code&gt;generate model&lt;/code&gt; command to create a model in a Rails application. The command accepts a model name along with its properties and data types. The message object for the demo application will have two properties: a title and a body.&lt;/p&gt;

&lt;p&gt;Run the command below in your terminal window to create a &lt;code&gt;Message&lt;/code&gt; model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails generate model message title:string body:text
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running the command above instructs Rails to create a &lt;code&gt;Message&lt;/code&gt; model with a title and body property, both having a string and text type, respectively. The command generates the following files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;message.rb&lt;/code&gt; file that serves as the message model.&lt;/li&gt;
&lt;li&gt;A migration file that contains instructions for creating a &lt;code&gt;messages&lt;/code&gt; table in the database. The file's name is a concatenation of the timestamp for when the file was created and the model name. E.g. &lt;code&gt;20220112205345_create_messages.rb&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, you'll edit the message model and add some validation rules. Rails provides validation rules that help define the valid state of model objects. These validation rules are checked before records are saved onto the database. Open the message model located at &lt;code&gt;app/models/message.rb&lt;/code&gt; and add the following lines of code to the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Message&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;validates&lt;/span&gt; &lt;span class="ss"&gt;:title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;presence: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above validates the presence of a title and body in every message object and prevents saving message objects where these properties are missing. Save the file after making the changes.&lt;/p&gt;

&lt;p&gt;Before message objects can be saved to the database, you need to run the migration file that was generated when creating the message model. The migration file located at &lt;code&gt;db/migrate/&amp;lt;timestamp&amp;gt;_create_messages.rb&lt;/code&gt; contains code to create a &lt;code&gt;messages&lt;/code&gt; table with a &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;body&lt;/code&gt; and timestamps columns (&lt;code&gt;created_at&lt;/code&gt; and &lt;code&gt;updated_at&lt;/code&gt;). To run the migration, run the command below in your terminal window:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails db:migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command above is Rails' database migrate command. Running this command executes the code in the migration file. When ran successfully, it returns an output similar to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;==&lt;/span&gt; 20220112205345 CreateMessages: migrating &lt;span class="o"&gt;===================================&lt;/span&gt;
&lt;span class="nt"&gt;--&lt;/span&gt; create_table&lt;span class="o"&gt;(&lt;/span&gt;:messages&lt;span class="o"&gt;)&lt;/span&gt;
    -&amp;gt; 0.0310s
&lt;span class="o"&gt;==&lt;/span&gt; 20220112205345 CreateMessages: migrated &lt;span class="o"&gt;(&lt;/span&gt;0.0312s&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==========================&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the &lt;code&gt;messages&lt;/code&gt; table now created, it can be populated with predefined messages. Rails offers the ability to seed the database with predefined records using a seeds file. The Rails' seeds file is located at &lt;code&gt;db/seed.rb&lt;/code&gt; and is triggered by the database seed command.&lt;br&gt;
To create some demo messages for the application, open the seeds file located at &lt;code&gt;db/seed.rb&lt;/code&gt; in your favorite text editor and add the following code to the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="s1"&gt;'Running seeds'&lt;/span&gt;
&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="no"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="ss"&gt;title: &lt;/span&gt;&lt;span class="s2"&gt;"Message &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;body: &lt;/span&gt;&lt;span class="s2"&gt;"Prow scuttle parrel provost Sail ho shrouds spirits boom mizzenmast yardarm. Pinnace holystone mizzenmast quarter crow's nest nipperkin grog yardarm hempen halter furl. Swab barque interloper chantey doubloon starboard grog black jack gangway rutters.
    Deadlights jack lad schooner scallywag dance the hempen jig carouser broadside cable strike colors. Bring a spring upon her cable holystone blow the man down spanker Shiver me timbers to go on account lookout wherry doubloon chase. Belay yo-ho-ho keelhaul squiffy black spot yardarm spyglass sheet transom heave to.
    Trysail Sail ho Corsair red ensign hulk smartly boom jib rum gangway. Case shot Shiver me timbers gangplank crack Jennys tea cup ballast Blimey lee snow crow's nest rutters. Fluke jib scourge of the seven seas boatswain schooner gaff booty Jack Tar transom spirits."&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="s1"&gt;'Seeds run successfully'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above runs a loop ten times and creates a message record using the predefined values. To run the seeds, run the following code in your terminal window:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails db:seed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The database seed command above runs the code in the seeds file and populates the database with ten records. When ran successfully, it returns the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="s2"&gt;"Running seeds"&lt;/span&gt;
&lt;span class="s2"&gt;"Seeds run successfully"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To see the number of messages in the database, open the rails console by running &lt;code&gt;rails console&lt;/code&gt; in your terminal window. Running that command will return an &lt;code&gt;irb&lt;/code&gt; prompt like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Loading development environment &lt;span class="o"&gt;(&lt;/span&gt;Rails 6.1.4.4&lt;span class="o"&gt;)&lt;/span&gt;
irb&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;:001:0&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the prompt, run &lt;code&gt;Message.count&lt;/code&gt; to see the number of message records in the database. The command should return the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;(&lt;/span&gt;8.8ms&lt;span class="o"&gt;)&lt;/span&gt;  SELECT COUNT&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; FROM &lt;span class="s2"&gt;"messages"&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The query result shows there are ten message records in the database. Type &lt;code&gt;exit&lt;/code&gt; to quit the &lt;code&gt;irb&lt;/code&gt; prompt at any time.&lt;/p&gt;

&lt;p&gt;With the messages in place, add the logic for viewing all and one message. Rails applications can create, read, update and delete records in the database using Active Record. Open the &lt;code&gt;app/controllers/secret_messages_controller.rb&lt;/code&gt; file in your text editor and update the &lt;code&gt;index&lt;/code&gt; and &lt;code&gt;show&lt;/code&gt; methods with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
  &lt;span class="vi"&gt;@messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;show&lt;/span&gt;
  &lt;span class="vi"&gt;@message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;index&lt;/code&gt; action, Active Record's &lt;code&gt;all&lt;/code&gt; method is used to fetch all the message records in the database, and the result is assigned to a &lt;code&gt;@messages&lt;/code&gt; instance variable. In the &lt;code&gt;show&lt;/code&gt; action, Active Record's &lt;code&gt;find&lt;/code&gt; method is used to find the message whose &lt;code&gt;id&lt;/code&gt; matches the &lt;code&gt;id&lt;/code&gt; in the request params and is assigned to the &lt;code&gt;@message&lt;/code&gt; instance variable.  The instance variables ensure the messages are accessible in the view.&lt;/p&gt;

&lt;p&gt;The last step towards viewing the existing messages in the app is to display them in their respective view pages. The &lt;code&gt;index&lt;/code&gt; view will display a list of all messages in the database, while the show page will display individual messages. First, open the &lt;code&gt;index&lt;/code&gt; view located at &lt;code&gt;app/views/secret_messages/index.html.erb&lt;/code&gt; and replace the code in it with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="no"&gt;Secret&lt;/span&gt; &lt;span class="no"&gt;Messages&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&amp;gt;
&amp;lt;% @messages.each do |message| %&amp;gt;
  &amp;lt;h4&amp;gt; &amp;lt;%= link_to message.title, secret_message_path(id: message.id) %&amp;gt; &amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;h4&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;% end &lt;/span&gt;&lt;span class="o"&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code in the &lt;code&gt;index&lt;/code&gt; view above accesses the &lt;code&gt;@messages&lt;/code&gt; instance variable created in the &lt;code&gt;index&lt;/code&gt; action of the &lt;code&gt;SecretMessages&lt;/code&gt; controller and loops over it to render each message's title in a link that links to the show page for each message. Lastly, open the &lt;code&gt;show&lt;/code&gt; view located at &lt;code&gt;app/views/secret_messages/show.html.erb&lt;/code&gt; and replace the code in it with the code below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= @message.title %&amp;gt;&amp;lt;/h1&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;%=&lt;/span&gt; &lt;span class="vi"&gt;@message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;body&lt;/span&gt; &lt;span class="sx"&gt;%&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= link_to 'Back', secret_messages_path %&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code in the &lt;code&gt;show&lt;/code&gt; view above accesses the &lt;code&gt;@message&lt;/code&gt; instance variable declared in the &lt;code&gt;show&lt;/code&gt; action of the &lt;code&gt;SecretMessages&lt;/code&gt; controller and displays the message's title, body and a link to go back to the &lt;code&gt;index&lt;/code&gt; view.&lt;br&gt;
With the code to view the messages in place, restart your Rails server and visit &lt;code&gt;http://localhost:3000/secret_messages&lt;/code&gt; in your browser. You will see a page with message titles like the one below:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FZbBDmiA.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%2Fi.imgur.com%2FZbBDmiA.png" alt="Messages index page"&gt;&lt;/a&gt;&lt;br&gt;
Clicking on any of the message titles will open up a page like this:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FpdkW2Fm.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%2Fi.imgur.com%2FpdkW2Fm.png" alt="Messages show page"&gt;&lt;/a&gt;&lt;br&gt;
In this section, you created a model to store messages, added a few messages to the database and displayed them in the app. In the next section, you will hide these messages behind an authentication wall.&lt;/p&gt;
&lt;h2&gt;
  
  
  Integrate Authentication to the Application with Devise
&lt;/h2&gt;

&lt;p&gt;Devise is an authentication solution for Rails. It offers a suite of authentication features that can be easily plugged into any Rails application. In this section, you will add authentication to the demo application with Devise.&lt;br&gt;
To set up Devise, start by adding it to the Gemfile. To do this, open the &lt;code&gt;Gemfile&lt;/code&gt; located in the application's root folder and add the following line of code to the end of the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'devise'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, in your terminal window, run &lt;code&gt;bundle install&lt;/code&gt; to install the gem. Devise provides an install generator, which configures it for use in a Rails application when you run it. In your terminal window, run the command below to configure Devise:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails generate devise:install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running the command above creates the following files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;devise.rb&lt;/code&gt; file located at &lt;code&gt;config/initializers/devise.rb&lt;/code&gt; with Devise configuration options.&lt;/li&gt;
&lt;li&gt;An English translation file named &lt;code&gt;devise.yml&lt;/code&gt;. It is located at &lt;code&gt;config/locales/devise.en.yml&lt;/code&gt;.
The command also returns an output with some compulsory and optional instructions. One of the compulsory instructions is to set a default URL option for Devise mailer. To do this for the development environment, in your text editor, open the &lt;code&gt;development.rb&lt;/code&gt; file located at &lt;code&gt;config/environments/development.rb&lt;/code&gt; and add the following code to the file:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;action_mailer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;default_url_options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;host: &lt;/span&gt;&lt;span class="s1"&gt;'localhost'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;port: &lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Devise uses the default URL options set in the code above to generate URLs in emails. Lastly, add the markup below to the application.html.erb file immediately after the opening &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"notice"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= notice %&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p class=&lt;/span&gt;&lt;span class="s2"&gt;"alert"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= alert %&amp;gt;&amp;lt;/p&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above renders error and success messages generated by Devise.&lt;/p&gt;

&lt;p&gt;Messages in the demo application should be visible to only authenticated users. Devise offers a model generator command that creates a Rails model that can be used for authentication. Next, you will create a &lt;code&gt;User&lt;/code&gt; model using Devise's model generator command. In your terminal window, run the command below to create a user model with Devise:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails generate devise User
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command above generates two files; a user model located at &lt;code&gt;app/models/user.rb&lt;/code&gt; and a migration file for creating the users table. The command also updates the route files with user routes for Devise. The user model located at &lt;code&gt;app/models/user.rb&lt;/code&gt; contains five Devise modules. They include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;database_authenticatable&lt;/code&gt; for hashing and storing passwords.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;registerable&lt;/code&gt; for handling the creation, editing and deletion of user accounts.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;recoverable&lt;/code&gt; for enabling password reset functionality.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rememberable&lt;/code&gt; for generating and clearing tokens for remembering users.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;validatable&lt;/code&gt; for enabling email and password validation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The authentication functionalities provided by the five Devise modules in the user model are already implemented and are functional as soon as the users table migration is run. To run the migration, run &lt;code&gt;rails db:migrate&lt;/code&gt; in your terminal window. You should get the following output if successful:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;== 20220120200559 DeviseCreateUsers: migrating ================================
-- create_table(:users)
    -&amp;gt; 0.0119s
-- add_index(:users, :email, {:unique=&amp;gt;true})
    -&amp;gt; 0.0027s
-- add_index(:users, :reset_password_token, {:unique=&amp;gt;true})
    -&amp;gt; 0.0020s
== 20220120200559 DeviseCreateUsers: migrated (0.0168s) =======================
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Devise offers authentication helper functions for Rails controllers and views. They include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;authenticate_user!&lt;/code&gt;: This helper function denies controller access to unauthenticated users.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;user_signed_in?&lt;/code&gt;: This returns a boolean that indicates whether or not a user is signed in.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;current_user&lt;/code&gt;: This helper returns the currently signed-in user's object.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;user_session&lt;/code&gt;: This helper returns information about the current user session.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Take note that the Devise helper function names depend on whatever your Devise model is named. This means if your Devise model is &lt;code&gt;Admin&lt;/code&gt; instead of &lt;code&gt;User&lt;/code&gt;, the helper function names will be &lt;code&gt;authenticate_admin!&lt;/code&gt;, &lt;code&gt;admin_signed_in?&lt;/code&gt;, &lt;code&gt;current_admin&lt;/code&gt; and &lt;code&gt;admin_session&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With the users migration now run, you'll restrict access to the &lt;code&gt;index&lt;/code&gt; and &lt;code&gt;show&lt;/code&gt; actions of the &lt;code&gt;SecretMessages&lt;/code&gt; controller using the &lt;code&gt;authenticate_user!&lt;/code&gt; helper. Open the &lt;code&gt;SecretMessages&lt;/code&gt; controller and add the following line of code to it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SecretMessagesController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="n"&gt;before_action&lt;/span&gt; &lt;span class="ss"&gt;:authenticate_user!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;except: &lt;/span&gt;&lt;span class="sx"&gt;%i[home]&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, the &lt;code&gt;authenticate_user!&lt;/code&gt; helper is used in a &lt;code&gt;before_action&lt;/code&gt; in the &lt;code&gt;SecretMessages&lt;/code&gt; controller. It ensures that unauthenticated users only have access to the home action in the controller. To test this out, restart your Rails server and try viewing all the messages in the app by visiting &lt;code&gt;http://localhost:3000/secret_messages&lt;/code&gt; in your browser. You will be redirected to a login page like the one below with a message indicating that you need to be authenticated to continue:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FqWFiebm.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%2Fi.imgur.com%2FqWFiebm.png" alt="Devise login page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The login page is created by Devise and contains links to other authentication pages like sign up and password reset. To view the messages, go ahead and create an account and log in.&lt;/p&gt;

&lt;p&gt;Next, you'll add a login/logout link to the app based on whether or not a user is logged in. In your editor, open the &lt;code&gt;application.html.erb&lt;/code&gt; file located at &lt;code&gt;app/views/layouts/application.html.erb&lt;/code&gt; and add the following code after the opening &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;% if &lt;/span&gt;&lt;span class="n"&gt;user_signed_in?&lt;/span&gt; &lt;span class="sx"&gt;%&amp;gt;
    &amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class="no"&gt;Welcome&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= current_user.email %&amp;gt;&amp;lt;/p&amp;gt;
    &amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;link_to&lt;/span&gt; &lt;span class="s1"&gt;'Logout'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;destroy_user_session_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;method: :delete&lt;/span&gt; &lt;span class="o"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;% else &lt;/span&gt;&lt;span class="o"&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= link_to 'Login', new_user_session_path %&amp;gt;
    &amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;link_to&lt;/span&gt; &lt;span class="s1"&gt;'Sign up'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_user_registration_path&lt;/span&gt; &lt;span class="sx"&gt;%&amp;gt;
  &amp;lt;% end %&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/body&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, a conditional statement is used to display either a logout link or a login and sign up link based on the value of the &lt;code&gt;user_signed_in?&lt;/code&gt; helper. If a user is signed in, the &lt;code&gt;current_user&lt;/code&gt; helper is used to display a  welcome message that includes the user's email address.&lt;/p&gt;

&lt;p&gt;Reloading the application in your browser should show the login and signup or logout text based on your authentication state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying the Rails application to Koyeb
&lt;/h2&gt;

&lt;p&gt;In this section, you will deploy your Rails application to Koyeb. Koyeb is a serverless platform for deploying applications across clouds and edges. It offers application deployment using pre-built Docker containers or native code using git. In this guide, we are going to deploy our app using the git-driven deployment method.&lt;/p&gt;

&lt;p&gt;Start by creating a repository for your Rails application on GitHub. Next, run the commands below in your terminal window to push the application code to your GitHub repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nt"&gt;--all&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Complete application with authentication."&lt;/span&gt;
git remote add origin git@github.com:&amp;lt;YOUR_GITHUB_USERNAME&amp;gt;/&amp;lt;YOUR_REPOSITORY_NAME&amp;gt;.git
git branch &lt;span class="nt"&gt;-M&lt;/span&gt; main
git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running the commands above moves the application code from your local development to GitHub. Next, head over to ElephantSQL to create a Postgres database using the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;While logged in and on the instances page, click the "Create a new instance" button.&lt;/li&gt;
&lt;li&gt;Enter a name and click the "Select region button".&lt;/li&gt;
&lt;li&gt;On the next page, click the "review" button and then click the "Create instance button on the next page".&lt;/li&gt;
&lt;li&gt;Select your newly created instance and copy your database URL. Store it in a safe place for use later.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fr41GNCe.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%2Fi.imgur.com%2Fr41GNCe.png" alt="ElephantSQL Postgres instance showing database URL"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On your Koyeb control panel, go to the &lt;code&gt;Secrets&lt;/code&gt; tab and create a new secret. Enter &lt;code&gt;DATABASE_URL&lt;/code&gt; as the secret name and paste your database URL as the value. Next, go to the &lt;code&gt;Overview&lt;/code&gt; tab and click the &lt;strong&gt;Create App&lt;/strong&gt; button to go to the App creation page.&lt;/p&gt;

&lt;p&gt;On the App creation page:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select GitHub as your deployment method.&lt;/li&gt;
&lt;li&gt;In the repositories list, select your application code repository.&lt;/li&gt;
&lt;li&gt;Specify the branch you want to deploy. In this case, &lt;code&gt;main&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set the run command to let Koyeb know how to deploy your app: &lt;code&gt;rails db:migrate &amp;amp;&amp;amp; rails db:seed &amp;amp;&amp;amp; rails server&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;In the environment variables section, click the add environment variable button.&lt;/li&gt;
&lt;li&gt;Select the &lt;code&gt;Secret&lt;/code&gt; type, enter &lt;code&gt;DATABASE_URL&lt;/code&gt; as the key and select the &lt;code&gt;DATABASE_URL&lt;/code&gt; secret created previously as the value.&lt;/li&gt;
&lt;li&gt;Give your app a name. e.g. &lt;code&gt;rails-auth&lt;/code&gt; and click the &lt;strong&gt;Create App&lt;/strong&gt; button.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FUiYX6PH.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%2Fi.imgur.com%2FUiYX6PH.png" alt="Deploying app on Koyeb"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking the &lt;strong&gt;Create App&lt;/strong&gt; button builds and deploys your app and redirects you to a deployment page where you can monitor the deployment. Once the deployment is complete and all necessary health checks have been passed, you can click your public URL to view your application.&lt;/p&gt;

&lt;p&gt;Your application now benefits from built-in continuous deployment, global load balancing, end-to-end encryption, its own private network with service mesh and discovery, autohealing, and more.&lt;/p&gt;

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

&lt;p&gt;In this tutorial, you created a Rails application for displaying messages. You also implemented authentication in the application using the Devise gem. Devise offers even more authentication features than what was covered in this tutorial. You can check out their &lt;a href="https://github.com/heartcombo/devise/wiki" rel="noopener noreferrer"&gt;wiki&lt;/a&gt; to learn more about Devise.&lt;/p&gt;

&lt;p&gt;Since we deployed the application on Koyeb using git-driven deployment, each change you push to your repository will&lt;br&gt;
automatically trigger a new build and deployment on the Koyeb Serverless Platform. Your changes will go live as soon as the deployment&lt;br&gt;
passes all necessary health checks. In case of a failure during deployment, Koyeb maintains the latest working deployment in production&lt;br&gt;
to ensure your application is always up and running.&lt;/p&gt;

&lt;p&gt;If you would like to look at the code for the demo application, you can find it &lt;a href="https://github.com/koyeb/example-rails-devise" rel="noopener noreferrer"&gt;here&lt;/a&gt;. If you have any questions or suggestions to improve this guide, feel free to reach out to us on &lt;a href="https://slack.koyeb.com/" rel="noopener noreferrer"&gt;Slack&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Deploy a Web Scraper using Puppeteer, Node.js and Docker</title>
      <dc:creator>Edouard Bonlieu</dc:creator>
      <pubDate>Mon, 24 Jan 2022 10:37:24 +0000</pubDate>
      <link>https://forem.com/koyeb/deploy-a-web-scraper-using-puppeteer-nodejs-and-docker-3alm</link>
      <guid>https://forem.com/koyeb/deploy-a-web-scraper-using-puppeteer-nodejs-and-docker-3alm</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Web scraping is the process of extracting meaningful data from websites. Although it can be done manually, nowadays there are several developer-friendly tools that can automate the process for you.&lt;/p&gt;

&lt;p&gt;In this tutorial we are going to create a web scraper using Puppeteer, a Node library developed by Google to perform several automated tasks using the Chromium engine.&lt;br&gt;
Web scraping is just one of the several applications that makes Puppeteer shine. In fact, according to the official &lt;a href="https://github.com/puppeteer/puppeteer"&gt;documentation&lt;/a&gt; on Github Puppeteer can be used to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generate screenshots and PDFs of web pages.&lt;/li&gt;
&lt;li&gt;Crawl a Single-Page Application and generate pre-rendered content.&lt;/li&gt;
&lt;li&gt;Automate form submission, UI testing, keyboard input, and interface interactions.&lt;/li&gt;
&lt;li&gt;Create an up-to-date, automated testing environment.&lt;/li&gt;
&lt;li&gt;Capture a timeline trace of your site to help diagnose performance issues.&lt;/li&gt;
&lt;li&gt;Test Chrome Extensions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this guide, we will first create scripts to showcase Puppeteer capabilities, then we will create an API to scrape pages via a simple HTTP API call using Express.js and deploy our application on Koyeb.&lt;/p&gt;
&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;To successfully follow and complete this guide, you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Basic knowledge of JavaScript.&lt;/li&gt;
&lt;li&gt;A local development environment with Node.js installed&lt;/li&gt;
&lt;li&gt;Basic knowledge of Express.js&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.docker.com/get-docker/"&gt;Docker&lt;/a&gt; installed on your machine&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://app.koyeb.com"&gt;Koyeb account&lt;/a&gt; to deploy and run the application&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://github.com"&gt;GitHub account&lt;/a&gt; to version and deploy your application code on Koyeb&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This tutorial does not require any prior knowledge of Puppeteer as we will go through every step of setting up and running a web scraper.&lt;br&gt;
However, make sure your version of Node.js is at least 10.18.1 as we are using Puppeteer v3+.&lt;/p&gt;

&lt;p&gt;For more information take a look at the official &lt;a href="https://github.com/puppeteer/puppeteer#usage"&gt;readme&lt;/a&gt; on the Puppeteer Github repository.&lt;/p&gt;
&lt;h2&gt;
  
  
  Steps
&lt;/h2&gt;

&lt;p&gt;To deploy a web scraper using Puppeteer, Express.js, and Docker on Koyeb, you need to follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Initializing the project&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Your first Puppeteer application&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Puppeteer in action&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scrap pages via a simple API call using Express&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deploy the app on Koyeb&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Initializing the project
&lt;/h2&gt;

&lt;p&gt;Get started by creating a new directory that will hold the application code.&lt;br&gt;
To a location of your choice, create and navigate to a new directory by executing the following commands:&lt;br&gt;
&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;mkdir &lt;/span&gt;puppeteer-on-koyeb
&lt;span class="nb"&gt;cd &lt;/span&gt;puppeteer-on-koyeb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the freshly created folder, we will create a Node.js application skeleton containing the Express.js dependencies that we will need to build our scraping API. In your terminal run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx express-generator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will be prompted with a set of questions to populate the initial &lt;code&gt;package.json&lt;/code&gt; file including the project name, version, and description.&lt;br&gt;
Once the command has been completed, your &lt;code&gt;package.json&lt;/code&gt; content should be similar to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"puppeteer-on-koyeb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Deploy a Web scraper using Puppeteer, ExpressJS and Docker on Koyeb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"private"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node ./bin/www"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"cookie-parser"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"~1.4.4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"debug"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"~2.6.9"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"express"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"~4.16.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"http-errors"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"~1.6.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"jade"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"~1.11.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"morgan"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"~1.9.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Samuel Zaza"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"license"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ISC"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creating the skeleton of the application is going to come handy to organize our files, especially later on when creating we will create our API endpoints.&lt;/p&gt;

&lt;p&gt;Next, add Pupetteer, the library we will use to perform the scraping as a project dependency by running:&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;span class="nt"&gt;--save&lt;/span&gt; puppeteer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Last, install and configure nodemon. While optional in this guide, nodemon will allow us to automatically restart our server when file changes are detected. This is a great tool to improve the development experience when developing locally. To install nodemon in your terminal, run:&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;nodemon &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, in your &lt;code&gt;package.json&lt;/code&gt; add the following section so we will be able to launch the application in development running &lt;code&gt;npm dev&lt;/code&gt; using nodemon and in production running &lt;code&gt;npm start&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;{
  "name": "puppeteer-on-koyeb",
  "version": "1.0.0",
  "description": "Deploy a Web scraper using Puppeteer, ExpressJS and Docker on Koyeb",
  "private": true,
+  "scripts": {
+    "start": "node ./bin/www",
+    "dev": "nodemon ./bin/www"
+  },
  "dependencies": {
    "cookie-parser": "~1.4.4",
    "debug": "~2.6.9",
    "express": "~4.16.1",
    "http-errors": "~1.6.3",
    "jade": "~1.11.0",
    "morgan": "~1.9.1",
  },
  "author": "Samuel Zaza",
  "license": "ISC"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Execute the following command to launch the application and ensure everything is working as expected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm start
&lt;span class="c"&gt;# or npm run dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open your browser at &lt;code&gt;http://localhost:3000&lt;/code&gt; and you should see the Express welcome message.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your first Puppeteer application
&lt;/h2&gt;

&lt;p&gt;Before diving into more advanced Puppeteer web scraping capabilities, we will create a minimalist application to take a webpage screenshot and save the result in our current directory.&lt;br&gt;
As mentioned previously, Puppeteer provides several features to control Chrome/Chromium and the ability to take screenshots of a webpage comes very handy.&lt;/p&gt;

&lt;p&gt;For this example, we will not dig into each parameter of the &lt;code&gt;screenshot&lt;/code&gt; method as we mainly want to confirm our installation works properly.&lt;/p&gt;

&lt;p&gt;Create a new JavaScript file named &lt;code&gt;screenshot.js&lt;/code&gt; in your project directory &lt;code&gt;puppeteer-on-koyeb&lt;/code&gt; by running:&lt;br&gt;
&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;touch &lt;/span&gt;screenshot.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To take a screenshot of a webpage, our application will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use Puppeteer, and create a new instance of &lt;code&gt;Browser&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Open a webpage&lt;/li&gt;
&lt;li&gt;Take a screenshot&lt;/li&gt;
&lt;li&gt;Close the page and browser&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Add the code below to the &lt;code&gt;screenshot.js&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;puppeteer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://koyeb.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;screenshot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Opening the browser...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newPage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Go to &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Taking a screenshot...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;screenshot&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./screenshot.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;fullPage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Closing the browser...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Job done!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;screenshot&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we are taking a screenshot of the &lt;a href="https://koyeb.com"&gt;Koyeb&lt;/a&gt; homepage and saving the result as a &lt;code&gt;png&lt;/code&gt; file in the root folder of the project.&lt;/p&gt;

&lt;p&gt;You can now run the application by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;node screenshot.js
Opening the browser...
Taking a screenshot...
Closing the browser...
Job &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the execution is completed, a screenshot is saved in the root folder of the application.&lt;br&gt;
You created your first automation using Puppeteer!&lt;/p&gt;
&lt;h2&gt;
  
  
  Puppeteer in action
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Simple Scraper
&lt;/h3&gt;

&lt;p&gt;In this section, we will create a more advanced scenario to scrap and retrieve information from a website's page.&lt;br&gt;
For this example, we will use the &lt;a href="https://stackoverflow.com/questions"&gt;Stack Overflow&lt;/a&gt; questions pages and instruct Puppeteer to extract each question and excerpt present on the webpage HTML.&lt;/p&gt;

&lt;p&gt;Before jumping into the code, in your browser, open the devTools to inspect the webpage source code. You should see a similar block for each question in the HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"question-summary"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"question-summary-11227809"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- we can ignore the stats wrapper --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"statscontainer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"summary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/questions/11227809/why-is-processing-a-sorted-array-faster-than-processing-an-unsorted-array"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"question-hyperlink"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Why is processing a sorted array faster than processing an unsorted array?&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"excerpt"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            Here is a piece of C++ code that shows some very peculiar behavior. For some strange reason, sorting the data (before the timed region) miraculously makes the loop almost six times faster. #include &lt;span class="err"&gt;&amp;amp;&lt;/span&gt;...
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- unnecessary wrapper --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"d-flex ai-start fw-wrap"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will use the JavaScript methods &lt;code&gt;querySelectorAll&lt;/code&gt; and &lt;code&gt;querySelector&lt;/code&gt; to extract both question and excerpt, and return as result an array of objects.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;querySelectorAll&lt;/code&gt;: Will be used to  to collect each question element. &lt;code&gt;document.querySelectorAll('.question-summary')&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;querySelector&lt;/code&gt; Will be used to extract the question title by calling &lt;code&gt;querySelector('.question-hyperlink').innerText&lt;/code&gt; and the excerpt using &lt;code&gt;querySelector('.excerpt').innerText&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Back to your terminal, and create a new folder &lt;code&gt;lib&lt;/code&gt; containing a file called &lt;code&gt;scraper.js&lt;/code&gt;:&lt;br&gt;
&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;mkdir &lt;/span&gt;lib
&lt;span class="nb"&gt;touch &lt;/span&gt;lib/scraper.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the file &lt;code&gt;scraper.js&lt;/code&gt; add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;puppeteer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://stackoverflow.com/questions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;singlePageScraper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Opening the browser...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newPage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Navigating to &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;...`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;waitUntil&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;load&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Collecting the questions...`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;questions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.question-summary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;question&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.question-hyperlink&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;excerpt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.excerpt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Closing the browser...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Job done!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;questions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;questions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;singlePageScraper&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;Although it looks way more complex than the &lt;code&gt;screenshot.js&lt;/code&gt; script, it is actually performing the same actions except for the scraping one. Let's list them:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create an instance of Browser and open a page.&lt;/li&gt;
&lt;li&gt;Go to the URL (and wait for the website to load).&lt;/li&gt;
&lt;li&gt;Extract the information from the website and collect the questions into an array of objects.&lt;/li&gt;
&lt;li&gt;Close the browser and return the tools list as question-excerpt pair.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You might feel confused about the scraping syntax of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;questions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.question-summary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;question&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.question-hyperlink&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;excerpt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.excerpt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We first call &lt;code&gt;page.evaluate&lt;/code&gt; to interact with the page DOM and then we start extracting the question and the excerpt.&lt;br&gt;
Moreover, in the code above, we transformed the result from &lt;code&gt;document.querySelectorAll&lt;/code&gt; into a JavaScript array to be able to call &lt;code&gt;map&lt;/code&gt; on it and return the pair &lt;code&gt;{ question, excerpt }&lt;/code&gt; for each converter tool.&lt;/p&gt;

&lt;p&gt;To run the function, we can import it into a new file &lt;code&gt;singlePageScraper.js&lt;/code&gt;, and run it. Create the file in the root directory of your application:&lt;br&gt;
&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;touch &lt;/span&gt;singlePageScraper.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, copy the code below that import the &lt;code&gt;singlePageScraper&lt;/code&gt; function and call it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;singlePageScraper&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./lib/scaper&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;singlePageScraper&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 script by executing the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node singlePageScraper.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following output appears in your terminal showing the questions and excerpts retrieved from the StackOverflow questions page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Opening the browser...
Navigating to https://stackoverflow.com/questions...
Collecting the tools...
Closing the browser...
Job done!
[
  {
    question: 'Google Places Autocomplete for WPF Application',
    excerpt: 'I have a windows desktop application developed in WPF( .Net Framework.)I want to implement Autocomplete textbox using google places api autocomplete, I found few reference which used Web browser to do ...'
  },
  {
    question: 'Change the field of a struct in Go',
    excerpt: "I'm trying to change a parameter of n1's left variable, but n1.left is not available, neither is n1.value or n1.right. What's wrong with this declarations? // lib/tree.go package lib type TreeNode ..."
  },
  ...
 ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Multi page scraper
&lt;/h3&gt;

&lt;p&gt;In the previous example, we learned how to scrap and retrieve information from a single page.&lt;br&gt;
We can now go even further and instruct Puppeteer to explore and extract information from multiple pages.&lt;/p&gt;

&lt;p&gt;For this scenario, we will scrap and extract questions and excerpts from a pre-defined number of StackOverflow questions pages.&lt;/p&gt;

&lt;p&gt;Our script will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Receive the number of pages to scrap as a parameter.&lt;/li&gt;
&lt;li&gt;Extract questions and excerpts from a page.&lt;/li&gt;
&lt;li&gt;Programmatically click on the "next page" element.&lt;/li&gt;
&lt;li&gt;Repeats &lt;em&gt;point 2&lt;/em&gt; and &lt;em&gt;point 3&lt;/em&gt; until the number of pages to scrap is reached.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Based on the previous function &lt;code&gt;singlePageScraper&lt;/code&gt; we created in &lt;code&gt;lib/scraper.js&lt;/code&gt; we will create a new function taking as an argument the number of pages to scrape.&lt;/p&gt;

&lt;p&gt;Let's take a look at the HTML source code of the page to select the correct button element we will emulate the click to go to the next page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"s-pagination site1 themed pager float-left"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"s-pagination--item is-selected"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;1&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"s-pagination--item js-pagination-item"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/questions?tab=votes&amp;amp;amp;page=2"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"Go to page 2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;2&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
...
&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"s-pagination--item js-pagination-item"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/questions?tab=votes&amp;amp;amp;page=1470621"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"Go to page 1470621"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;1470621&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- This is the button we need to select and click on --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"s-pagination--item js-pagination-item"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/questions?tab=votes&amp;amp;amp;page=2"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"next"&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"Go to page 2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; Next&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Puppeteer class &lt;code&gt;Page&lt;/code&gt; provides a handy method &lt;code&gt;click&lt;/code&gt; that accepts CSS selectors to simulate a click on an element. In our case, to go to the next page, we decide to use the &lt;code&gt;.pager &amp;gt; a:last-child&lt;/code&gt; selector.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;lib/scraper.js&lt;/code&gt; file, create a new function called &lt;code&gt;multiPageScraper&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;const puppeteer = require('puppeteer');

const URL = 'https://stackoverflow.com/questions';

const singlePageScraper = async () =&amp;gt; {
  console.log('Opening the browser...');
  const browser = await puppeteer.launch();
  const page = await browser.newPage();

  console.log(`Navigating to ${URL}...`);
  await page.goto(URL, { waitUntil: 'load' });

  console.log(`Collecting the questions...`);
  const questions = await page.evaluate(() =&amp;gt; {
    return [...document.querySelectorAll('.question-summary')]
      .map((question) =&amp;gt; {
        return {
          question: question.querySelector('.question-hyperlink').innerText,
          excerpt: question.querySelector('.excerpt').innerText,
        };
      });
  });

  console.log('Closing the browser...');

  await page.close();
  await browser.close();

  console.log('Job done!');
  console.log(questions);
  return questions;
};

+const multiPageScraper = async (pages = 1) =&amp;gt; {
+  console.log('Opening the browser...');
+  const browser = await puppeteer.launch();
+  const page = await browser.newPage();
+
+  console.log(`Navigating to ${URL}...`);
+  await page.goto(URL, { waitUntil: 'load' });
+
+  const totalPages = pages;
+  let questions = [];
+
+  for (let initialPage = 1; initialPage &amp;lt;= totalPages; initialPage++) {
+    console.log(`Collecting the questions of page ${initialPage}...`);
+    let pageQuestions = await page.evaluate(() =&amp;gt; {
+      return [...document.querySelectorAll('.question-summary')]
+        .map((question) =&amp;gt; {
+          return {
+            question: question.querySelector('.question-hyperlink').innerText,
+            excerpt: question.querySelector('.excerpt').innerText,
+          }
+        });
+    });
+
+    questions = questions.concat(pageQuestions);
+    console.log(questions);
+  // Go to next page until the total number of pages to scrap is reached
+    if (initialPage &amp;lt; totalPages) {
+      await Promise.all([
+        await page.click('.pager &amp;gt; a:last-child'),
+        await page.waitForSelector('.question-summary'),
+      ])
+    }
+  }
+
+  console.log('Closing the browser...');
+
+  await page.close();
+  await browser.close();
+
+  console.log('Job done!');
+  return questions;
+};

module.exports = {
  singlePageScraper,
+  multiPageScraper,
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we are collecting questions and related excerpts for multiple pages, we use a for loop to retrieve the list of questions for each page.&lt;br&gt;
Each &lt;code&gt;questions&lt;/code&gt; retrieved for a page is then concatenated in an array &lt;code&gt;questions&lt;/code&gt; which is returned once the fetching is completed.&lt;/p&gt;

&lt;p&gt;As we did for the single page scraper example, create a new file &lt;code&gt;multiPageScraper.js&lt;/code&gt; in the root directory to import and call the &lt;code&gt;multiPageScraper&lt;/code&gt; function:&lt;br&gt;
&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;touch &lt;/span&gt;multiPageScraper.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, add 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;const { multiPageScraper } = require('./lib/scaper');

multiPageScraper(2);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the purpose of the script, we are hardcoding the number of pages to fetch to &lt;code&gt;2&lt;/code&gt;. We will make this dynamic when we will build the API.&lt;/p&gt;

&lt;p&gt;In your terminal execute the following command to run the script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node multiPageScraper.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following output appears in your terminal showing the questions and excerpts retrieved for each page scraped:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Opening the browser...
Navigating to https://stackoverflow.com/questions...
Collecting the questions of page 1...
&lt;span class="o"&gt;[&lt;/span&gt;
  &lt;span class="o"&gt;{&lt;/span&gt;
    question: &lt;span class="s1"&gt;'Blazor MAIUI know platform'&lt;/span&gt;,
    excerpt: &lt;span class="s1"&gt;'there is some way to known the platform where is running my Blazor maui app?. Select not work property in "Windows" (you need use size=2 or the list not show), i would read the platform in ...'&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;,
  ...
&lt;span class="o"&gt;]&lt;/span&gt;
Collecting the questions of page 2...
&lt;span class="o"&gt;[&lt;/span&gt;
  &lt;span class="o"&gt;{&lt;/span&gt;
    question: &lt;span class="s1"&gt;'Blazor MAIUI know platform'&lt;/span&gt;,
    excerpt: &lt;span class="s1"&gt;'there is some way to known the platform where is running my Blazor maui app?. Select not work property in "Windows" (you need use size=2 or the list not show), i would read the platform in ...'&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;,
  ...
&lt;span class="o"&gt;]&lt;/span&gt;
Closing the browser...
Job &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the next section, we will write a simple API server containing one endpoint to scrap a user-defined number of pages and return the list of questions and excerpts scraped.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scrap pages via a simple API call using Express
&lt;/h2&gt;

&lt;p&gt;We are going to create a simple Express.js API server having an endpoint &lt;code&gt;/questions&lt;/code&gt; that accepts a query parameter &lt;code&gt;pages&lt;/code&gt; and returns the list of questions and excerpts from page 1 to the page sent as parameter.&lt;/p&gt;

&lt;p&gt;For instance, to retrieve the first three pages of questions and their excerpts from Stack Overflow, we will call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;http://localhost:3000/questions?pages&lt;span class="o"&gt;=&lt;/span&gt;3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To create the &lt;code&gt;questions&lt;/code&gt; endpoit, go to the &lt;code&gt;routes&lt;/code&gt; directory and create new file &lt;code&gt;question.js&lt;/code&gt;:&lt;br&gt;
&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;routes
&lt;span class="nb"&gt;touch &lt;/span&gt;questions.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, add the code below to the &lt;code&gt;question.js&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scraper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../lib/scaper&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 1. Get the parameter "pages"&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;pages&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// 2. Call the scraper function&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;questions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;scraper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;multiPageScraper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// 3. Return the array of questions to the client&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Questions correctly retrieved&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;questions&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What the code does is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get the query parameter &lt;code&gt;pages&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Call the newly created function &lt;code&gt;multiPageScraper&lt;/code&gt; and pass the &lt;code&gt;pages&lt;/code&gt; value.&lt;/li&gt;
&lt;li&gt;Return the array of questions back to the client.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We now need to define the &lt;code&gt;questions&lt;/code&gt; route in the Express router. To do so, open &lt;code&gt;app.js&lt;/code&gt; and add 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;const createError = require('http-errors');
const express = require('express');
const path = require('path');
const cookieParser = require('cookie-parser');
const logger = require('morgan');

const indexRouter = require('./routes/index');
+const questionsRouter = require('./routes/questions');

const app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);
+app.use('/questions', questionsRouter);

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

&lt;/div&gt;



&lt;p&gt;Note that thanks to the Express generator we used to initialize our project, we do not have to setup our server from scratch, a few middlewrides are already setup for us.&lt;br&gt;
Run the server again and try the to call the &lt;code&gt;/questions&lt;/code&gt; API endpoint using either the browser or cURL.&lt;/p&gt;

&lt;p&gt;Here is the ouput you should get running it from your terminal using cURL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;curl http://localhost:3000/questions&lt;span class="se"&gt;\?&lt;/span&gt;pages&lt;span class="se"&gt;\=&lt;/span&gt;2 | jq &lt;span class="s1"&gt;'.'&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"statusCode"&lt;/span&gt;: 200,
  &lt;span class="s2"&gt;"message"&lt;/span&gt;: &lt;span class="s2"&gt;"Questions correctly retrieved"&lt;/span&gt;,
  &lt;span class="s2"&gt;"data"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"questions"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
      &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"question"&lt;/span&gt;: &lt;span class="s2"&gt;"Is there a way to return float or integer from a conditional True/False"&lt;/span&gt;,
        &lt;span class="s2"&gt;"excerpt"&lt;/span&gt;: &lt;span class="s2"&gt;"n_level = range(1, steps + 2) steps is user input,using multi-index dataframe for i in n_level: if df['Crest'] &amp;gt;= df[f'L{i}K']: df['Marker'] = i elif df['Trough'] &amp;amp;..."&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;,
      &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"question"&lt;/span&gt;: &lt;span class="s2"&gt;"Signin With Popup - Firebase and Custom Provider"&lt;/span&gt;,
        &lt;span class="s2"&gt;"excerpt"&lt;/span&gt;: &lt;span class="s2"&gt;"I am working on an application that authenticates users with a Spotify account. I have a working login page, however, I would prefer users to not be sent back to the home page when they sign in. I ..."&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;,
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we are done! We now have a web scraper that with minimal changes can scrap any websites.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy the app on Koyeb
&lt;/h2&gt;

&lt;p&gt;Now that we have a working server, we can demonstrate how to deploy the application on Koyeb.&lt;br&gt;
Koyeb simple user interface gives you two choices to deploy our app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deploy native code using git-driven deployment&lt;/li&gt;
&lt;li&gt;Deploy pre-built Docker containers from any public or private registries.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since we are using Puppeteer, we need some extra system packages installed so we will deploy on Koyeb using Docker.&lt;/p&gt;

&lt;p&gt;In this guide, I won't go through the steps of creating a Dockerfile and pushing it to the Docker registry but if you are interested in learning more, I suggest you start with the &lt;a href="https://docs.docker.com/get-started/"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Before we start working with Docker, we have to perform a change into the &lt;code&gt;/lib/scaper.js&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;const puppeteer = require('puppeteer');

const URL = 'https://stackoverflow.com/questions';

const singlePageScraper = async () =&amp;gt; {
  console.log('Opening the browser...');
  const browser = await puppeteer.launch();
  const page = await browser.newPage();

  console.log(`Navigating to ${URL}...`);
  await page.goto(URL, { waitUntil: 'load' });

  console.log(`Collecting the questions...`);
  const questions = await page.evaluate(() =&amp;gt; {
    return [...document.querySelectorAll('.question-summary')]
      .map((question) =&amp;gt; {
        return {
          question: question.querySelector('.question-hyperlink').innerText,
          excerpt: question.querySelector('.excerpt').innerText,
        };
      });
  });

  console.log('Closing the browser...');

  await page.close();
  await browser.close();

  console.log('Job done!');
  console.log(questions);
  return questions;
};

const multiPageScraper = async (pages = 1) =&amp;gt; {
  console.log('Opening the browser...');
-  const browser = await puppeteer.launch();
+  const browser = await puppeteer.launch({
+      headless: true,
+      executablePath: '/usr/bin/chromium-browser',
+      args: [
+        '--no-sandbox',
+        '--disable-gpu',
+      ]
+  });
  const page = await browser.newPage();

  console.log(`Navigating to ${URL}...`);
  await page.goto(URL, { waitUntil: 'load' });

  const totalPages = pages;
  let questions = [];

  for (let initialPage = 1; initialPage &amp;lt;= totalPages; initialPage++) {
    console.log(`Collecting the questions of page ${initialPage}...`);
    let pageQuestions = await page.evaluate(() =&amp;gt; {
      return [...document.querySelectorAll('.question-summary')]
        .map((question) =&amp;gt; {
          return {
            question: question.querySelector('.question-hyperlink').innerText,
            excerpt: question.querySelector('.excerpt').innerText,
          }
        });
    });

    questions = questions.concat(pageQuestions);
    console.log(questions);
  // Go to next page until the total number of pages to scrap is reached
    if (initialPage &amp;lt; totalPages) {
      await Promise.all([
        await page.click('.pager &amp;gt; a:last-child'),
        await page.waitForSelector('.question-summary'),
      ])
    }
  }

  console.log('Closing the browser...');

  await page.close();
  await browser.close();

  console.log('Job done!');
  return questions;
};

module.exports = {
  singlePageScraper,
  multiPageScraper,
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These extra parameters are required to properly run Puppeteer inside a Docker container.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dockerize the application and push it to the Docker Hub
&lt;/h3&gt;

&lt;p&gt;Get started by creating a Dockerfile containing the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:lts-alpine&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;apk update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apk add &lt;span class="nt"&gt;--no-cache&lt;/span&gt; nmap &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nb"&gt;echo&lt;/span&gt; @edge http://nl.alpinelinux.org/alpine/edge/community &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; /etc/apk/repositories &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nb"&gt;echo&lt;/span&gt; @edge http://nl.alpinelinux.org/alpine/edge/main &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; /etc/apk/repositories &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    apk update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    apk add &lt;span class="nt"&gt;--no-cache&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;      chromium &lt;span class="se"&gt;\
&lt;/span&gt;      harfbuzz &lt;span class="se"&gt;\
&lt;/span&gt;      &lt;span class="s2"&gt;"freetype&amp;gt;2.8"&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;      ttf-freefont &lt;span class="se"&gt;\
&lt;/span&gt;      nss

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . /app&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 3000&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["npm", "start"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a fairly simple Dockerfile. We inherit from the Node alpine base image, install the dependencies required by Puppeteer, add our web scraper application code and indicate how to run it.&lt;/p&gt;

&lt;p&gt;We can now build the Docker image by running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; &amp;lt;YOUR_DOCKER_USERNAME&amp;gt;/puppeteer-on-koyeb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Take care to replace &lt;code&gt;&amp;lt;YOUR_DOCKER_USERNAME&amp;gt;&lt;/code&gt; with your Docker Hub username.&lt;/p&gt;

&lt;p&gt;Once the build succeeded, we can push our image to the Docker Hub running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker push &amp;lt;YOUR_DOCKER_USERNAME&amp;gt;/puppeteer-on-koyeb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deploy the app on Koyeb
&lt;/h3&gt;

&lt;p&gt;Let's login to the Koyeb &lt;a href="////app.koyeb.com"&gt;Control Panel&lt;/a&gt; and click on the &lt;strong&gt;Create App&lt;/strong&gt; button.&lt;br&gt;
You land on the App creation page.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In "Deployment method", select Docker&lt;/li&gt;
&lt;li&gt;Enter the Docker image you just pushed &lt;code&gt;&amp;lt;YOUR_DOCKER_USERNAME&amp;gt;/puppeteer-on-koyeb&lt;/code&gt; to the Docker Hub. We do not need to configure the extra args or command fields&lt;/li&gt;
&lt;li&gt;Pick the container size, server region, and number of instances you'd like to run your application&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;Ports&lt;/strong&gt; section, change the port value from &lt;code&gt;8080&lt;/code&gt; to &lt;code&gt;3000&lt;/code&gt;, this is used by Koyeb to determine if your service is healthy. The &lt;code&gt;3000&lt;/code&gt; port is the port our application listen to&lt;/li&gt;
&lt;li&gt;Give your Koyeb App a name.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once you click the &lt;strong&gt;Create App&lt;/strong&gt; button, you will automatically be redirected to the Koyeb App page where you can follow the progress of your application deployment. Once your app is deployed, click on the &lt;em&gt;Public URL&lt;/em&gt; ending with &lt;code&gt;koyeb.app&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then ensure everything is working as expected by retrieving the two first pages of questions from Stack Overflow running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl http://&amp;lt;KOYEB_APP_NAME&amp;gt;-&amp;lt;KOYEB_ORG_NAME&amp;gt;.koyeb.app/questions?pages=2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything is working fine, you should see the list of questions returned by the API.&lt;/p&gt;

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

&lt;p&gt;First of all, congratulations on reaching this point! It was a long journey but we now have all the basic knowledge to successfully create and deploy a web scraper.&lt;/p&gt;

&lt;p&gt;Starting from the beginning, we played with Puppeteer screenshot capabilities and slowly built up a fairly robust scraper that can automatically change the page to retrieve questions from StackOverflow.&lt;/p&gt;

&lt;p&gt;Successively, we moved from a simple script to a running Express API server which exposes a specific endpoint to call the script and scrap a dynamic number of pages based on the query parameter sent along with the API call.&lt;/p&gt;

&lt;p&gt;Finally, the cherry on the top is the deployment of our server with Koyeb:&lt;br&gt;
Thanks to the simplicity of its deployment using pre-build Docker images we can now perform our scraping in a production environment.&lt;/p&gt;

&lt;p&gt;If you have any questions or suggestions regarding this guide, feel free to reach out on &lt;a href="https://slack.koyeb.com"&gt;Slack&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>javascript</category>
      <category>node</category>
      <category>docker</category>
    </item>
    <item>
      <title>Deploy a Rest API using Koa, Prisma, and Aiven on Koyeb</title>
      <dc:creator>Edouard Bonlieu</dc:creator>
      <pubDate>Mon, 17 Jan 2022 14:50:30 +0000</pubDate>
      <link>https://forem.com/koyeb/deploy-a-rest-api-using-koa-prisma-and-aiven-on-koyeb-5d6j</link>
      <guid>https://forem.com/koyeb/deploy-a-rest-api-using-koa-prisma-and-aiven-on-koyeb-5d6j</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this tutorial, we will showcase how to build a Notes REST API using Koajs, Prisma, and Aiven on Koyeb. By running your application on Koyeb, you natively benefit from continuous deployment using git, autoscaling, autohealing, TLS encryption, a Global Edge Network CDN, and more.&lt;/p&gt;

&lt;p&gt;Koa is a minimalist, expressive and robust web framework for web applications and APIs. We will use Koa to build our application REST API.&lt;/p&gt;

&lt;p&gt;Aiven is a fully-managed, multi-cloud data platform allowing you to deploy a wide range way of open-source data services and databases such as MySQL, PostgreSQL, InfluxDB, Redis, and more. We will use Aiven to provision a MySQL database and use it to store our Notes information.&lt;/p&gt;

&lt;p&gt;Last, we will make use of Prisma, an ORM offering powerful primitive that will help us interact with the MySQL database from our application intuitively and safely.&lt;/p&gt;

&lt;p&gt;At the end of this guide, you will have a working Notes application deployed on Koyeb using git-driven deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;To successfully follow and complete this guide, you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A local development environment with Node.js installed&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://app.koyeb.com"&gt;Koyeb account&lt;/a&gt; to deploy and run the application&lt;/li&gt;
&lt;li&gt;An &lt;a href="https://aiven.io"&gt;Aiven account&lt;/a&gt; to run the MySQL database&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://github.com"&gt;GitHub account&lt;/a&gt; to version and deploy your application code on Koyeb&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;To deploy the Rest API using Koa, Prisma, and Aiven on Koyeb, you need to follow these three steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Deploy a MySQL database on Aiven&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Create the Notes REST API using Koa and Prisma&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deploy the Notes application to Koyeb&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Deploy a MySQL database on Aiven
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://aiven.io"&gt;Aiven&lt;/a&gt; is a fully-managed, multi-cloud data platform allowing you to deploy a wide range of open-source databases including MySQL, PostgreSQL, InfluxDB, Redis, and many more.&lt;br&gt;
In this guide, we will deploy a MySQL database on Aiven and use it as the data backend for our application.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Aiven provides a 1-month free trial with $300 credits to try out the platform.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;On the Aiven control panel, click the &lt;strong&gt;Create a new service&lt;/strong&gt; button on the top right corner.&lt;br&gt;
You land on the &lt;strong&gt;Create Service&lt;/strong&gt; page where you need to select the service type to deploy. Select the MySQL service.&lt;/p&gt;

&lt;p&gt;&lt;a href="//koyeb.com/static/images/tutorials/deploy-a-rest-api-using-koa-prisma-and-aiven/aiven-01.png" class="article-body-image-wrapper"&gt;&lt;img src="//koyeb.com/static/images/tutorials/deploy-a-rest-api-using-koa-prisma-and-aiven/aiven-01.png" alt="Select Aiven service"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, select Google Cloud as the cloud service provider to run the MySQL database.&lt;/p&gt;

&lt;p&gt;&lt;a href="//koyeb.com/static/images/tutorials/deploy-a-rest-api-using-koa-prisma-and-aiven/aiven-02.png" class="article-body-image-wrapper"&gt;&lt;img src="//koyeb.com/static/images/tutorials/deploy-a-rest-api-using-koa-prisma-and-aiven/aiven-02.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select the &lt;strong&gt;Hobbyist&lt;/strong&gt; plan which is perfect for small test environments and is ideal to follow this guide.&lt;/p&gt;

&lt;p&gt;&lt;a href="//koyeb.com/static/images/tutorials/deploy-a-rest-api-using-koa-prisma-and-aiven/aiven-03.png" class="article-body-image-wrapper"&gt;&lt;img src="//koyeb.com/static/images/tutorials/deploy-a-rest-api-using-koa-prisma-and-aiven/aiven-03.png" alt="Select Aiven cloud service provider"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Last, click the &lt;strong&gt;Create Service&lt;/strong&gt; button to provision the MySQL database. You land on the Aiven Services page where you can see the newly created service.&lt;/p&gt;

&lt;p&gt;Click the MySQL service to go to the service details page and retrieve the MySQL database credentials.&lt;/p&gt;

&lt;p&gt;&lt;a href="//koyeb.com/static/images/tutorials/deploy-a-rest-api-using-koa-prisma-and-aiven/aiven-05.png" class="article-body-image-wrapper"&gt;&lt;img src="//koyeb.com/static/images/tutorials/deploy-a-rest-api-using-koa-prisma-and-aiven/aiven-05.png" alt="Aiven MySQL service overview"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take note of the &lt;strong&gt;Service URI&lt;/strong&gt; in a secure place, that’s what we will use to connect to our database in our application. Embedded in the URI are the MySQL user, password, host, and port as well as a default database name, so don't share it publicly!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tip: If you’re more of a command line person, you can make use of the &lt;a href="https://developer.aiven.io/docs/tools/cli.html"&gt;Aiven CLI&lt;/a&gt; as well.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Connect to the database
&lt;/h3&gt;

&lt;p&gt;Before we go further, let's ensure we can properly connect to the MySQL database we just deployed to ensure everything is working as expected.&lt;br&gt;
In the terminal, run the following command to connect to the database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mysql &lt;span class="nt"&gt;--user&lt;/span&gt; AIVEN_DB_USER &lt;span class="nt"&gt;--password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;AIVEN_DB_PASSWORD &lt;span class="nt"&gt;--host&lt;/span&gt; AIVEN_DB_HOST &lt;span class="nt"&gt;--port&lt;/span&gt; AIVEN_DB_PORT defaultdb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Don't forget to replace &lt;code&gt;AIVEN_DB_USER&lt;/code&gt;, &lt;code&gt;AIVEN_DB_PASSWORD&lt;/code&gt;, &lt;code&gt;AIVEN_DB_HOST&lt;/code&gt;, and &lt;code&gt;AIVEN_DB_PORT&lt;/code&gt; with your own information.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once the command is executed, if everything goes well, you should see the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Welcome to the MySQL monitor.  Commands end with &lt;span class="p"&gt;;&lt;/span&gt; or &lt;span class="se"&gt;\g&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Your MySQL connection &lt;span class="nb"&gt;id &lt;/span&gt;is 139834
Server version: 8.0.26 Source distribution

Copyright &lt;span class="o"&gt;(&lt;/span&gt;c&lt;span class="o"&gt;)&lt;/span&gt; 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type &lt;span class="s1"&gt;'help;'&lt;/span&gt; or &lt;span class="s1"&gt;'\h'&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;help. Type &lt;span class="s1"&gt;'\c'&lt;/span&gt; to clear the current input statement.

mysql&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create the Notes REST API using Koa and Prisma
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create the Koa application
&lt;/h3&gt;

&lt;p&gt;First, we will create a new Koa application and install the necessary packages required by our application.&lt;br&gt;
To start, create a new directory for our application code and change to the newly created directory using the command below:&lt;br&gt;
&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;mkdir &lt;/span&gt;koa-prisma-notes-api
&lt;span class="nb"&gt;cd &lt;/span&gt;koa-prisma-notes-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, initialize a new Node project using the command below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command creates a &lt;code&gt;package.json&lt;/code&gt; file inside the &lt;code&gt;koa-prisma-notes-api&lt;/code&gt; directory containing basic information such as the project name, version, and author.&lt;/p&gt;

&lt;p&gt;We can then install the dependencies required by our API using the &lt;code&gt;npm&lt;/code&gt; command:&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;koa @koa/router koa-body
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command installs Koa, &lt;code&gt;koa-router&lt;/code&gt; a router for Koa which we will use to define the API endpoints, and &lt;code&gt;koa-body&lt;/code&gt; a body-parser middleware to parse the request body as JSON.&lt;/p&gt;

&lt;p&gt;With those dependencies installed, create a new &lt;code&gt;src&lt;/code&gt; containing an &lt;code&gt;index.js&lt;/code&gt; file:&lt;br&gt;
&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;mkdir &lt;/span&gt;src &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;src
&lt;span class="nb"&gt;touch &lt;/span&gt;index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open and add the following code to the &lt;code&gt;index.js&lt;/code&gt; file using your preferred editor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/index.js&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Koa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;koa&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@koa/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;KoaBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;koa-body&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Koa&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;KoaBody&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;allowedMethods&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server running at: http://localhost:8080&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, we:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;import the dependencies required by our application,&lt;/li&gt;
&lt;li&gt;create a new instance of Koa to which everything will be tied to,&lt;/li&gt;
&lt;li&gt;add the Koa router and Koa body middlewares to the Koa application,&lt;/li&gt;
&lt;li&gt;launch the Koa server on port &lt;code&gt;8080&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can then start the server by running in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node src/index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works fine but for a better development experience, we would like the server to restart automatically whenever we make changes.&lt;br&gt;
For that, we will make use of Nodemon which will automatically restart the application when file changes are detected in the directory.&lt;/p&gt;

&lt;p&gt;To install &lt;code&gt;nodemon&lt;/code&gt; in your terminal, run the following command:&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;nodemon &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we can start the server by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nodemon src/index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, add the following scripts to your &lt;code&gt;package.json&lt;/code&gt; to ease the launch of the application for development and production as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;package.json&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nodemon src/index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node src/index.js"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install Prisma
&lt;/h3&gt;

&lt;p&gt;Prisma is a next-generation ORM for Node.js and TypeScript. It supports multiple databases such as PostgreSQL, MySQL, SQL Server, SQLite, and MongoDB.&lt;br&gt;
We will use Prisma to manage our schemas and query the database from our application.&lt;/p&gt;

&lt;p&gt;Start by adding Prisma to your project using the following command:&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;prisma &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then initialize a fresh Prisma project by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx prisma init &lt;span class="nt"&gt;--datasource-provider&lt;/span&gt; mysql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a new &lt;code&gt;prisma&lt;/code&gt; directory that contains a &lt;code&gt;schema.prisma&lt;/code&gt; file and a &lt;code&gt;.env&lt;/code&gt; and file in the project root.&lt;br&gt;
The &lt;code&gt;schema.prisma&lt;/code&gt; file contains things like the Prisma client generator, the database connection, and the Prisma schema which will be used to define the database schema.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;✔ Your Prisma schema was created at prisma/schema.prisma
  You can now open it &lt;span class="k"&gt;in &lt;/span&gt;your favorite editor.

Next steps:
1. Set the DATABASE_URL &lt;span class="k"&gt;in &lt;/span&gt;the .env file to point to your existing database. If your database has no tables yet, &lt;span class="nb"&gt;read &lt;/span&gt;https://pris.ly/d/getting-started
2. Set the provider of the datasource block &lt;span class="k"&gt;in &lt;/span&gt;schema.prisma to match your database: postgresql, mysql, sqlite, sqlserver or mongodb &lt;span class="o"&gt;(&lt;/span&gt;Preview&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
3. Run prisma db pull to turn your database schema into a Prisma schema.
4. Run prisma generate to generate the Prisma Client. You can &lt;span class="k"&gt;then &lt;/span&gt;start querying your database.

More information &lt;span class="k"&gt;in &lt;/span&gt;our documentation:
https://pris.ly/d/getting-started
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;.env&lt;/code&gt; file contains the environment variables that will be put into the system environments. Prisma will then read and use these variables.&lt;br&gt;
Edit the &lt;code&gt;.env&lt;/code&gt; file by replacing the &lt;code&gt;DATABASE_URL&lt;/code&gt; value with your Aiven database connection string.&lt;br&gt;
&lt;/p&gt;

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

+DATABASE_URL&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"mysql://AIVEN_DB_USER:AIVEN_DB_PASSWORD@AIVEN_DB_HOST:AIVEN_PORT/AIVEN_DB_DATABASE_NAME?ssl-mode=REQUIRED"&lt;/span&gt;
&lt;span class="nt"&gt;-DATABASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"mysql://johndoe:randompassword@localhost:3306/mydb"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Prisma schema file contains the configuration of the Prisma setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// prisma/schema.prisma&lt;/span&gt;

&lt;span class="nx"&gt;generator&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prisma-client-js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;datasource&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mysql&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;url&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create a Prisma schema for the notes API
&lt;/h3&gt;

&lt;p&gt;Our application will just have one model called &lt;code&gt;Note&lt;/code&gt;. To create the data model definition in the &lt;code&gt;prisma/schema.prisma&lt;/code&gt; file add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// prisma/schema.prisma&lt;/span&gt;

&lt;span class="nx"&gt;generator&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prisma-client-js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;datasource&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mysql&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;url&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="nx"&gt;Note&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="nx"&gt;id&lt;/span&gt;        &lt;span class="nx"&gt;Int&lt;/span&gt;      &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;id&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;autoincrement&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="nx"&gt;title&lt;/span&gt;     &lt;span class="nb"&gt;String&lt;/span&gt;   &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VarChar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="nx"&gt;content&lt;/span&gt;   &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="nx"&gt;createdAt&lt;/span&gt; &lt;span class="nx"&gt;DateTime&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="nx"&gt;updatedAt&lt;/span&gt; &lt;span class="nx"&gt;DateTime&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;updatedAt&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each field definition is composed of the following parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The field name&lt;/li&gt;
&lt;li&gt;The field type&lt;/li&gt;
&lt;li&gt;Type modifiers (optional)&lt;/li&gt;
&lt;li&gt;Attributes, including native database type attributes (optional)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our &lt;code&gt;Note&lt;/code&gt; model has a couple of fields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;id&lt;/code&gt;: of type &lt;code&gt;Int&lt;/code&gt; marked as the primary key using the &lt;code&gt;@id&lt;/code&gt; modifier and set to a default value which will be auto-incremented&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;title&lt;/code&gt;: of type &lt;code&gt;String&lt;/code&gt; and using the native database type &lt;code&gt;varchar&lt;/code&gt; with a length of 255.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;content&lt;/code&gt;: of type  &lt;code&gt;String&lt;/code&gt; but marked as optional by using &lt;code&gt;?&lt;/code&gt; and of native database type &lt;code&gt;text&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;createdAt&lt;/code&gt;: of type &lt;code&gt;DateTime&lt;/code&gt; with a default value set to the current time when a note is created&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;updatedAt&lt;/code&gt;: of type &lt;code&gt;DateTime&lt;/code&gt; with a default value set to the time when the note is updated&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Create your first Prisma migration
&lt;/h3&gt;

&lt;p&gt;With the note model defined, we can now perform a Prisma migration to synchronize our database schema with our Prisma schema. To do so, run the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npx prisma migrate dev

Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource &lt;span class="s2"&gt;"db"&lt;/span&gt;: MySQL database &lt;span class="s2"&gt;"defaultdb"&lt;/span&gt; at &lt;span class="s2"&gt;"mysql-xyz.aivencloud.com:28784"&lt;/span&gt;

✔ Enter a name &lt;span class="k"&gt;for &lt;/span&gt;the new migration: …
Applying migration &lt;span class="sb"&gt;`&lt;/span&gt;20211229094929_&lt;span class="sb"&gt;`&lt;/span&gt;

The following migration&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt; have been created and applied from new schema changes:

migrations/
  └─ 20211229094929_/
    └─ migration.sql

Your database is now &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;sync &lt;/span&gt;with your schema.

✔ Generated Prisma Client &lt;span class="o"&gt;(&lt;/span&gt;3.7.0 | library&lt;span class="o"&gt;)&lt;/span&gt; to ./node_modules/@prisma/client &lt;span class="k"&gt;in &lt;/span&gt;822ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the migration is completed, your &lt;code&gt;prisma&lt;/code&gt; directory structure should now look as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;prisma
├── migrations
│   ├── 20211229094929_
│   │   └── migration.sql
│   └── migration_lock.toml
└── schema.prisma
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While it’s totally fine to use &lt;code&gt;migrate dev&lt;/code&gt; to run migrations in a development environment, in production, or in your CI/CD pipeline, we need to make sure we apply any pending migrations and create the database if it does not exist using &lt;code&gt;prisma migrate deploy&lt;/code&gt; before running the application.&lt;/p&gt;

&lt;p&gt;To make doing that straightforward, let’s add a &lt;code&gt;build&lt;/code&gt; script in 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 json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;package.json&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"prisma generate &amp;amp;&amp;amp; prisma migrate deploy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create seeds data
&lt;/h3&gt;

&lt;p&gt;We are now ready to seed our database with some mock data using Prisma. Into the &lt;code&gt;prisma&lt;/code&gt; directory, create a new &lt;code&gt;seed.js&lt;/code&gt; file containing the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// prisma/seed.js&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PrismaClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@prisma/client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;PrismaClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createMany&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Deploy a Go Gin Application on Koyeb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;This tutorial explains how to deploy a Go Gin application on the Koyeb serverless platform using git-driven deployment.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Deploy a Laravel Application with Continuous Deployment on Koyeb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;This guide shows how to deploy a Laravel application on the Koyeb Serverless Platform using git-driven deployment. Git-driven deployment allows you to push your code without having to take care of the build, deployment, and run process. Koyeb handles all this for you.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Continuous Deployment of a NestJS Application on Koyeb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;This guide explains how to continuously deploy a NestJS application on the Koyeb serverless platform.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$disconnect&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;The script uses the Prisma client to insert data into the database. You may notice that we are using the &lt;code&gt;createMany()&lt;/code&gt; function to insert multiple data at once.&lt;/p&gt;

&lt;p&gt;Next, add a &lt;code&gt;prisma&lt;/code&gt; section in our &lt;code&gt;package.json&lt;/code&gt; file to be able to run the script using the Prisma CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;package.json&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"prisma"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"seed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node prisma/seed.js"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then to seed the database, execute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npx prisma db seed
Environment variables loaded from .env
Running seed &lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;node prisma/seed.js&lt;span class="sb"&gt;`&lt;/span&gt; ...

🌱  The seed &lt;span class="nb"&gt;command &lt;/span&gt;has been executed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Building the Notes Koa API
&lt;/h3&gt;

&lt;p&gt;With all the setup out of the way, let’s start building the API’s functionality. As mentioned earlier, the note API is going to contain basic CRUD operations.&lt;br&gt;
As seen briefly in the seed section above, we will be making use of the Prisma client to interact with our database and perform the necessary CRUD operation.&lt;/p&gt;

&lt;p&gt;Add the code below inside the &lt;code&gt;index.js&lt;/code&gt; file containing our Koa application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/index.js&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PrismaClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@prisma/client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Koa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;koa&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@koa/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;KoaBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;koa-body&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Koa&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/notes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;notes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;findMany&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Notes retrieved&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/notes/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;note&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;findUnique&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Note retrieved&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Note not found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/notes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;note&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;      &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;201&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Note created&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/notes/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;note&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;      &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Note updated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/notes/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;204&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Note delete&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;KoaBody&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;allowedMethods&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server running at: http://localhost:8080&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above adds the following routes to our Note application:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GET /notes&lt;/code&gt;: retrieves all notes and uses the Prisma client &lt;code&gt;findMany()&lt;/code&gt; function to retrieve the notes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /notes/:id&lt;/code&gt;: retrieves a single note from its ID and uses the Prisma &lt;code&gt;findUnique()&lt;/code&gt; function to retrieve the note. If the note is found the API responds with an HTTP code &lt;code&gt;200&lt;/code&gt; and &lt;code&gt;404&lt;/code&gt; otherwise.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;POST /notes&lt;/code&gt;: creates a new note. It uses the Prisma &lt;code&gt;create()&lt;/code&gt; function to create the note and returns a &lt;code&gt;201&lt;/code&gt; HTTP code when the note is created.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PUT /notes/:id&lt;/code&gt;: updates an existing note from its ID. It uses the Prisma &lt;code&gt;update()&lt;/code&gt; function to update the note and returns a &lt;code&gt;200&lt;/code&gt; HTTP code when the note is updated.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DELETE /notes/:id&lt;/code&gt;: deletes a note from its ID. This endpoint uses the Prisma &lt;code&gt;delete()&lt;/code&gt; function to delete the note and returns a &lt;code&gt;204&lt;/code&gt; HTTP code when the note is deleted.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Run the Notes API application
&lt;/h3&gt;

&lt;p&gt;It's time to test out the API to ensure everything is working as expected.&lt;/p&gt;

&lt;p&gt;First, launch the server by running:&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;The server will start and be accessible at &lt;code&gt;http://localhost:8080&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then, let's play with the API using &lt;code&gt;curl&lt;/code&gt; to test the different endpoints:&lt;br&gt;
&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;# Retrieve all notes&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://localhost:8080/notes | jq &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# Output&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"message"&lt;/span&gt;: &lt;span class="s2"&gt;"Notes retrieved"&lt;/span&gt;,
  &lt;span class="s2"&gt;"data"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"id"&lt;/span&gt;: 1,
      &lt;span class="s2"&gt;"title"&lt;/span&gt;: &lt;span class="s2"&gt;"Deploy a Go Gin Application on Koyeb"&lt;/span&gt;,
      &lt;span class="s2"&gt;"content"&lt;/span&gt;: &lt;span class="s2"&gt;"This tutorial explains how to deploy a Go Gin application on the Koyeb serverless platform using git-driven deployment."&lt;/span&gt;,
      &lt;span class="s2"&gt;"status"&lt;/span&gt;: &lt;span class="s2"&gt;"draft"&lt;/span&gt;,
      &lt;span class="s2"&gt;"createdAt"&lt;/span&gt;: &lt;span class="s2"&gt;"2021-12-29T10:10:57.293Z"&lt;/span&gt;,
      &lt;span class="s2"&gt;"updatedAt"&lt;/span&gt;: &lt;span class="s2"&gt;"2021-12-29T10:10:57.294Z"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;,
    &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"id"&lt;/span&gt;: 2,
      &lt;span class="s2"&gt;"title"&lt;/span&gt;: &lt;span class="s2"&gt;"Deploy a Laravel Application with Continuous Deployment on Koyeb"&lt;/span&gt;,
      &lt;span class="s2"&gt;"content"&lt;/span&gt;: &lt;span class="s2"&gt;"This guide shows how to deploy a Laravel application on the Koyeb Serverless Platform using git-driven deployment. Git-driven deployment allows you to push your code without having to take care of the build, deployment, and run process. Koyeb handles all this for you."&lt;/span&gt;,
      &lt;span class="s2"&gt;"status"&lt;/span&gt;: &lt;span class="s2"&gt;"draft"&lt;/span&gt;,
      &lt;span class="s2"&gt;"createdAt"&lt;/span&gt;: &lt;span class="s2"&gt;"2021-12-29T10:10:57.294Z"&lt;/span&gt;,
      &lt;span class="s2"&gt;"updatedAt"&lt;/span&gt;: &lt;span class="s2"&gt;"2021-12-29T10:10:57.294Z"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;,
    &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"id"&lt;/span&gt;: 3,
      &lt;span class="s2"&gt;"title"&lt;/span&gt;: &lt;span class="s2"&gt;"Continuous Deployment of a NestJS Application on Koyeb"&lt;/span&gt;,
      &lt;span class="s2"&gt;"content"&lt;/span&gt;: &lt;span class="s2"&gt;"This guide explains how to continuously deploy a NestJS application on the Koyeb serverless platform."&lt;/span&gt;,
      &lt;span class="s2"&gt;"status"&lt;/span&gt;: &lt;span class="s2"&gt;"draft"&lt;/span&gt;,
      &lt;span class="s2"&gt;"createdAt"&lt;/span&gt;: &lt;span class="s2"&gt;"2021-12-29T10:10:57.294Z"&lt;/span&gt;,
      &lt;span class="s2"&gt;"updatedAt"&lt;/span&gt;: &lt;span class="s2"&gt;"2021-12-29T10:10:57.294Z"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Retrieve a single note&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://localhost:8080/notes/1 | jq &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# Output&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"message"&lt;/span&gt;: &lt;span class="s2"&gt;"Note retrieved"&lt;/span&gt;,
  &lt;span class="s2"&gt;"data"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"id"&lt;/span&gt;: 1,
    &lt;span class="s2"&gt;"title"&lt;/span&gt;: &lt;span class="s2"&gt;"Deploy a Go Gin Application on Koyeb"&lt;/span&gt;,
    &lt;span class="s2"&gt;"content"&lt;/span&gt;: &lt;span class="s2"&gt;"This tutorial explains how to deploy a Go Gin application on the Koyeb serverless platform using git-driven deployment."&lt;/span&gt;,
    &lt;span class="s2"&gt;"status"&lt;/span&gt;: &lt;span class="s2"&gt;"draft"&lt;/span&gt;,
    &lt;span class="s2"&gt;"createdAt"&lt;/span&gt;: &lt;span class="s2"&gt;"2021-12-29T10:10:57.293Z"&lt;/span&gt;,
    &lt;span class="s2"&gt;"updatedAt"&lt;/span&gt;: &lt;span class="s2"&gt;"2021-12-29T10:10:57.294Z"&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Create a new note&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"title": "Sample note title", "content": "Sample note content"}'&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8080/notes | jq &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# Output&lt;/span&gt;

&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"message"&lt;/span&gt;: &lt;span class="s2"&gt;"Note created"&lt;/span&gt;,
  &lt;span class="s2"&gt;"data"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"id"&lt;/span&gt;: 5,
    &lt;span class="s2"&gt;"title"&lt;/span&gt;: &lt;span class="s2"&gt;"Sample note title"&lt;/span&gt;,
    &lt;span class="s2"&gt;"content"&lt;/span&gt;: &lt;span class="s2"&gt;"Sample note content"&lt;/span&gt;,
    &lt;span class="s2"&gt;"status"&lt;/span&gt;: &lt;span class="s2"&gt;"draft"&lt;/span&gt;,
    &lt;span class="s2"&gt;"createdAt"&lt;/span&gt;: &lt;span class="s2"&gt;"2021-12-29T10:47:16.903Z"&lt;/span&gt;,
    &lt;span class="s2"&gt;"updatedAt"&lt;/span&gt;: &lt;span class="s2"&gt;"2021-12-29T10:47:16.904Z"&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Update a note&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"title": "Sample note title [UPDATED]", "content": "Sample note content"}'&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; PUT http://localhost:8080/notes/5 | jq &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# Output&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"message"&lt;/span&gt;: &lt;span class="s2"&gt;"Note updated"&lt;/span&gt;,
  &lt;span class="s2"&gt;"data"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"id"&lt;/span&gt;: 5,
    &lt;span class="s2"&gt;"title"&lt;/span&gt;: &lt;span class="s2"&gt;"Sample note title [UPDATED]"&lt;/span&gt;,
    &lt;span class="s2"&gt;"content"&lt;/span&gt;: &lt;span class="s2"&gt;"Sample note content"&lt;/span&gt;,
    &lt;span class="s2"&gt;"status"&lt;/span&gt;: &lt;span class="s2"&gt;"draft"&lt;/span&gt;,
    &lt;span class="s2"&gt;"createdAt"&lt;/span&gt;: &lt;span class="s2"&gt;"2021-12-29T10:47:16.903Z"&lt;/span&gt;,
    &lt;span class="s2"&gt;"updatedAt"&lt;/span&gt;: &lt;span class="s2"&gt;"2021-12-29T10:50:44.279Z"&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Delete a note&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; DELETE http://localhost:8080/notes/5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Update the Prisma schema (optional)
&lt;/h3&gt;

&lt;p&gt;Our application is now feature complete. But before we wrap up, let’s make a small refactor by adding status to notes. That way, we can have notes that are in draft and those published.&lt;/p&gt;

&lt;p&gt;Let’s start by updating the Prisma schema. Since we want to have predetermined status (&lt;code&gt;draft&lt;/code&gt; and &lt;code&gt;published&lt;/code&gt;), we are going to create an enum and add a new field called &lt;code&gt;status&lt;/code&gt; set to the type of the &lt;code&gt;Status&lt;/code&gt; enum with a default value of &lt;code&gt;draft&lt;/code&gt; to the Note model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// prisma/schema.prisma&lt;/span&gt;

&lt;span class="nx"&gt;generator&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prisma-client-js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;datasource&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mysql&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;url&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;Status&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="nx"&gt;draft&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="nx"&gt;published&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="nx"&gt;Note&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;id&lt;/span&gt;        &lt;span class="nx"&gt;Int&lt;/span&gt;      &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;id&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;autoincrement&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="nx"&gt;title&lt;/span&gt;     &lt;span class="nb"&gt;String&lt;/span&gt;   &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VarChar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;content&lt;/span&gt;   &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;    &lt;span class="nx"&gt;Status&lt;/span&gt;   &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;createdAt&lt;/span&gt; &lt;span class="nx"&gt;DateTime&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="nx"&gt;updatedAt&lt;/span&gt; &lt;span class="nx"&gt;DateTime&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;updatedAt&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we need to create a new migration to synchronize our database schema with the Prisma schema by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npx prisma migrate dev
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource &lt;span class="s2"&gt;"db"&lt;/span&gt;: MySQL database &lt;span class="s2"&gt;"defaultdb"&lt;/span&gt; at &lt;span class="s2"&gt;"mysql-xyz.aivencloud.com:28784"&lt;/span&gt;

✔ Enter a name &lt;span class="k"&gt;for &lt;/span&gt;the new migration: … add status
Applying migration &lt;span class="sb"&gt;`&lt;/span&gt;20211229125948_add_status&lt;span class="sb"&gt;`&lt;/span&gt;

The following migration&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt; have been created and applied from new schema changes:

migrations/
  └─ 20211229125948_add_status/
    └─ migration.sql

Your database is now &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;sync &lt;/span&gt;with your schema.

✔ Generated Prisma Client &lt;span class="o"&gt;(&lt;/span&gt;3.7.0 | library&lt;span class="o"&gt;)&lt;/span&gt; to ./node_modules/@prisma/client &lt;span class="k"&gt;in &lt;/span&gt;2.05s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When prompted for a name for the new migration, we’ll enter “add status”.&lt;/p&gt;

&lt;p&gt;Once the migration is completed, the &lt;code&gt;migrations&lt;/code&gt; directory should look like below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;prisma/migrations
├── 20211229125830_
│   └── migration.sql
├── 20211229125948_add_status
│   └── migration.sql
└── migration_lock.toml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Last, update the application to use the freshly created &lt;code&gt;status&lt;/code&gt; field by editing the Koa application &lt;code&gt;index.js&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/index.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PrismaClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@prisma/client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Koa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;koa&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@koa/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;KoaBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;koa-body&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Koa&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/notes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;notes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;findMany&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;notes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;findMany&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;    &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Notes retrieved&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/notes/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;note&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;findUnique&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Note retrieved&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Note not found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/notes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;note&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;     &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;201&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Note created&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/notes/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;note&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;     &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Note updated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/notes/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;204&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Note delete&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;KoaBody&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;allowedMethods&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server running at: http://localhost:8080&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now filter the notes based on their status when we call the &lt;code&gt;/notes&lt;/code&gt; endpoint and can also update the status of a note.&lt;br&gt;
For instance to list all notes with the &lt;code&gt;draft&lt;/code&gt; status run:&lt;br&gt;
&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;# Retrieve all draft notes&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://localhost:8080/notes?status&lt;span class="o"&gt;=&lt;/span&gt;draft | jq &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# Output&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"message"&lt;/span&gt;: &lt;span class="s2"&gt;"Notes retrieved"&lt;/span&gt;,
  &lt;span class="s2"&gt;"data"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"id"&lt;/span&gt;: 1,
      &lt;span class="s2"&gt;"title"&lt;/span&gt;: &lt;span class="s2"&gt;"Deploy a Go Gin Application on Koyeb"&lt;/span&gt;,
      &lt;span class="s2"&gt;"content"&lt;/span&gt;: &lt;span class="s2"&gt;"This tutorial explains how to deploy a Go Gin application on the Koyeb serverless platform using git-driven deployment."&lt;/span&gt;,
      &lt;span class="s2"&gt;"status"&lt;/span&gt;: &lt;span class="s2"&gt;"draft"&lt;/span&gt;,
      &lt;span class="s2"&gt;"createdAt"&lt;/span&gt;: &lt;span class="s2"&gt;"2021-12-29T12:58:37.639Z"&lt;/span&gt;,
      &lt;span class="s2"&gt;"updatedAt"&lt;/span&gt;: &lt;span class="s2"&gt;"2021-12-29T12:58:37.640Z"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;,
    &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"id"&lt;/span&gt;: 2,
      &lt;span class="s2"&gt;"title"&lt;/span&gt;: &lt;span class="s2"&gt;"Deploy a Laravel Application with Continuous Deployment on Koyeb"&lt;/span&gt;,
      &lt;span class="s2"&gt;"content"&lt;/span&gt;: &lt;span class="s2"&gt;"This guide shows how to deploy a Laravel application on the Koyeb Serverless Platform using git-driven deployment. Git-driven deployment allows you to push your code without having to take care of the build, deployment, and run process. Koyeb handles all this for you."&lt;/span&gt;,
      &lt;span class="s2"&gt;"status"&lt;/span&gt;: &lt;span class="s2"&gt;"draft"&lt;/span&gt;,
      &lt;span class="s2"&gt;"createdAt"&lt;/span&gt;: &lt;span class="s2"&gt;"2021-12-29T12:58:37.639Z"&lt;/span&gt;,
      &lt;span class="s2"&gt;"updatedAt"&lt;/span&gt;: &lt;span class="s2"&gt;"2021-12-29T12:58:37.640Z"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;,
    &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"id"&lt;/span&gt;: 3,
      &lt;span class="s2"&gt;"title"&lt;/span&gt;: &lt;span class="s2"&gt;"Continuous Deployment of a NestJS Application on Koyeb"&lt;/span&gt;,
      &lt;span class="s2"&gt;"content"&lt;/span&gt;: &lt;span class="s2"&gt;"This guide explains how to continuously deploy a NestJS application on the Koyeb serverless platform."&lt;/span&gt;,
      &lt;span class="s2"&gt;"status"&lt;/span&gt;: &lt;span class="s2"&gt;"draft"&lt;/span&gt;,
      &lt;span class="s2"&gt;"createdAt"&lt;/span&gt;: &lt;span class="s2"&gt;"2021-12-29T12:58:37.639Z"&lt;/span&gt;,
      &lt;span class="s2"&gt;"updatedAt"&lt;/span&gt;: &lt;span class="s2"&gt;"2021-12-29T12:58:37.640Z"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deploy the Notes application on Koyeb
&lt;/h2&gt;

&lt;p&gt;We are now ready to deploy our note API on Koyeb.&lt;/p&gt;

&lt;p&gt;Koyeb is a developer-friendly serverless platform to deploy apps globally. It supports deploying applications using pre-built Docker containers or native code using git.&lt;br&gt;
For the purpose of this tutorial, we will deploy our application using git-driven deployment.&lt;/p&gt;

&lt;p&gt;Head over to GitHub to create a new repository and push the application code running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git init
git add &lt;span class="nt"&gt;--all&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Initial commit"&lt;/span&gt;
git branch &lt;span class="nt"&gt;-M&lt;/span&gt; main
git remote add origin https://github.com/YOUR_GITHUB_USERNAME/koa-prisma-notes-api.git
git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the &lt;a href="https://app.koyeb.com/"&gt;Koyeb&lt;/a&gt; control panel, click the &lt;strong&gt;DEPLOY MY FIRST APP&lt;/strong&gt; button to go to the App creation page.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select GitHub as the deployment method to use&lt;/li&gt;
&lt;li&gt;In the repositories list, select the repository containing your Koa application&lt;/li&gt;
&lt;li&gt;Specify the branch to deploy, in this case, &lt;code&gt;main&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;Environment variables&lt;/strong&gt; section, add an environment variable &lt;code&gt;DATABASE_URL&lt;/code&gt; having for value your Aiven connection string of form: &lt;code&gt;mysql://AIVEN_DB_USER:AIVEN_DB_PASSWORD@AIVEN_DB_HOST:AIVEN_PORT/AIVEN_DB_DATABASE_NAME?ssl-mode=REQUIRED&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Give your App a name, i.e koa-prisma-notes-api-on-koyeb, and click Create App.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There is no need to set the build and run commands, by default Koyeb detects if a &lt;code&gt;build&lt;/code&gt; and &lt;code&gt;start&lt;/code&gt; scripts are present in your &lt;code&gt;package.json&lt;/code&gt; file and execute them automatically.&lt;br&gt;
The &lt;code&gt;build&lt;/code&gt; script will be run during the build stage and the &lt;code&gt;start&lt;/code&gt;script to launch the application once the build succeeded.&lt;/p&gt;

&lt;p&gt;&lt;a href="//koyeb.com/static/images/tutorials/deploy-a-rest-api-using-koa-prisma-and-aiven/deploy-on-koyeb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="//koyeb.com/static/images/tutorials/deploy-a-rest-api-using-koa-prisma-and-aiven/deploy-on-koyeb.jpg" alt="Deploy on Koyeb"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You land on the deployment page where you can follow the progress of your application's deployment. Once the build and deployment are completed, you can access your application by clicking the App URL ending with &lt;code&gt;koyeb.app&lt;/code&gt; in the Koyeb control panel.&lt;/p&gt;

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

&lt;p&gt;That's it! In this tutorial, we looked at how to build a REST API with Koa, Prisma, and Aiven. We created a MySQL database using Aiven, created a new Koa application, and used Prisma to interact with our MySQL database from our application.&lt;br&gt;
Along the line, we covered how to run migration and seed our database with data using Prisma.&lt;/p&gt;

&lt;p&gt;Finally, we deployed the application on Koyeb using git-driven deployment: all the changes you push to your repository will automatically trigger a new build and deployment on the Koyeb Serverless Platform.&lt;br&gt;
With the Koyeb continuous deployment feature, your changes will go live as soon as the deployment passes all necessary health checks. In case of a failure during deployment, the platform maintains the latest working deployment in production to ensure your application is always up and running.&lt;/p&gt;

&lt;p&gt;You can access the complete application code on &lt;a href="https://github.com/koyeb/example-koa-prisma"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>webdev</category>
      <category>node</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Deploy a Go Gin Application on Koyeb</title>
      <dc:creator>Edouard Bonlieu</dc:creator>
      <pubDate>Wed, 12 Jan 2022 13:26:21 +0000</pubDate>
      <link>https://forem.com/koyeb/deploy-a-go-gin-application-on-koyeb-453e</link>
      <guid>https://forem.com/koyeb/deploy-a-go-gin-application-on-koyeb-453e</guid>
      <description>&lt;p&gt;This guide explains how to deploy a Golang Gin application on the Koyeb serverless platform using git-driven deployment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/gin-gonic/gin"&gt;Gin&lt;/a&gt; is a web framework written in Golang focusing on performance and simplicity.&lt;/p&gt;

&lt;p&gt;By deploying a Go Gin application on &lt;a href="////koyeb.com"&gt;Koyeb&lt;/a&gt; using git-driven deployment, each time you push your code changes, your application will be automatically built and promoted once the built and health checks are completed.&lt;br&gt;
Once your application is deployed, it will benefit from Koyeb native autoscaling, automatic HTTPS (SSL), auto-healing, and global load-balancing across our edge network with zero configuration.&lt;/p&gt;
&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;To successfully follow and complete this guide, you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Go programming language installed&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://app.koyeb.com"&gt;Koyeb account&lt;/a&gt; to deploy and run the Go web API&lt;/li&gt;
&lt;li&gt;A &lt;a href="////github.com/"&gt;&lt;strong&gt;GitHub account&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Steps
&lt;/h2&gt;

&lt;p&gt;To successfully complete this guide and deploy the Go API on Koyeb, you need to follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Building a minimalist Go Gin application&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deploy the Go Gin application on Koyeb&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Building a minimalist Go Gin application
&lt;/h2&gt;

&lt;p&gt;To get started, create a new directory to build our sample application:&lt;br&gt;
&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;mkdir&lt;/span&gt; ~/gin-demo
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/gin-demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, run &lt;code&gt;go mod init&lt;/code&gt; to create a &lt;code&gt;go.mod&lt;/code&gt; file and track your code's dependencies.&lt;br&gt;
As you add dependencies, the &lt;code&gt;go.mod&lt;/code&gt; file will list the versions your code depends on allowing you to keep your builds reproducible and giving you direct control over which module versions to use.&lt;/p&gt;

&lt;p&gt;In your project folder, create a new file named &lt;code&gt;app.go&lt;/code&gt; with the following content inside:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s"&gt;"fmt"&lt;/span&gt;
  &lt;span class="s"&gt;"os"&lt;/span&gt;

  &lt;span class="s"&gt;"github.com/gin-gonic/gin"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"PORT"&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;port&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"8000"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s"&gt;"message"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Hello, world!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/:name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s"&gt;"message"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, %s!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&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;The code above launches a Gin server listening on port 8000 by default with two API routes configured:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/&lt;/code&gt; returning "Hello, world!"&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/:name&lt;/code&gt; returning "Hello, :name!" where :name is the string passed in parameter, i.e /john will return "Hello, john!".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, in your terminal execute &lt;code&gt;go mod tidy&lt;/code&gt; to add missing modules required by our project and add &lt;code&gt;github.com/gin-gonic/gin&lt;/code&gt; as a project dependency.&lt;/p&gt;

&lt;p&gt;You can now run the application locally by running &lt;code&gt;go run server.go&lt;/code&gt; and navigating in your browser at &lt;code&gt;http://localhost:8000&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy the Go Gin application on Koyeb
&lt;/h2&gt;

&lt;p&gt;Next, initialize a new git repository on your local machine running:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Add a new remote pointing to your GitHub repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git remote add origin git@github.com:&amp;lt;YOUR_GITHUB_USERNAME&amp;gt;/&amp;lt;YOUR_GITHUB_REPOSITORY&amp;gt;.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Last, add the &lt;code&gt;app.go&lt;/code&gt;, &lt;code&gt;go.mod&lt;/code&gt; and &lt;code&gt;go.sum&lt;/code&gt; files to your repository and commit &amp;amp; push your changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add app.go go.mod go.sum
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Initial commit"&lt;/span&gt;
git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go to the Koyeb &lt;a href="https://app.koyeb.com"&gt;Control Panel&lt;/a&gt; and click the Create App button to go to the App creation page:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select GitHub as the deployment method to use&lt;/li&gt;
&lt;li&gt;In the repositories list, select the repository containing your Go Gin application&lt;/li&gt;
&lt;li&gt;Specify the branch to deploy, in this case, &lt;code&gt;main&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Give your App a name, i.e go-gin-on-koyeb, and click Create App.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then, click the &lt;strong&gt;Create App&lt;/strong&gt; button to create and deploy the application. You land on the deployment page where you can follow the progress of your Go Gin application's deployment. Once the build and deployment are completed, you can access your application by clicking the App URL ending with &lt;code&gt;koyeb.app&lt;/code&gt; in the Koyeb control panel.&lt;/p&gt;

&lt;p&gt;If you want to learn about how Koyeb automatically builds your Go Gin applications from git, make sure to read our &lt;a href="////koyeb.com/docs/apps/build-from-git"&gt;&lt;strong&gt;how we build from git&lt;/strong&gt;&lt;/a&gt; documentation.&lt;/p&gt;

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

&lt;p&gt;In this guide, you learned how to deploy a Go Gin application on Koyeb using git. Each change you push to your repository will automatically trigger a new build and deployment on the Koyeb Serverless Platform.&lt;br&gt;
Your changes then go live as soon as the deployment passes all necessary health checks. In case of a failure during one of your deployments, we ensure to keep the latest working deployment active so your application is always up and running.&lt;/p&gt;

&lt;p&gt;If you have any questions or suggestions to improve this guide, feel free to reach out to us on &lt;strong&gt;&lt;a href="https://slack.koyeb.com/"&gt;Slack&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>go</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Deploy a Laravel Application with Continuous Deployment on Koyeb</title>
      <dc:creator>Edouard Bonlieu</dc:creator>
      <pubDate>Mon, 10 Jan 2022 17:13:54 +0000</pubDate>
      <link>https://forem.com/koyeb/deploy-a-laravel-application-with-continuous-deployment-on-koyeb-2k98</link>
      <guid>https://forem.com/koyeb/deploy-a-laravel-application-with-continuous-deployment-on-koyeb-2k98</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Laravel is a popular, simple and flexible PHP application framework that is ideal for modern, full-stack web apps.&lt;/p&gt;

&lt;p&gt;Laravel provides a great developer experience with its many built-in features like dependency injections, an expressive database abstraction layer, queues and scheduled jobs, unit and integration testing, and more.&lt;/p&gt;

&lt;p&gt;In this guide, we create a basic Laravel application, push it to a GitHub repository, and deploy it on the Koyeb Serverless Platform using git-driven deployment which allows you to push your code without having to take care of the build, deployment, and run process. Koyeb handles all this for you.&lt;/p&gt;

&lt;p&gt;By deploying your Laravel application on &lt;a href="https://koyeb.com"&gt;Koyeb&lt;/a&gt;, you benefit from the platform's built-in autoscaling, autohealing, TLS encryption, global load balancing across our edge network, service discovery, and more.&lt;/p&gt;

&lt;p&gt;If you want to learn how to &lt;a href="https://koyeb.com/tutorials/dockerize-and-deploy-a-laravel-application-to-production"&gt;Dockerize and Deploy a Laravel Application to Production&lt;/a&gt;, make sure to check out the linked guide.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;To follow and complete this guide successfully, you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;a href="https://app.koyeb.com/"&gt;Koyeb account&lt;/a&gt; to deploy and run the Laravel web application&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://www.koyeb.com/docs/cli/installation"&gt;Koyeb CLI&lt;/a&gt; installed to interact with Koyeb from the command line&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://github.com/"&gt;GitHub account&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.php.net/"&gt;PHP&lt;/a&gt; and &lt;a href="https://getcomposer.org/"&gt;Composer&lt;/a&gt; installed on your machine&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;To deploy a Laravel web application on the Koyeb serverless platform, you need to follow these three steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new Laravel application&lt;/li&gt;
&lt;li&gt;Push the Laravel application to a GitHub repository&lt;/li&gt;
&lt;li&gt;Deploy the Laravel application on Koyeb&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Create a new Laravel application
&lt;/h2&gt;

&lt;p&gt;To get started, we will create a new Laravel project using Composer, a PHP package manager. In your terminal, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer create-project --prefer-dist laravel/laravel laravel-on-koyeb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will create a new Laravel application in the &lt;code&gt;laravel-on-koyeb&lt;/code&gt; directory and install all the dependencies required by the app to run properly.&lt;/p&gt;

&lt;p&gt;You can launch the application in development mode by running the following command in your terminal from the &lt;code&gt;laravel-on-koyeb&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Open a browser window and navigate to the &lt;code&gt;http://localhost:8000&lt;/code&gt; URL. You land on the Laravel welcome page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generate a key for Laravel's encryption services
&lt;/h3&gt;

&lt;p&gt;Generate an APP_KEY to properly secure user sessions and other encrypted data by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan key:generate --show
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save this value in a safe place. We will pass it to Koyeb as an &lt;code&gt;ENV_VAR&lt;/code&gt; when we deploy the Laravel app on the platform later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add a Procfile
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;Procfile&lt;/code&gt; tells Koyeb how to run your application. Create a &lt;code&gt;Profile&lt;/code&gt; in your application's root directory by executing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo "web: vendor/bin/heroku-php-apache2 public/" &amp;gt; Procfile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Push the Laravel application to a GitHub Repository
&lt;/h2&gt;

&lt;p&gt;Now that we have created our Laravel application, we will create a git directory to store it. Return to your &lt;code&gt;laravel-on-koyeb&lt;/code&gt; directory and initialize a new git directory for your Laravel 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 init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add a .gitignore file
&lt;/h3&gt;

&lt;p&gt;To keep only the necessary files in the repository, add this .gitignore file to exclude all unnecessary Laravel files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl https://raw.githubusercontent.com/github/gitignore/master/Laravel.gitignore &amp;gt; .gitignore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Execute the following command to add and commit the changes made in your files to your repository:&lt;br&gt;
&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 "Laravel app initial commit"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add these changes to your remote GitHub repository for this app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git remote add origin git@github.com:YOUR_GITHUB_USERNAME/laravel-on-koyeb.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rename the repository default branch to main executing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git branch -M main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, push your changes to the GitHub repository by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push -u origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You are now ready to deploy your application on Koyeb.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy the Laravel application on Koyeb
&lt;/h2&gt;

&lt;p&gt;Go to the &lt;a href="https://app.koyeb.com/apps"&gt;&lt;strong&gt;Koyeb Control Panel&lt;/strong&gt;&lt;/a&gt; and click the &lt;strong&gt;Create App&lt;/strong&gt; button.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;On the App Creation form, select &lt;code&gt;GitHub&lt;/code&gt; as your deployment method.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;&lt;em&gt;Repository&lt;/em&gt;&lt;/strong&gt;, select your &lt;code&gt;laravel-on-koyeb&lt;/code&gt; repository and specify the &lt;strong&gt;&lt;em&gt;Branch&lt;/em&gt;&lt;/strong&gt;. For this demo, put &lt;code&gt;main&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Thanks to your Procfile, there is no need to specify a &lt;strong&gt;&lt;em&gt;Run command&lt;/em&gt;&lt;/strong&gt;. Since this is a basic app, you can use the default settings for container size, regions, horizontal scaling, and port.&lt;/li&gt;
&lt;li&gt;Add an environment variable Secret with the &lt;strong&gt;&lt;em&gt;key&lt;/em&gt;&lt;/strong&gt; as &lt;code&gt;APP_KEY&lt;/code&gt; and the &lt;strong&gt;&lt;em&gt;value&lt;/em&gt;&lt;/strong&gt; as the value you generated in the step above.&lt;/li&gt;
&lt;li&gt;Finally, give your App a name, i.e &lt;code&gt;laravel-on-koyeb&lt;/code&gt;, and click &lt;strong&gt;Create App.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You land on the deployment page of your service where you can follow the progress of your Laravel application's deployment. Koyeb is building and deploying your application. Once the build and deployment are completed, you can access your application by clicking the App URL ending with &lt;code&gt;koyeb.app&lt;/code&gt; in the Koyeb control panel.&lt;/p&gt;

&lt;p&gt;If you want to learn about how Koyeb automatically builds your Laravel applications from git, make sure to read our &lt;a href="https://koyeb.com/docs/apps/build-from-git"&gt;&lt;strong&gt;how we build from git&lt;/strong&gt;&lt;/a&gt; documentation.&lt;/p&gt;

&lt;p&gt;Your Laravel application is now running on Koyeb and benefits from native autoscaling, automatic HTTPS (SSL), auto-healing, and global load-balancing across our edge network.&lt;/p&gt;

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

&lt;p&gt;In this guide, you learned how to deploy a Laravel application on Koyeb and benefit from its built-in continuous deployment pipeline. Each change you push to your repository will automatically trigger a new build and deployment on the Koyeb Serverless Platform.&lt;/p&gt;

&lt;p&gt;Your changes then go live as soon as the deployment passes all necessary health checks. In case of a failure during one of your deployments, we ensure to keep the latest working deployment active so your application is always up and running.&lt;/p&gt;

&lt;p&gt;If you have any questions or suggestions to improve this guide, feel free to reach out to us on &lt;strong&gt;&lt;a href="https://slack.koyeb.com/"&gt;Slack&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>php</category>
      <category>tutorial</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Continuous Deployment of a NestJS Application on Koyeb</title>
      <dc:creator>Edouard Bonlieu</dc:creator>
      <pubDate>Wed, 10 Nov 2021 08:39:30 +0000</pubDate>
      <link>https://forem.com/koyeb/continuous-deployment-of-a-nestjs-application-on-koyeb-3fn8</link>
      <guid>https://forem.com/koyeb/continuous-deployment-of-a-nestjs-application-on-koyeb-3fn8</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;NestJS is a Node.js framework to build efficient and scalable server-side applications. Nest uses and abstracts ExpressJS under the hood to ease development but keeps its API accessible to developers.&lt;br&gt;
This allows you to compose and use all Express's compatible third-party modules and middlewares. In addition to Express, you can also configure Nest to use Fastify, another popular Node.js framework.&lt;br&gt;
Nest is built with typescript and combines the use of object-oriented programming, functional programming, and functional reactive programming.&lt;/p&gt;

&lt;p&gt;In this tutorial, we will create a minimalist NestJS application and showcase how to deploy the application with continuous deployment on Koyeb.&lt;br&gt;
By deploying the Nest application on Koyeb using the git-driven deployment method, each time you push new changes to your GitHub repository, a new deployment will occur and be promoted once the built and health checks are completed.&lt;/p&gt;

&lt;p&gt;Thanks to Koyeb, you will benefit from native global load-balancing across our edge network, autoscaling, automatic HTTPS (SSL), and auto-healing with zero configuration.&lt;/p&gt;
&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;To successfully follow and complete this guide, you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A local development environment with Node.js installed&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://github.com"&gt;GitHub account&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://app.koyeb.com"&gt;Koyeb account&lt;/a&gt; to deploy and run the Nest application&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Steps
&lt;/h2&gt;

&lt;p&gt;To successfully complete this tutorial and deploy the Nest application on Koyeb Serverless Platform, you need to follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Create and configure the Nest application&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Push the sources to GitHub&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deploy the Nest app on Koyeb&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Create and configure the Nest application
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Installing the NestJS CLI
&lt;/h3&gt;

&lt;p&gt;To get started, we need to install the Nest CLI. In your terminal run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-g&lt;/span&gt; @nestjs/cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create a new Nest application
&lt;/h3&gt;

&lt;p&gt;The Nest CLI installed, we can initialize a new Nest app running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nest new nestjs-on-koyeb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command below created a directory &lt;code&gt;nestjs-on-koyeb&lt;/code&gt; containing the node modules to properly run the Nest application and a few other boilerplate files.&lt;br&gt;
&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;.&lt;/span&gt;
├── README.md
├── nest-cli.json
├── node_modules
├── package-lock.json
├── package.json
├── src
│   ├── app.controller.spec.ts
│   ├── app.controller.ts
│   ├── app.module.ts
│   ├── app.service.ts
│   └── main.ts
├── &lt;span class="nb"&gt;test&lt;/span&gt;
│   ├── app.e2e-spec.ts
│   └── jest-e2e.json
├── tsconfig.build.json
└── tsconfig.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuring the Nest application
&lt;/h3&gt;

&lt;p&gt;By default, the Nest listens on port 3000. There are many cases you will want the application to listen on a different port.&lt;br&gt;
Replace the line below to allow setting up the port via the &lt;code&gt;PORT&lt;/code&gt; environment variable or use the port 3000 if no environment variable is provided in the &lt;code&gt;src/main.ts&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;main.ts&lt;/code&gt; is the entry file of the application which uses the core function NestFactory to create a Nest application instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;PRISM_DELETED&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;PRISM_INSERTED&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, open and edit the &lt;code&gt;package.json&lt;/code&gt; file to specify the &lt;code&gt;npm&lt;/code&gt; and &lt;code&gt;node&lt;/code&gt; versions to use. Here we use the Node LTS version and the latest NPM version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;engines&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;14.x&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;npm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;7.x&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Push the sources to GitHub
&lt;/h2&gt;

&lt;p&gt;Once the edits are performed, we can commit and push our application to a GitHub repository. When we previously ran the &lt;code&gt;nest new nestjs-on-koyeb&lt;/code&gt; command, a git repository has been initialized so we don't need to run &lt;code&gt;git init&lt;/code&gt; inside our application directory.&lt;/p&gt;

&lt;p&gt;Add the Nest application sources:&lt;br&gt;
&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 "Nest app initial commit"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add a new remote pointing to your GitHub repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git remote add origin git@github.com:&amp;lt;YOUR_GITHUB_USERNAME&amp;gt;/&amp;lt;YOUR_GITHUB_REPOSITORY&amp;gt;.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rename the repository default branch to &lt;code&gt;main&lt;/code&gt; running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git branch -M main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Push your changes to the GitHub repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push -u origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deploy the Nest app on Koyeb
&lt;/h2&gt;

&lt;p&gt;On the &lt;a href="////app.koyeb.com/apps"&gt;Koyeb Control Panel&lt;/a&gt;, click the &lt;strong&gt;Create App&lt;/strong&gt; button. You land on the App creation page.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select &lt;code&gt;GitHub&lt;/code&gt; as the deployment method to use&lt;/li&gt;
&lt;li&gt;In the repositories selector, select the repository containing your Nest application sources&lt;/li&gt;
&lt;li&gt;Specify the branch to deploy, in my case I will deploy the &lt;code&gt;main&lt;/code&gt; branch.&lt;/li&gt;
&lt;li&gt;To let Koyeb how to launch the Nest application, add &lt;code&gt;npm run start:prod&lt;/code&gt; as the run command. This will launch the application in production mode.&lt;/li&gt;
&lt;li&gt;In the environment variables section, add a new entry with the name &lt;code&gt;NODE_ENV&lt;/code&gt; and &lt;code&gt;production&lt;/code&gt; as value.&lt;/li&gt;
&lt;li&gt;Then, give your App a name, i.e &lt;code&gt;koyeb-nestjs-demo&lt;/code&gt;, and click &lt;strong&gt;Create App.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You land on the deployment page where you can follow the build of your Nest application. Once the build is completed, your application is being deployed and you will be able to access it via &lt;code&gt;&amp;lt;APP_NAME&amp;gt;.&amp;lt;ORG_NAME&amp;gt;.koyeb.app&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you want to learn about how Koyeb automatically builds your applications from git, make sure to read our &lt;a href="////koyeb.com/docs/apps/build-from-git"&gt;how we build from git&lt;/a&gt; documentation.&lt;/p&gt;

&lt;p&gt;In this guide, we showcased how Koyeb simplifies the deployment of a NestJS application. With minimal effort, you have a complete, production-ready environment with native global load-balancing, TLS encryption, autoscaling, autohealing, and more to run your Nest application.&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Continuously deploy a Flask App using Gunicorn on Koyeb</title>
      <dc:creator>Edouard Bonlieu</dc:creator>
      <pubDate>Mon, 18 Oct 2021 12:26:10 +0000</pubDate>
      <link>https://forem.com/koyeb/continuously-deploy-a-flask-app-using-gunicorn-on-koyeb-5065</link>
      <guid>https://forem.com/koyeb/continuously-deploy-a-flask-app-using-gunicorn-on-koyeb-5065</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Flask is a lightweight web framework written in Python that offers developers powerful tools and features to create web applications with ease and flexibility. &lt;/p&gt;

&lt;p&gt;This guide demonstrates how to deploy a Flask application using Gunicorn on the Koyeb Severless Platform. You will create a "Hello World" Flask application, push your code to a GitHub repository, and then deploy your application on the Koyeb platform using its git-driven deployment.&lt;/p&gt;

&lt;p&gt;With Koyeb's git-driven deployment, your application benefits from a built-in continuous deployment pipeline because each git push you make to your repository automatically triggers a new build and deployment for your application on the Koyeb Serverless Platform. &lt;/p&gt;

&lt;p&gt;For those who prefer deploying Docker containers, we also published a guide explaining how to dockerize and deploy a &lt;a href="https://www.koyeb.com/tutorials/python-flask-application-deployment-on-koyeb"&gt;Python Flask application on the Koyeb Serverless Platform&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;To successfully follow and complete this guide, you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;a href="////app.koyeb.com/auth/signin"&gt;&lt;strong&gt;Koyeb account&lt;/strong&gt;&lt;/a&gt; to deploy and run your Python Flask application&lt;/li&gt;
&lt;li&gt;
&lt;a href="////www.python.org/downloads/"&gt;&lt;strong&gt;Python&lt;/strong&gt;&lt;/a&gt; installed on your computer&lt;/li&gt;
&lt;li&gt;A &lt;a href="////github.com/"&gt;&lt;strong&gt;GitHub account&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;To successfully create and deploy Flask application on Koyeb using git-driven deployment, you will need to follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a Flask application&lt;/li&gt;
&lt;li&gt;Deploy the Flask application on Koyeb&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Create a Flask application
&lt;/h2&gt;

&lt;p&gt;Begin by creating a directory where our application will live and moving into it by running the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir flask-on-koyeb
cd flask-on-koyeb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create a virtual environment
&lt;/h3&gt;

&lt;p&gt;Next, we will create a virtual environment, also known as virtualenv. Virtual environments allow you to create an isolated Python environment to avoid interfering with Python's system packages or other virtual environments.&lt;/p&gt;

&lt;p&gt;To create a virtual environment, execute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 -m venv ~/.venv/flask-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command creates a new directory &lt;code&gt;flask-app&lt;/code&gt; in the ~/.venv directory. The virtualenv contains a copy of the Python interpreter, pip, the standard library, and various supporting files.&lt;/p&gt;

&lt;p&gt;To activate the virtualenv we just created, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;source ~/.venv/flask-app/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The virtualenv python and pip executables are now added into your shell’s PATH.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install Dependencies
&lt;/h3&gt;

&lt;p&gt;Next, install the dependencies required to run the application. In this case, we need Flask and Gunicorn. Flask is the lightweight Python framework we are using for this application and Gunicorn is a web server gateway interface (WSGI) server implementation used to run Python web apps. Gunicorn is a high-performing server better suited for production traffic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install Flask Gunicorn # Install Flask and Gunicorn
pip freeze &amp;gt; requirements.txt # Create the requirements.txt to store the dependencies and version of each package required to run our application.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create the Flask application
&lt;/h3&gt;

&lt;p&gt;In your &lt;code&gt;flask-on-koyeb&lt;/code&gt; directory, create a new &lt;code&gt;app.py&lt;/code&gt; file with 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;from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'

if __name__ == "__main__":
    app.run()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This file is storing our Flask application code. In the snipper above, we define a route to handle &lt;code&gt;/&lt;/code&gt; requests and return &lt;code&gt;Hello, World!&lt;/code&gt; as a response.&lt;/p&gt;

&lt;p&gt;Check to see if the application is working locally by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 app.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your browser, go to &lt;code&gt;http://localhost:5000&lt;/code&gt; and you will see &lt;code&gt;Hello, World!&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a git directory for the Flask application
&lt;/h2&gt;

&lt;p&gt;Now that we have created our Flask application, we will create a git directory to store it.&lt;/p&gt;

&lt;p&gt;Initialize a new git directory for your Flask project by running the following in your terminal:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;To keep only the necessary files in the repository, add this .gitignore file to exclude unnecessary files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl https://raw.githubusercontent.com/github/gitignore/master/Python.gitignore &amp;gt; .gitignore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, execute the following command to add your files and commit the changes to your repository:&lt;br&gt;
&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 "Flask app initial commit"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open a new tab in your browser and go to GitHub. Create a new repository named &lt;code&gt;flask-on-koyeb&lt;/code&gt; and click the &lt;em&gt;Create repository&lt;/em&gt; button. Then, go back to your terminal and add GitHub as a remote repository by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git remote add origin git@github.com:YOUR_GITHUB_USERNAME/flask-on-koyeb.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rename the repository default branch to main executing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git branch -M main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, push your changes to the GitHub repository by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push -u origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you are ready to deploy your application on Koyeb.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy the Flask application on Koyeb
&lt;/h2&gt;

&lt;p&gt;On the &lt;a href="////app.koyeb.com/apps"&gt;Koyeb Control Panel&lt;/a&gt;, click the &lt;strong&gt;Create App&lt;/strong&gt; button.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the form, select &lt;code&gt;GitHub&lt;/code&gt; as your deployment method.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;&lt;em&gt;Repository&lt;/em&gt;&lt;/strong&gt;, select your repository and specify the &lt;strong&gt;&lt;em&gt;Branch&lt;/em&gt;&lt;/strong&gt;. For this demo, put &lt;code&gt;Main&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Specify &lt;code&gt;gunicorn app:app&lt;/code&gt; for your &lt;strong&gt;&lt;em&gt;Run command&lt;/em&gt;&lt;/strong&gt; to let Koyeb know how to launch your application.&lt;/li&gt;
&lt;li&gt;Then, give your App a name, i.e &lt;code&gt;koyeb-flask-demo&lt;/code&gt;, and click &lt;strong&gt;Create App.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Note: You can add more regions, change the instance size, set environment variables, and define horizontal scaling according to your needs.&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You land on the deployment page of your service where you can follow the progress of your Flask application's deployment. Koyeb will take care to build and deploy your application. Once these steps are completed, you can access your application by clicking your App URL ending with koyeb.app in the Koyeb control panel.&lt;/p&gt;

&lt;p&gt;If you want to learn about how Koyeb automatically builds your applications from git, make sure to read our &lt;a href="https://koyeb.com/docs/apps/build-from-git"&gt;how we build from git&lt;/a&gt; documentation.&lt;/p&gt;

&lt;p&gt;Your Flask application is now running on Koyeb and benefits from native autoscaling, automatic HTTPS (SSL), auto-healing, and global load-balancing across our edge network.&lt;/p&gt;

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

&lt;p&gt;In this guide, you learned how to deploy a Flask application on Koyeb and benefit from its built-in continuous deployment pipeline. Each change you push to your repository will automatically trigger a new build and deployment on the Koyeb Serverless Platform. Your changes then go live as soon as the deployment passes all necessary health checks. In case of a failure during one of your deployments, we ensure to keep the latest working deployment active so your application is always up and running.&lt;/p&gt;

&lt;p&gt;Other great benefits to deploying your Python Flask application on Koyeb include the platform's built-in autoscaling, automatic HTTPS (SSL), high availability, global load-balancing and edge network.&lt;/p&gt;

&lt;p&gt;All of these features and more work out-of-the-box and from the getgo. You focus on your code while Koyeb handles all the necessary underlying infrastructure to keep your services scalable, high performing and available.&lt;/p&gt;

&lt;p&gt;Give Koyeb a try with your application! If you have any questions or suggestions to improve this guide, feel free to reach out to us on &lt;a href="////slack.koyeb.com"&gt;Slack&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>python</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to Deploy a Python Django Application using PlanetScale and Koyeb Serverless Platform</title>
      <dc:creator>Edouard Bonlieu</dc:creator>
      <pubDate>Fri, 10 Sep 2021 07:17:52 +0000</pubDate>
      <link>https://forem.com/koyeb/how-to-deploy-a-python-django-application-using-planetscale-and-koyeb-serverless-platform-2ffg</link>
      <guid>https://forem.com/koyeb/how-to-deploy-a-python-django-application-using-planetscale-and-koyeb-serverless-platform-2ffg</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Django is a popular and powerful framework for Python application developers. Django comes with many features like authentication, content administration, an Object-Relational Mapper (ORM), and much more.&lt;br&gt;
Django supports various relational databases including MySQL which makes it possible to run a Django application using the PlanetScale database serverless platform without having to perform any changes in your application.&lt;/p&gt;

&lt;p&gt;In this guide, we will create a Django application, configure our project to use a PlanetScale database, and deploy the application on the Koyeb Serverless Platform using git-driven deployment.&lt;/p&gt;

&lt;p&gt;Using Koyeb git-driven deployment, your Koyeb application is linked to your GitHub repository and each time changes are pushed to your repository, your application is being redeployed automatically by Koyeb.&lt;/p&gt;

&lt;p&gt;At the end of this guide, you will have a working Django application running on Koyeb.&lt;/p&gt;
&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;To successfully deploy a Django application on Koyeb, you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python installed on your machine&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://app.koyeb.com"&gt;Koyeb account&lt;/a&gt; to deploy and run the Django application&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://planetscale.com"&gt;PlanetScale account&lt;/a&gt; to run the database our application will use&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://github.com/"&gt;GitHub account&lt;/a&gt; to store your application code and deploy your application on Koyeb via GitHub&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Steps
&lt;/h2&gt;

&lt;p&gt;To complete this guide to have a Django application running on Koyeb, you need to follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Create a virtual environment&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Create a new Django application&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Configure Django to use a PlanetScale database&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deploy the Django application on Koyeb&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Create a virtual environment
&lt;/h2&gt;

&lt;p&gt;Before creating the Django application, we will create a virtual environment also known as a virtualenv. Virtual environments allow you&lt;br&gt;
to create an isolated Python environment to avoid interfering with the Python's system packages or other virtual environments.&lt;/p&gt;

&lt;p&gt;To create a new virtual environment that we will use for our Django application, in your terminal run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv ~/.venv/django-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command creates a new folder &lt;code&gt;django-app&lt;/code&gt; in the &lt;code&gt;~/.venv&lt;/code&gt; directory. The virtualenv contains a copy of the Python interpreter, pip, the standard library, and various supporting files.&lt;/p&gt;

&lt;p&gt;We can now activate the virtualenv we previously created by running:&lt;br&gt;
&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;source&lt;/span&gt; ~/.venv/django-app/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the virtualenv is activated, the virtualenv python and pip executables are added into your shell’s PATH.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a new Django application
&lt;/h2&gt;

&lt;p&gt;Let's start by creating a dedicated folder for our app and moving into it:&lt;br&gt;
&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;mkdir &lt;/span&gt;django-on-koyeb
&lt;span class="nb"&gt;cd &lt;/span&gt;django-on-koyeb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before creating our Django application, we need to install:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;django, to install the Django framework and libraries&lt;/li&gt;
&lt;li&gt;dj-database-url, a Django utility that allows to parse DATABASE_URL.&lt;/li&gt;
&lt;li&gt;gunicorn, a pure-Python HTTP server for WSGI applications that can run multiple Python concurrent processes&lt;/li&gt;
&lt;li&gt;mysqlclient, the librairies to use MySQL or in our case Planetscale&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;mysqlclient requires system librairies, please check&lt;br&gt;
&lt;a href="https://pypi.org/project/mysqlclient/"&gt;https://pypi.org/project/mysqlclient/&lt;/a&gt; for detailled instructions&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In your terminal, execute the following commands to install the packages locally and save&lt;br&gt;
these dependencies.&lt;br&gt;
&lt;/p&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;django gunicorn dj_database_url mysqlclient
pip freeze &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the previous step is completed, you can create the Django application in&lt;br&gt;
our local directory by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;django-admin startproject django_on_koyeb ./
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command creates a &lt;code&gt;django_on_koyeb&lt;/code&gt; directory in your current directory containing the following files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;├── django_on_koyeb
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── manage.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Prepare the Django application for production
&lt;/h3&gt;

&lt;p&gt;Next, we will edit the &lt;code&gt;settings.py&lt;/code&gt; file as we need to customize settings&lt;br&gt;
related to security and performance for&lt;br&gt;
our development and production environment.&lt;/p&gt;

&lt;p&gt;Open the &lt;code&gt;settings.py&lt;/code&gt; using your favorite editor, here nano:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano django_on_koyeb/settings.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will edit the &lt;code&gt;settings.py&lt;/code&gt; file to load some important settings of our application using environment variables.&lt;br&gt;
To access and read environment variables, we need to import the &lt;code&gt;os&lt;/code&gt; module.&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;+&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Django also requires a &lt;code&gt;SECRET_KEY&lt;/code&gt;. This key is used to provide cryptographic signing and should be set to a unique, unpredictable value.&lt;br&gt;
By default, we will want to generate a random secret key when nothing is passed as an environment variable, i.e. when you are running in development mode.&lt;/p&gt;

&lt;p&gt;To generate a random secret key, we will need to import &lt;code&gt;from django.core.management.utils import get_random_secret_key&lt;/code&gt;:&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="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.core.management.utils&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_random_secret_key&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Search for the &lt;code&gt;SECRET_KEY = ...&lt;/code&gt; line in the &lt;code&gt;settings.py&lt;/code&gt; file and replace it as below:&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="n"&gt;SECRET_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'DJANGO_SECRET_KEY'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;get_random_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;Now, when the &lt;code&gt;DJANGO_SECRET_KEY&lt;/code&gt; environment variable is set, our application will use it. If no value is provided, the &lt;code&gt;get_random_secret_key()&lt;/code&gt; function is called and will return a random secret key.&lt;/p&gt;

&lt;p&gt;By default, the Django application runs in &lt;code&gt;DEBUG&lt;/code&gt;. When deploying the application in production, for security and performance purposes &lt;code&gt;DEBUG&lt;/code&gt; mode needs to be disabled. We will change the default value to disable DEBUG until it is explicitly enabled via the environment variable &lt;code&gt;DJANGO_DEBUG=True&lt;/code&gt;.&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="n"&gt;DEBUG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'DJANGO_DEBUG'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'False'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'True'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, update the &lt;code&gt;ALLOWED_HOSTS&lt;/code&gt; directive to read the &lt;code&gt;DJANGO_ALLOWED_HOSTS&lt;/code&gt; from the environment. &lt;code&gt;ALLOWED_HOSTS&lt;/code&gt; is required to contain the list of strings representing the host/domain names that the Django application can serve.&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="n"&gt;ALLOWED_HOSTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DJANGO_ALLOWED_HOSTS"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"localhost,127.0.0.1"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Last, go to the bottom of the file and add the following directive below &lt;code&gt;STATIC_URL&lt;/code&gt;:&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="n"&gt;STATIC_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'/static/'&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;STATIC_ROOT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BASE_DIR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"staticfiles"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This setting is used to set the directory from which we want to serve static files.&lt;br&gt;
The first part of the Django configuration is done, we can move to the next step and configure Django to use a PlanetScale database.&lt;/p&gt;
&lt;h2&gt;
  
  
  Configure Django to use a PlanetScale database
&lt;/h2&gt;

&lt;p&gt;To use a PlanetScale database in our Django application, create a new database&lt;br&gt;
from the PlanetScale &lt;a href="https://app.planetscale.com/"&gt;control panel&lt;/a&gt; or using the&lt;br&gt;
&lt;a href="https://github.com/planetscale/cli#installation"&gt;CLI&lt;/a&gt; running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pscale database create django-on-koyeb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the database is created, create a new database password for the main branch. On the PlanetScale control panel, click the &lt;strong&gt;Connect&lt;/strong&gt; button and new password to generate a user and password to connect the database.&lt;br&gt;
You can also perform this action using the PlanetScale CLI by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pscale password create django-on-koyeb main production-password
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep these credentials in a safe place, we will need them when deploying our application on Koyeb.&lt;/p&gt;

&lt;p&gt;On PlanetScale, the main database's schema is immutable and all changes must occur on a development branch. As we will need to perform a migration propagate our models into our PlanetScale database,&lt;br&gt;
we need to create a new branch.&lt;/p&gt;

&lt;p&gt;On the PlanetScale control panel, click the &lt;strong&gt;New branch&lt;/strong&gt; button and name the branch migration. You can also perform this operation using the PlanetScale CLI running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pscale branch create django-on-koyeb migration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the branch is created, create a new database password to access the branch. On the PlanetScale control panel, click the &lt;strong&gt;Connect&lt;/strong&gt; button and new password to generate a user and password to connect the database.&lt;br&gt;
You can also perform this action using the PlanetScale CLI by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pscale password create django-on-koyeb migration migration-branch-password
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As PlanetScale uses Vitess behind the scenes, we need to use a custom database engine to make our Django application work with Vitess.&lt;br&gt;
To retrieve the Vitess custom engine, clone the Vitess repository and copy the &lt;code&gt;custom_db_backends&lt;/code&gt; directory in your Django application root folder:&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/vitessio/vitess.git ~/vitess
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; ~/vitess/support/django/custom_db_backends ./
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, open the Django application &lt;code&gt;settings.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano django_on_koyeb/settings.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, Django is using an SQLite database, we need to edit the&lt;br&gt;
&lt;code&gt;settings.py&lt;/code&gt; to use a Vitess database and retrieve the configuration via the &lt;code&gt;DJANGO_DATABASE_URL&lt;/code&gt; environment variable.&lt;br&gt;
If the &lt;code&gt;DJANGO_DATABASE_URL&lt;/code&gt; is not set, the application will raise the exception &lt;code&gt;DJANGO_DATABASE_URL environment variable not defined&lt;/code&gt; when starting.&lt;br&gt;
In the &lt;code&gt;settings.py&lt;/code&gt; replace the following part:&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;# DATABASES = {
#     'default': {
#         'ENGINE': 'django.db.backends.sqlite3',
#         'NAME': BASE_DIR / 'db.sqlite3',
#     }
# }
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DJANGO_DATABASE_URL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DJANGO_DATABASE_URL environment variable not defined"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;DB_PARAMS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dj_database_url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DJANGO_DATABASE_URL"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;DB_PARAMS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"ENGINE"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"custom_db_backends.vitess"&lt;/span&gt;
&lt;span class="n"&gt;DATABASES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DB_PARAMS&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;Let's not forget to import the &lt;code&gt;dj_database_url&lt;/code&gt; module we're using:&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="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.core.management.utils&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_random_secret_key&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;dj_database_url&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now save and close the &lt;code&gt;settings.py&lt;/code&gt;. Let's run Django migration to propagate the application models to the PlanetScale database. In the terminal run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;DJANGO_DATABASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;mysql://PS_USERNAME:PS_PASSWORD@PS_HOST:3306 python manage.py migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace the &lt;code&gt;PS_USERNAME&lt;/code&gt;, &lt;code&gt;PS_PASSWORD&lt;/code&gt;, &lt;code&gt;PS_HOST&lt;/code&gt; values with the PlanetScale values you generated for the &lt;code&gt;migration&lt;/code&gt; branch.&lt;/p&gt;

&lt;p&gt;Then on the PlanetScale control panel, create a new &lt;strong&gt;Deploy request&lt;/strong&gt; to propagate the schema changes performed on the &lt;code&gt;migration&lt;/code&gt; branch to the production branch &lt;code&gt;main&lt;/code&gt; and deploy it. You can also perform this operation using the PlanetScale CLI by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pscale deploy-request create django-on-koyeb migration
pscale deploy-request deploy django-on-koyeb 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application is now configured and ready to be deployed on Koyeb.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy the Django application on Koyeb
&lt;/h2&gt;

&lt;p&gt;As the Django application will be deployed on Koyeb using Git, we need to initialize a new git directory for our Django project.&lt;br&gt;
In your terminal run:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;To keep only necessary files in our repository, we will add a &lt;code&gt;.gitignore&lt;/code&gt; file to exclude undesired files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://raw.githubusercontent.com/github/gitignore/master/Python.gitignore &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .gitignore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, execute the following command to add files to commit to your repository and commit the changes&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Django app initial commit"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open a new tab in your browser and go to &lt;a href="https://github.com/"&gt;GitHub&lt;/a&gt;. Create a new repository named &lt;code&gt;django-on-koyeb&lt;/code&gt; and click the &lt;strong&gt;Create repository&lt;/strong&gt; button.&lt;br&gt;
Then, go back to your terminal and add GitHub as a remote repository by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote add origin git@github.com:YOUR_GITHUB_USERNAME/django-on-koyeb.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rename the repository default branch to main executing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git branch &lt;span class="nt"&gt;-M&lt;/span&gt; main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Last, push your changes to the GitHub repository by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything is now ready to deploy the Django application on Koyeb.&lt;/p&gt;

&lt;p&gt;Go to the Koyeb &lt;a href="https://app.koyeb.com"&gt;control panel&lt;/a&gt; and click the &lt;strong&gt;Create App&lt;/strong&gt; button.&lt;br&gt;
Choose GitHub as a deployment method and choose the repository you previously created in the list and set &lt;code&gt;main&lt;/code&gt; as the branch value.&lt;/p&gt;

&lt;p&gt;Override the default &lt;strong&gt;Run command&lt;/strong&gt; with the following value to get the application to run properly: &lt;code&gt;gunicorn --worker-tmp-dir /dev/shm django_on_koyeb.wsgi&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then, in the &lt;strong&gt;Ports&lt;/strong&gt; section change the default port from 80 to 8000 which is the default port our application is listening to.&lt;/p&gt;

&lt;p&gt;In the &lt;strong&gt;Environment variables&lt;/strong&gt; section:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add an environment variable of type &lt;strong&gt;Secret&lt;/strong&gt; with &lt;code&gt;DJANGO_DATABASE_URL&lt;/code&gt; as the value and in the value section click &lt;strong&gt;Create Secret&lt;/strong&gt; and name your Secret &lt;code&gt;django-db-url&lt;/code&gt; and &lt;code&gt;mysql://PS_USERNAME:PS_PASSWORD@PS_HOST:3306&lt;/code&gt; as value. Take care to replace PS_USERNAME, PS_PASSWORD, and PS_HOST with the PlanetScale password information you created for your main production branch.&lt;/li&gt;
&lt;li&gt;Create a plaintext environment variable with the name &lt;code&gt;DJANGO_DEBUG&lt;/code&gt; and value set to &lt;code&gt;True&lt;/code&gt;. We need this to validate our application is running properly as it doesn't contain any routes at the moment.&lt;/li&gt;
&lt;li&gt;Create a plaintext environment variable with the name &lt;code&gt;DJANGO_ALLOWED_HOSTS&lt;/code&gt;
and value set to &lt;code&gt;django-on-koyeb-&amp;lt;KOYEB-ORG&amp;gt;.koyeb.app&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Give your App a name, for instance &lt;code&gt;django-on-koyeb&lt;/code&gt; and click the &lt;strong&gt;Create App&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;Your application is now being built and deployed on the Koyeb serverless platform. Within a few minutes, you will be able to access your application by clicking your App URL: &lt;code&gt;https://django-on-koyeb-&amp;lt;KOYEB-ORG&amp;gt;.koyeb.app&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;In this guide, we explained how to deploy a Django application on the Koyeb serverless platform with PlanetScale as the database backend for our application.&lt;br&gt;
By deploying on Koyeb, your Django application is secured with native TLS encryption and benefits from all the Koyeb serverless features including autoscaling, auto-healing, and a high-performance edge network.&lt;/p&gt;

&lt;p&gt;Thanks to the git-driven deployment feature offered by Koyeb, each time you push new modifications to your GitHub repository, a new deployment of your application occurs automatically.&lt;br&gt;
This allows you to focus on your application code while Koyeb takes care of building, deploying your application, and ensure your service is always up and running.&lt;/p&gt;

&lt;p&gt;If you have any questions or suggestions to improve this guide,&lt;br&gt;
feel free to reach out to us on &lt;a href="https://slack.koyeb.com"&gt;Slack&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>tutorial</category>
      <category>django</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Dockerize, Deploy and Run a Ruby on Rails application on Koyeb</title>
      <dc:creator>Edouard Bonlieu</dc:creator>
      <pubDate>Fri, 27 Aug 2021 07:10:57 +0000</pubDate>
      <link>https://forem.com/koyeb/dockerize-deploy-and-run-a-ruby-on-rails-application-on-koyeb-3ih</link>
      <guid>https://forem.com/koyeb/dockerize-deploy-and-run-a-ruby-on-rails-application-on-koyeb-3ih</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Ruby on Rails, or Rails, is a popular, server-side model-view-controller (MVC) web framework written in Ruby.&lt;br&gt;
Rails provides all the features you need to build and maintain a modern web application.&lt;/p&gt;

&lt;p&gt;Rails follows the convention over configuration philosophy meaning you write less code, and don't have to deal with tons of configuration files so you can focus on your application logic.&lt;/p&gt;

&lt;p&gt;In this documentation, we will explain how to dockerize, deploy and run a Ruby on Rails application on the Koyeb serverless platform. By running your application on Koyeb, you natively benefit from&lt;br&gt;
autoscaling, autohealing, TSL encryption, a Global Edge Network CDN, and more.&lt;/p&gt;

&lt;p&gt;At the end of this guide, you will have a working Rails application containerized and running on Koyeb.&lt;/p&gt;
&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;To successfully dockerize and run your Rails application on Koyeb, you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rails installed on your machine&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.docker.com/get-docker/"&gt;Docker&lt;/a&gt; installed on your machine&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://app.koyeb.com"&gt;Koyeb account&lt;/a&gt; to deploy and run the Rails application&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://www.koyeb.com/docs/cli/installation"&gt;Koyeb CLI&lt;/a&gt; installed to interact with Koyeb from the command line&lt;/li&gt;
&lt;li&gt;A registry that we will use to store our Rails web app Docker image and deploy it on Koyeb&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Steps
&lt;/h2&gt;

&lt;p&gt;To successfully complete this guide to have a Rails application containerized and running on Koyeb, you need to follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Create a new Rails application&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dockerize the Rails application&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Push the Docker image to a container registry&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deploy the Dockerized Rails app on Koyeb&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Create a new Rails application
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;If you already have an existing Rails application that you want to dockerize and deploy on Koyeb, you can jump to the next step.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To get started, we will create a basic Rails application using the new application generator. The command we will execute creates all the foundation of a fresh Rails application so that you don't have to write it yourself.&lt;/p&gt;

&lt;p&gt;In your terminal, run the following command to create a new Rails application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails new demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command creates a demo directory and installs all the dependencies required to run the application. Once the initialization is done, go to the demo directory and add a new route to the router file &lt;code&gt;config/routes.rb&lt;/code&gt; to handle request on &lt;code&gt;/&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;draw&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="s1"&gt;'hello_world#index'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The route above is used to indicate GET / requests are mapped to the index action of HelloWorldController.&lt;br&gt;
To create the HelloWorldController and its index action, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails generate controller HelloWorld index &lt;span class="nt"&gt;--skip-routes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we pass the &lt;code&gt;--skip-routes&lt;/code&gt; as we don't want to generate a route for this controler as we previously manually created one.&lt;br&gt;
Now, you can launch the development server running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$rails&lt;/span&gt; server
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; Booting Puma
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; Rails 6.1.4 application starting &lt;span class="k"&gt;in &lt;/span&gt;development
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; Run &lt;span class="sb"&gt;`&lt;/span&gt;bin/rails server &lt;span class="nt"&gt;--help&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;more startup options
Puma starting &lt;span class="k"&gt;in &lt;/span&gt;single mode...
&lt;span class="k"&gt;*&lt;/span&gt; Puma version: 5.4.0 &lt;span class="o"&gt;(&lt;/span&gt;ruby 2.6.1-p33&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Super Flight"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;*&lt;/span&gt;  Min threads: 5
&lt;span class="k"&gt;*&lt;/span&gt;  Max threads: 5
&lt;span class="k"&gt;*&lt;/span&gt;  Environment: development
&lt;span class="k"&gt;*&lt;/span&gt;          PID: 28869
&lt;span class="k"&gt;*&lt;/span&gt; Listening on http://127.0.0.1:3000
&lt;span class="k"&gt;*&lt;/span&gt; Listening on http://[::1]:3000
Use Ctrl-C to stop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Request on &lt;code&gt;/&lt;/code&gt; will be handled by our HelloWorld controller. You can open a browser window and navigate to the &lt;code&gt;http://localhost:3000&lt;/code&gt; URL. You land on the HelloWorld application page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dockerize the Rails application
&lt;/h2&gt;

&lt;p&gt;To Dockerize the Rails application, create a &lt;code&gt;Dockerfile&lt;/code&gt; in your project root directory and copy the content below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; ruby:3-alpine&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apk add &lt;span class="nt"&gt;--no-cache&lt;/span&gt; build-base tzdata nodejs yarn sqlite-dev postgresql-dev mysql-dev
&lt;span class="k"&gt;RUN &lt;/span&gt;gem &lt;span class="nb"&gt;install &lt;/span&gt;bundler
&lt;span class="k"&gt;RUN &lt;/span&gt;bundle &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; RAILS_ENV=production&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;bundle &lt;span class="nb"&gt;exec &lt;/span&gt;rails assets:precompile
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 3000&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["rails", "server", "-b", "0.0.0.0"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Build the Docker image by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; ghcr.io/&amp;lt;GITHUB_USERNAME&amp;gt;/rails-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;In this guide we will push the Docker image to the GitHub container registry. You are free to use another registry as Koyeb allows you to deploy from any container registry.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once the build is finished, you can run a container locally with the image to validate everything is working as expected using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 3000:3000 ghcr.io/&amp;lt;GITHUB_USERNAME&amp;gt;/rails-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your container should start and you can test the routes using curl:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl localhost:3000/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Push the Docker image to a container registry
&lt;/h2&gt;

&lt;p&gt;Now that the Docker image is built and working properly, we can push it to a container registry. In this guide we will use the GitHub container registry. In your terminal run the command below to push the image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker push ghcr.io/&amp;lt;GITHUB_USERNAME&amp;gt;/rails-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your Docker image is now available on the GitHub container registry: &lt;code&gt;https://github.com/&amp;lt;YOUR_GITHUB_USERNAME&amp;gt;?tab=packages&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy the Dockerized Rails web app on Koyeb
&lt;/h2&gt;

&lt;p&gt;You can now deploy the dockerized Rails application on Koyeb. This section explains how to deploy on the Koyeb serverless platform using the CLI. This operation can also be performed using the &lt;a href="https://app.koyeb.com"&gt;control panel&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First, we need to create a Koyeb Secret containing the GitHub container registry configuration to deploy private images. In your terminal execute the following command and replace &lt;code&gt;&amp;lt;REPLACE_ME_WITH_GH_USERNAME&amp;gt;&lt;/code&gt; with your GitHub username and &lt;code&gt;&amp;lt;REPLACE_ME_WITH_GH_TOKEN&amp;gt;&lt;/code&gt; with a valid GitHub token having registry read/write permissions and execute the command below.&lt;br&gt;
&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;echo&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s1"&gt;'{
  "auths": {
    "ghcr.io": {
      "username": "&amp;lt;GITHUB_USERNAME&amp;gt;",
      "password": "&amp;lt;GITHUB_TOKEN&amp;gt;"
    }
  }
}'&lt;/span&gt; | koyeb secrets create docker-hub-credentials &lt;span class="nt"&gt;--value-from-stdin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now deploy the Rails application on Koyeb Serverless Platform running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;koyeb app init rails-app &lt;span class="nt"&gt;--docker&lt;/span&gt; &lt;span class="s2"&gt;"ghcr.io/&amp;lt;REPLACE_ME_WITH_GH_USERNAME&amp;gt;/rails-app"&lt;/span&gt; &lt;span class="nt"&gt;--ports&lt;/span&gt; 3000:http &lt;span class="nt"&gt;--routes&lt;/span&gt; /:3000 &lt;span class="nt"&gt;--docker-private-registry-secret&lt;/span&gt; gh-registry-credentials
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Within a few minutes, your application will be live and accessible at &lt;code&gt;https://rails-app-&amp;lt;KOYEB-ORG&amp;gt;.koyeb.app&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;In this guide, we explained how to containerize, deploy and run a Rails application on Koyeb.&lt;br&gt;
By deploying on Koyeb, your Rails application is secured with native TLS encryption and benefits from all the Koyeb serverless features including autoscaling, auto-healing, and a high-performance edge network.&lt;/p&gt;

&lt;p&gt;If you have any questions or suggestions to improve this guide,&lt;br&gt;
feel free to reach out to us on &lt;a href="https://slack.koyeb.com"&gt;Slack&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>ruby</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Deploy a RESTful Go API with Gin on Koyeb</title>
      <dc:creator>Edouard Bonlieu</dc:creator>
      <pubDate>Tue, 24 Aug 2021 16:09:12 +0000</pubDate>
      <link>https://forem.com/koyeb/deploy-a-restful-go-api-with-gin-on-koyeb-lfl</link>
      <guid>https://forem.com/koyeb/deploy-a-restful-go-api-with-gin-on-koyeb-lfl</guid>
      <description>&lt;p&gt;In this guide, we will explain how to build and deploy a Go API using the Gin framework on the Koyeb serverless platform.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/gin-gonic/gin"&gt;Gin&lt;/a&gt; is a web framework written in Go focusing on performance. It provides an elegant way to write web applications and microservices and comes with a set of commonly used primitives like routing, middleware, rendering, and more.&lt;/p&gt;

&lt;p&gt;By deploying your application on Koyeb, you benefit from powerful primitives including native autoscaling, automatic HTTPS (SSL), auto-healing, and global load-balancing across our edge network with zero configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;To successfully follow and complete this guide, you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Go programming language installed&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.docker.com/get-docker/"&gt;Docker&lt;/a&gt; installed on your machine&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://app.koyeb.com"&gt;Koyeb account&lt;/a&gt; to deploy and run the Go web API&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://www.koyeb.com/docs/cli/installation"&gt;Koyeb CLI&lt;/a&gt; installed to interact with Koyeb from the command line&lt;/li&gt;
&lt;li&gt;Have a registry that we will use to store our Go web app Docker image and deploy it on Koyeb&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;To successfully complete this guide and deploy the Go API on Koyeb, you need to follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Building the Go API using Gin&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dockerize the Go application&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deploy the Dockerized Go API on Koyeb&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Building the Go API using Gin
&lt;/h2&gt;

&lt;p&gt;First, let's get started by creating a new directory in your &lt;a href="https://golang.org/doc/gopath_code#GOPATH"&gt;GOPATH&lt;/a&gt; to build our sample application:&lt;br&gt;
&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;mkdir&lt;/span&gt; &lt;span class="nv"&gt;$GOPATH&lt;/span&gt;/src/go-demo
&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;$GOPATH&lt;/span&gt;/src/go-demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this guide, we name the directory &lt;code&gt;go-demo&lt;/code&gt;. You can name the folder whatever you like.&lt;/p&gt;

&lt;p&gt;Next, run &lt;code&gt;go mod init&lt;/code&gt; to create a &lt;code&gt;go.mod&lt;/code&gt; file and track your code's dependencies. As you add dependencies, the &lt;code&gt;go.mod&lt;/code&gt; file will list the versions your code depends on allowing you to keep your builds reproducible and gives you direct control over which module versions to use.&lt;/p&gt;

&lt;p&gt;In your project folder, create a new file named &lt;code&gt;server.go&lt;/code&gt; with the following content inside:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"os"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/gin-gonic/gin"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"PORT"&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;port&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"8000"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"message"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Hello, world!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/:name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"message"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, %s!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&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;The code above launch a Gin server listening on port 8000 by default with two API routes configured:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/&lt;/code&gt; returning "Hello, world!"&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/:name&lt;/code&gt; returning "Hello, :name!" where :name is the string passed in parameter, i.e /john will return "Hello, john!".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, in your terminal execute &lt;code&gt;go mod tidy&lt;/code&gt; to add missing modules required by our project and add &lt;code&gt;github.com/gin-gonic/gin&lt;/code&gt; as a project dependency.&lt;/p&gt;

&lt;p&gt;You can now run the application locally running &lt;code&gt;go run server.go&lt;/code&gt; and navigate in your browser at &lt;code&gt;http://localhost:8000&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dockerize the Go application
&lt;/h2&gt;

&lt;p&gt;To Dockerize our Go application, create a &lt;code&gt;Dockerfile&lt;/code&gt; in your project directory.&lt;br&gt;
In this guide, we use &lt;a href="https://docs.docker.com/develop/develop-images/multistage-build/"&gt;Docker multi-stage build&lt;/a&gt; to keep the image layers size as small as possible and to ensure our image contains only what is needed to run.&lt;/p&gt;

&lt;p&gt;In your Dockerfile, copy the content below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; golang:1.16-alpine AS builder&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;go mod download
&lt;span class="k"&gt;RUN &lt;/span&gt;go build &lt;span class="nt"&gt;-o&lt;/span&gt; ./go-demo ./server.go


&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; alpine:latest AS runner&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /app/go-demo .&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8000&lt;/span&gt;
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["./go-demo"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first stage is used to install dependencies and build our application, in the second one we copy the application binary from stage one and use it to run the application.&lt;/p&gt;

&lt;p&gt;To build the Docker image execute the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; &amp;lt;DOCKER_HUB_USERNAME&amp;gt;/go-demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;In this guide we will push the Docker image to the Docker Hub. You are free to use another different registry as Koyeb allows you to deploy from any container registry.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once the build is completed, you can run a container using the image locally to validate everything is working as expected running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 8000:8000 &amp;lt;DOCKER_HUB_USERNAME&amp;gt;/go-demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything goes well, your container starts properly, you can test the routes using curl:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$curl&lt;/span&gt; localhost:8000/
Hello, world!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we can push the Docker image to a container registry, in this guide, the Docker Hub using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker push &amp;lt;DOCKER_HUB_USERNAME&amp;gt;/go-demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the push command is completed, the Docker image is stored on the container registry and we can deploy it on Koyeb.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy the Dockerized Go API on Koyeb
&lt;/h2&gt;

&lt;p&gt;We are now ready to deploy our Go web application on Koyeb. First, create a Koyeb Secret to store your container registry configuration.&lt;br&gt;
In this guide, we will deploy our app from the Docker Hub. For other container registries example, check out the related &lt;a href="https://dev.to/docs/apps/private-container-registry-secrets"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: if your Docker image is public, there is no need to create a secret containing your container registry configuration.&lt;/em&gt;&lt;br&gt;
&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;echo&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s1"&gt;'{
  "auths": {
    "index.docker.io/v1/": {
      "username": "&amp;lt;REPLACE_ME_WITH_DOCKER_HUB_USERNAME&amp;gt;",
      "password": "&amp;lt;REPLACE_ME_WITH_DOCKER_HUB_TOKEN&amp;gt;"
    }
  }
}'&lt;/span&gt; | koyeb secrets create docker-hub-credentials &lt;span class="nt"&gt;--value-from-stdin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now deploy the Go web application on Koyeb Serverless Platform running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;koyeb app init go-demo &lt;span class="nt"&gt;--docker&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;REPLACE_ME_WITH_DOCKER_HUB_USERNAME&amp;gt;/go-demo"&lt;/span&gt; &lt;span class="nt"&gt;--ports&lt;/span&gt; 8000:http &lt;span class="nt"&gt;--routes&lt;/span&gt; /:8000 &lt;span class="nt"&gt;--docker-private-registry-secret&lt;/span&gt; docker-hub-credentials
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command creates a new Koyeb App and deploys our Go application exposing port 8000 and making it publicly accessible on the &lt;code&gt;/&lt;/code&gt; route of your Koyeb App URL.&lt;/p&gt;

&lt;p&gt;To retrieve your Koyeb App URL and access your application, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$koyeb&lt;/span&gt; app get go-demo
ID                                      NAME            DOMAINS                                 UPDATED AT
d58ebed1-48c0-46b7-a2f1-91f3ffdbccf2    go-demo         go-demo-&amp;lt;YOUR_ORG&amp;gt;.koyeb.app    2021-06-23 09:46:55.411403 +0000 UTC
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the URL in your browser to access your application running on Koyeb and natively offering autoscaling, automatic HTTPS (SSL), auto-healing, and global load-balancing across our edge network.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>tutorial</category>
      <category>go</category>
      <category>docker</category>
    </item>
    <item>
      <title>Dockerize and Deploy a Laravel Application to Production</title>
      <dc:creator>Edouard Bonlieu</dc:creator>
      <pubDate>Thu, 29 Jul 2021 06:23:28 +0000</pubDate>
      <link>https://forem.com/koyeb/dockerize-and-deploy-a-laravel-application-to-production-3326</link>
      <guid>https://forem.com/koyeb/dockerize-and-deploy-a-laravel-application-to-production-3326</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Laravel is a popular, simple and flexible PHP application framework.&lt;br&gt;
Laravel comes with many build features offering a great developer experience such as thorough dependency injection, an expressive database abstraction layer, queues and scheduled jobs, unit and integration testing, and more.&lt;/p&gt;

&lt;p&gt;In this guide, we will explain how to dockerize and deploy a Laravel application to production using Docker to containerize our application and deploy it to the Koyeb Serverless Platform.&lt;/p&gt;

&lt;p&gt;By deploying your Laravel application on Koyeb, you benefit from native autoscaling, autohealing, TLS encryption, global load balancing across our edge network, service discovery, and more.&lt;/p&gt;
&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;To successfully follow and complete this guide, you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.docker.com/get-docker/"&gt;Docker&lt;/a&gt; installed on your machine

&lt;ul&gt;
&lt;li&gt;A &lt;a href="https://app.koyeb.com"&gt;Koyeb account&lt;/a&gt; to deploy and run the Laravel web application&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://dev.to/docs/cli/installation"&gt;Koyeb CLI&lt;/a&gt; installed to interact with Koyeb from the command line&lt;/li&gt;
&lt;li&gt;Have a registry we will use to store our Laravel web app Docker image and deploy it on Koyeb&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Steps
&lt;/h2&gt;

&lt;p&gt;To successfully deploy a Laravel web application on the Koyeb serverless platform, you need to follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Create a new Laravel application&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dockerize the Laravel application&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Push the Docker image to a container registry&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deploy the Dockerized Laravel web app on Koyeb&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Create a new Laravel application
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;If you already have an existing Laravel application you want to dockerize and deploy on Koyeb, you can jump to the next step.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To get started, we will create a new Laravel project using Composer, a PHP package manager. In your terminal, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer create-project &lt;span class="nt"&gt;--prefer-dist&lt;/span&gt; laravel/laravel laravel-demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will create a new Laravel application in the &lt;code&gt;laravel-demo&lt;/code&gt; directory and install all the dependencies required by the app to run properly.&lt;/p&gt;

&lt;p&gt;You can launch the application in development mode by running the following command in your terminal from the &lt;code&gt;laravel-demo&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open a browser window and navigate to the &lt;code&gt;http://localhost:8000&lt;/code&gt; URL. You should see the Laravel welcome page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dockerize the Laravel application
&lt;/h2&gt;

&lt;p&gt;With our minimalistic Laravel application ready, we can now create the Dockerfile that we will use to containerize our Laravel application.&lt;/p&gt;

&lt;p&gt;We will use the &lt;code&gt;webdevops/php-nginx:7.4-alpine&lt;/code&gt; as the base image which provides Nginx with PHP-FPM installed and configured. The image can be customized depending on your needs. You can read the full documentation &lt;a href="https://dockerfile.readthedocs.io/en/latest/content/DockerImages/dockerfiles/php-nginx.html"&gt;here&lt;/a&gt;.&lt;br&gt;
In your application directory, create a new file named &lt;code&gt;Dockerfile&lt;/code&gt; and paste the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; webdevops/php-nginx:7.4-alpine&lt;/span&gt;

&lt;span class="c"&gt;# Install Laravel framework system requirements (https://laravel.com/docs/8.x/deployment#optimizing-configuration-loading)&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apk add oniguruma-dev postgresql-dev libxml2-dev
&lt;span class="k"&gt;RUN &lt;/span&gt;docker-php-ext-install &lt;span class="se"&gt;\
&lt;/span&gt;        bcmath &lt;span class="se"&gt;\
&lt;/span&gt;        ctype &lt;span class="se"&gt;\
&lt;/span&gt;        fileinfo &lt;span class="se"&gt;\
&lt;/span&gt;        json &lt;span class="se"&gt;\
&lt;/span&gt;        mbstring &lt;span class="se"&gt;\
&lt;/span&gt;        pdo_mysql &lt;span class="se"&gt;\
&lt;/span&gt;        pdo_pgsql &lt;span class="se"&gt;\
&lt;/span&gt;        tokenizer &lt;span class="se"&gt;\
&lt;/span&gt;        xml

&lt;span class="c"&gt;# Copy Composer binary from the Composer official Docker image&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=composer:latest /usr/bin/composer /usr/bin/composer&lt;/span&gt;

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; WEB_DOCUMENT_ROOT /app/public&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; APP_ENV production&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;composer &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-interaction&lt;/span&gt; &lt;span class="nt"&gt;--optimize-autoloader&lt;/span&gt; &lt;span class="nt"&gt;--no-dev&lt;/span&gt;
&lt;span class="c"&gt;# Optimizing Configuration loading&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;php artisan config:cache
&lt;span class="c"&gt;# Optimizing Route loading&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;php artisan route:cache
&lt;span class="c"&gt;# Optimizing View loading&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;php artisan route:cache

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; application:application .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you probably noticed, we don't specify the &lt;code&gt;CMD&lt;/code&gt; to tell Docker how to run our container.&lt;br&gt;
This is because the base image &lt;code&gt;FROM webdevops/php-nginx:7.4-alpine&lt;/code&gt; run the Nginx and PHP-FPM in the foreground and we inherit this command.&lt;/p&gt;

&lt;p&gt;If your application requires additional php extensions, you can install them using the &lt;code&gt;docker-php-ext-install&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In this guide we will push the Docker image to the Docker Hub. You are free to use another different registry as Koyeb allows you to deploy from any container registry.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To build the image run the following command and replace &lt;code&gt;&amp;lt;DOCKER_HUB_USERNAME&amp;gt;&lt;/code&gt; with your own.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; &amp;lt;DOCKER_HUB_USERNAME&amp;gt;/laravel-demo &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the build is complete, you can run the image locally to ensure everything is working as expected.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 9000:80 &amp;lt;DOCKER_HUB_USERNAME&amp;gt;/laravel-demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Push the Docker image to a container registry
&lt;/h2&gt;

&lt;p&gt;Now that we have our Docker image ready, we can push it to the Docker Hub by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker push &amp;lt;DOCKER_HUB_USERNAME&amp;gt;/laravel-demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the image is successfully pushed to the Docker Hub, we can use it to deploy the Laravel application on Koyeb.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy the Dockerized Laravel web app on Koyeb
&lt;/h2&gt;

&lt;p&gt;With the previous steps completed, we can now deploy our application on production to Koyeb.&lt;br&gt;
This section explains how to deploy on the Koyeb serverless platform using the CLI. This operation can also be performed using the &lt;a href="https://app.koyeb.com"&gt;control panel&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First, we need to create a Koyeb Secret containing the Docker Hub configuration to deploy private images. In your terminal execute the following command and replace &lt;code&gt;&amp;lt;DOCKER_HUB_USERNAME&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;DOCKER_HUB_TOKEN&amp;gt;&lt;/code&gt;&lt;br&gt;
with your own.&lt;br&gt;
&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;echo&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s1"&gt;'{
  "auths": {
    "index.docker.io/v1/": {
      "username": "&amp;lt;DOCKER_HUB_USERNAME&amp;gt;",
      "password": "&amp;lt;DOCKER_HUB_TOKEN&amp;gt;"
    }
  }
}'&lt;/span&gt; | koyeb secrets create docker-hub-credentials &lt;span class="nt"&gt;--value-from-stdin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now deploy the Laravel application by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;koyeb app init laravel-demo &lt;span class="nt"&gt;--docker&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;DOCKER_HUB_USERNAME&amp;gt;/laravel-demo"&lt;/span&gt; &lt;span class="nt"&gt;--docker-private-registry-secret&lt;/span&gt; docker-hub-credentials
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command creates a new Koyeb App and deploy the Laravel application using the Docker image. To retrieve your Koyeb App URL and access your application, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$koyeb&lt;/span&gt; app get laravel-demo
ID                                      NAME            DOMAINS                                 UPDATED AT
d58ebed1-48c0-46b7-a2f1-91f3ffdbcccc    laravel-demo    laravel-demo-&amp;lt;YOUR_ORG&amp;gt;.koyeb.app       2021-06-28 12:46:55.411403 +0000 UTC
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the URL in your browser to access your application running on Koyeb.&lt;/p&gt;

&lt;p&gt;This guide shows how easy it is to deploy your Laravel application in production using Docker and Koyeb.&lt;br&gt;
Thanks to Koyeb native global load balancing edge network, your content is distributed near your users and your app comes with native TLS encryption.&lt;/p&gt;

&lt;p&gt;To learn more about what Koyeb has to offer, check out the &lt;a href="https://dev.to/features"&gt;features&lt;/a&gt; page.&lt;/p&gt;

</description>
      <category>php</category>
      <category>tutorial</category>
      <category>docker</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The Koyeb Serverless Engine: from Kubernetes to Nomad, Firecracker, and Kuma</title>
      <dc:creator>Edouard Bonlieu</dc:creator>
      <pubDate>Thu, 08 Jul 2021 10:54:52 +0000</pubDate>
      <link>https://forem.com/koyeb/the-koyeb-serverless-engine-from-kubernetes-to-nomad-firecracker-and-kuma-1jh9</link>
      <guid>https://forem.com/koyeb/the-koyeb-serverless-engine-from-kubernetes-to-nomad-firecracker-and-kuma-1jh9</guid>
      <description>&lt;p&gt;At Koyeb, our mission is to provide the fastest way to deploy applications globally. We are building a platform allowing developers and businesses to easilyrun applications, a platform where you don't need to think and deal with the&lt;br&gt;
resiliency and scalability of your servers: &lt;em&gt;a serverless platform&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Ironically, a serverless platform is actually full of servers. As a cloud service provider, we operate the infrastructure for you and abstract it as much&lt;br&gt;
as possible.&lt;/p&gt;

&lt;p&gt;The initial technological choices you make as a cloud service provider are crucial. Not only do they determine the features you can develop, but also the resiliency and scalability of your entire platform.&lt;/p&gt;

&lt;p&gt;We decided to build our own serverless engine, one that would not be limited by existing implementations. The first version of Koyeb was built on top of Kubernetes and allowed us to quickly build a working cloud platform. After a few months of operating with this version, we decided to move user workloads from Kubernetes to a custom stack based on Nomad, Firecracker, and Kuma.&lt;/p&gt;

&lt;p&gt;We wrote this blog post to explain why we moved from Kubernetes to a custom stack to power our users' serverless workloads. This post is written from our point of view as a cloud service provider.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Koyeb's requirements: Fast, Global, Secure, Scalable&lt;/li&gt;
&lt;li&gt;Building on top of the right abstraction layer&lt;/li&gt;
&lt;li&gt;The limits of Kubernetes&lt;/li&gt;
&lt;li&gt;The stack behind Koyeb Serverless Engine: Nomad, Firecracker, Kuma on BareMetal... and Kubernetes&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Koyeb's requirements: Fast, Global, Secure, Scalable
&lt;/h2&gt;

&lt;p&gt;Before diving into the technicals, let me outline the requirements which led us to where we are today.&lt;/p&gt;

&lt;p&gt;At Koyeb, we are building a next-generation serverless platform that should be the fastest way to deploy applications globally. There are four core pillars we want to achieve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fast&lt;/strong&gt;: we want the platform to be quick, both when you deploy your application and when the application is running. We believe deploying a software update should take minutes or ideally seconds. No developer wants to wait dozens of minutes before an upgrade is deployed, especially when working on development or pre-production environments. Execution should also be fast and your workloads should not be slower in the
cloud than on your laptop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Global&lt;/strong&gt;: for businesses, deploying globally is rarely optional in 2021, and it is definitely not an option for us as we have customers all around the world. Whether you're operating a global B2C brand or a B2B company, if you have users all around the world, you need a simple and effective way to operate in multiple regions. Compliance and performance are the two drivers here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secure&lt;/strong&gt;: as a cloud service provider, security is crucial, especially as we operate a multi-tenant environment. Isolation between customers should be reliable, both at the host and network level. From a user perspective, security should be built-in and should not be an option.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalable&lt;/strong&gt;: to be competitive on the market, we need to offer a scalable platform for our end-users and we need to build a platform able to support both your growth and
our own growth. We've already experienced the pain of struggling with growth &lt;a href="https://blog.scaleway.com/scaleway-is-growing-too-fast-out-of-stock/"&gt;in a previous life&lt;/a&gt;. To better support our customers all around the world, we want to be able to run on different cloud service providers depending on locations and to respect sovereignty requirements.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that we have a list of requirements, let's move to the technical options.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building on top of the right abstraction layer
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The options
&lt;/h3&gt;

&lt;p&gt;We considered all level of abstractions to build&lt;br&gt;
a full-featured platform which would be able to support our mission and requirements. We had roughly 4 options, below is the list sorted from the highest level of abstraction to the&lt;br&gt;
one where you deal directly with hardware:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Cloud providers primitives&lt;/strong&gt;: Building on top high-level function and container primitives of cloud providers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kubernetes&lt;/strong&gt;: Using Kubernetes to power our user workloads&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VMs or BareMetal&lt;/strong&gt;: Building a purpose-built solution, on top of Virtual Machines or BareMetal
servers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Racking&lt;/strong&gt;: Operating our own physical infrastructure and
network (aka racking BareMetal machines)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Our own users face the same kind of options to deploy and operate their production applications. Most of them will rule out options &lt;strong&gt;3&lt;/strong&gt; and &lt;strong&gt;4&lt;/strong&gt; as these are irrelevant for&lt;br&gt;
most businesses nowadays.&lt;br&gt;
&lt;strong&gt;We believe anybody who is not in the infrastructure business should try to build on top of high-level providers like Koyeb, aka option 1.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Our first choice: Kubernetes to the rescue
&lt;/h3&gt;

&lt;p&gt;We quickly ruled out racking servers (option 4). We've been in the business of racking and even building BareMetal servers&lt;br&gt;
&lt;a href="https://blog.scaleway.com/c2-ramp-up-10000-baremetal-servers-month/"&gt;before&lt;/a&gt; but there are now enough options to pick from, at least for our current needs. In 2021, building software usually involves relying on a cloud service provider. We are no exception to that as we are &lt;strong&gt;building a cloud service provider on top of other cloud service providers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We also ruled out building on top of high-level abstractions of cloud service providers (option 1) since it doesn't provide the control we need.This option would probably allow us to develop features faster, but our platform would suffer from the same product limits as these abstractions. Since our goal is to remove these limits to improve our users' deployment experience, this choice would be counter-productive.&lt;/p&gt;

&lt;p&gt;With this in mind, we started to build on top of Kubernetes, believing this would be the right abstraction layer to quickly build a reliable platform meeting our requirements. Spoiler alert, after several months we decided to build a purpose-built solution instead...&lt;/p&gt;

&lt;h2&gt;
  
  
  The limits of Kubernetes
&lt;/h2&gt;

&lt;p&gt;At Koyeb, we have been operating Kubernetes clusters for two years now and, once we started to support custom user functions and containers, we began to see limits.&lt;/p&gt;

&lt;p&gt;Here is a broad overview of the limits we started to hit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Complexity:&lt;/strong&gt; Let's start with the most common complaint you might hear: it's complex. In our case, we need to be able to extend the core. Even when operating a cloud platform is your business, understanding how Kubernetes works and why it was implemented this way is hard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security:&lt;/strong&gt; Kubernetes provides some options to isolate multi-tenant serverless workloads. We first worked with &lt;a href="https://gvisor.dev/"&gt;gVisor&lt;/a&gt;, but the performances were disapointing.
We decided to explore using Firecracker but running Firecracker on Kubernetes was experimental.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Global and multi-zone deployments:&lt;/strong&gt; User workloads on Koyeb need to be able to run
in multiple zones. Kubernetes doesn't support multi-zone out of the box. Implementing multi-zone with Kubernetes requires deploying a full cluster per zone, with a dedicated control plane for each data center.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability:&lt;/strong&gt; Kubernetes is known to have limits in terms of the number of nodes in a cluster, which means that multi-cluster support needs to be implemented really quickly when operating at scale.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Upgradability:&lt;/strong&gt; Release cycles are really short, which is great but difficult to manage in production. Having to upgrade every two months, which means testing and validating that the upgrades do not break the production quickly becomes a full-time job.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overhead:&lt;/strong&gt; Kubernetes clusters tend to have &lt;a href="https://learnk8s.io/allocatable-resources"&gt;considerable
overhead&lt;/a&gt;. On each hypervisor, Kubelet uses between 10% and 25% of RAM which is a non-negligible cost. Spoiler alert: We're more around 100MB with our new architecture.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Kubernetes: a generalist orchestration platform
&lt;/h3&gt;

&lt;p&gt;Back in the early 2010s, the hype was more around &lt;a href="https://www.openstack.org/"&gt;OpenStack&lt;/a&gt; than Kubernetes as Docker didn't even exist, but Kubernetes is the same kind of project: an all-purpose orchestration platform.&lt;/p&gt;

&lt;p&gt;In our experience as a cloud service provider, when you work with large general-purpose software projects, you tend to&lt;br&gt;
hit the same issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;once you start scaling or trying to develop advanced features on such a platform, you need to fully understand the internals&lt;/li&gt;
&lt;li&gt;you spend a lot of energy trying to follow upgrades which might not be relevant to you, break your integrations, and you suffer from decisions you have no control over&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don't get me wrong, Kubernetes definitely helped us develop quickly the first generations of the Koyeb engine. The ability to deploy pre-written Helm Charts is a powerful tool to deploy existing software.&lt;/p&gt;

&lt;p&gt;As a cloud service provider, we knew we would eventually hit the limits and would either need to deep dive into Kubernetes and contribute inside its core or design the Koyeb platform differently...&lt;/p&gt;

&lt;h2&gt;
  
  
  The stack behind Koyeb: Nomad, Firecracker, Kuma on BareMetal... and Kubernetes
&lt;/h2&gt;

&lt;p&gt;With all these limits in mind, we started to re-design the platform to support our goals.&lt;br&gt;
After some testing, we decided to build our serverless platform using a combination of powerful technologies. Enter Nomad, Firecracker, and Kuma on BareMetal... and Kubernetes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BvaLylcg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.koyeb.com/static/images/blog/koyeb-achitecture-core-components.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BvaLylcg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.koyeb.com/static/images/blog/koyeb-achitecture-core-components.png" alt="Koyeb Serverless Platform Core Internal Componets"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Overall architecture
&lt;/h3&gt;

&lt;p&gt;To understand why we combined these technologies, let's take a step back.&lt;br&gt;
On the Koyeb platform, there are two key parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;strong&gt;Koyeb Control Plane&lt;/strong&gt; is composed of the Go APIs behind &lt;a href="https://app.koyeb.com"&gt;app.koyeb.com&lt;/a&gt; and related databases. It receives the API calls and handles all the logic to effectively deploy the app on the Koyeb Data Plane. It needs to run 24x7x365 with requirements pretty similar to those of users' on Koyeb.&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;Koyeb Data Plane&lt;/strong&gt; hosts the deployed users' applications. It's the core of the platform, it needs to support running millions of containers across thousands of
hypervisors. It's the most demanding part of the platform.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On each hypervisor of the data plane, there are 4 major elements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;strong&gt;container runtime and virtualization technology&lt;/strong&gt;, Firecracker, effectively executing the applications, ensuring
multi-tenants workloads are isolated and secured in a performant fashion&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;networking technology&lt;/strong&gt;, composed of Kuma and Envoy, providing the service mesh and discovery engine which enable seamless private networking between services&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;orchestration engine&lt;/strong&gt;, Nomad, which performs all provisioning operations when a deployment happens or scaling events happen&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;operating system and servers&lt;/strong&gt;, CoreOS on High-End BareMetal servers, where the applications run with the lowest possible overhead&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4JECcMHY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.koyeb.com/static/images/blog/koyeb-achitecture-stack-ultra-simplified.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4JECcMHY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.koyeb.com/static/images/blog/koyeb-achitecture-stack-ultra-simplified.png" alt="Koyeb Serverless Stack Ultra Simplified"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the Control Plane runs on... Kubernetes. As we cannot run the Koyeb Control Plane on Koyeb to avoid circular dependencies, we run the APIs on top of Kubernetes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Diving into Nomad, Firecracker, and Nomad
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Nomad for Container Orchestration
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.nomadproject.io/"&gt;Nomad&lt;/a&gt; is a workload orchestration engine which can be used to manage containers and non-containerized applications across clouds.&lt;br&gt;
Nomad lets us deploy and manage the containerized applications that are running on the platform. It provisions Firecracker microVMs and communicates with containerd to manage and run the containers.&lt;/p&gt;

&lt;p&gt;We selected Nomad to do the orchestration because compared to Kubernetes it is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;easily extendable. Runtimes can easily be customized and integrating with Firecracker was seamless using a custom nomad driver.&lt;/li&gt;
&lt;li&gt;simpler to use. The scope of the project is way smaller, it doesn't cover everything from runtime to networking and that's just what we needed.&lt;/li&gt;
&lt;li&gt;multi-zone out of the box, simplifying how we make serverless workloads global.&lt;/li&gt;
&lt;li&gt;easy to implement control plane at the region level, reducing the overhead of per-region Kubernetes clusters.&lt;/li&gt;
&lt;li&gt;has a smaller footprint and is easy scalable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Firecracker for Virtualization
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://firecracker-microvm.github.io/"&gt;Firecracker&lt;/a&gt; is a lightweight virtualization technology that was purpose-built to securely and efficiently run multi-tenant serverless workloads. We needed a virtualization technology that&lt;br&gt;
would keep our clients' workloads secure and isolated, and provides fast boot-up times for new instances without compromising performances. That's exactly what Firecracker does.&lt;/p&gt;

&lt;p&gt;We've written about &lt;a href="https://www.koyeb.com/blog/firecracker-microvms-lightweight-virtualization-for-containers-and-serverless-workloads"&gt;Firecracker MicroVMs&lt;/a&gt; in a previous blog post if you want to dive deeper.&lt;/p&gt;

&lt;p&gt;The key benefits are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multi-tenancy security and isolation,&lt;/li&gt;
&lt;li&gt;High density on bare metal machines thanks to low overhead,&lt;/li&gt;
&lt;li&gt;Fast boot-times for autoscaling microservices and functions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are a few more benefits that we go over in detail in our post &lt;a href="https://www.koyeb.com/blog/10-reasons-why-we-love-firecracker-microvms"&gt;10 Reasons Why We Love Firecracker MicroVMs&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Kuma for Service Mesh Control Plane
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://kuma.io/"&gt;Kuma&lt;/a&gt; is an open-source service mesh built on top &lt;a href="https://www.envoyproxy.io/"&gt;Envoy&lt;/a&gt;. It is a control plane that connects distributed services running on Kubernernets and VMs.&lt;/p&gt;

&lt;p&gt;We built Koyeb to host distributed and microservice architectures. Distributed architectures need a way to connect the services that run within them. A service mesh is the dedicated infrastructure layer that is responsible for the secure, quick, and reliable communication between services in containerized and microservice applications.&lt;br&gt;
For more information about service meshes, check out our post on &lt;a href="https://www.koyeb.com/blog/service-mesh-and-microservices-improving-network-management-and-observability"&gt;service meshes and microservices&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Kuma is a rare service mesh that is not tightly coupled to its workload scheduler. This distinguishes it from alternative service meshes like Linkerd and Istio, which only work on Kubernetes. Moreover, Kuma supports multi-zone and cloud-agnostic out of the box.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3DBOPjfO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.koyeb.com/static/images/blog/koyeb-achitecture-stack-ultra-simplified-mesh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3DBOPjfO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.koyeb.com/static/images/blog/koyeb-achitecture-stack-ultra-simplified-mesh.png" alt="Koyeb Serverless Stack Ultra Simplified with Mesh"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Kuma control plane allows us to secure, observe, and manage the microservice network. Next to each service instance on Koyeb is an Envoy Proxy. These proxies form the data plane, which connects to the Kuma control plane.&lt;/p&gt;

&lt;p&gt;Proxies are configured from the control plane, meaning the hostnames your instances should know for DNS, their retry policies, and more are all communicated to the proxy from the control plane.&lt;/p&gt;

&lt;p&gt;Kuma and Envoy provide us with a great option for private networking, especially because they:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;are platform agnostic,&lt;/li&gt;
&lt;li&gt;support multi-region and multi-cloud deployments,&lt;/li&gt;
&lt;li&gt;can run in a zero-trust network environment thanks to native TLS encryption and mTLS authentication,&lt;/li&gt;
&lt;li&gt;provide natively secure communication between services.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Koyeb Serverless Platform is Purpose-Built
&lt;/h2&gt;

&lt;p&gt;We built Koyeb to be a secure and powerful serverless platform that is developer-friendly. Providing this &lt;strong&gt;serverless experience entails running multi-tenant workloads on bare metal servers&lt;/strong&gt; in a secure and resource-efficient manner.&lt;br&gt;
Moving from Kubernetes to a customized stack of Nomad, Firecracker, and Kuma enables us to provide the serverless experience we envision for the serverless future.&lt;/p&gt;

&lt;p&gt;You can use Koyeb to host web apps and services, Docker containers, APIs, event-driven functions, cron jobs, and more. At the moment, the platform has built-in Docker container deployment and git-driven deployment is on the way!&lt;/p&gt;

&lt;p&gt;Discover the serverless experience and by &lt;a href="https://app.koyeb.com/auth/signup"&gt;signing up&lt;/a&gt; today. Also, feel free to join us over on &lt;a href="https://slack.koyeb.com/"&gt;Slack&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And if you want to help build a serverless cloud service provider and dive deeper into these technologies, &lt;a href="https://dev.to/careers"&gt;we're hiring&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>cloud</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
