One place for hosting & domains

      November 2019

      How To Build an Inspirational Quote Application Using AdonisJs and MySQL


      The author selected the Tech Education Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      AdonisJs is a Node.js web framework written in plain JavaScript that runs on all major operating systems. It uses the popular MVC (Model – View – Controller) design pattern and offers a stable ecosystem for writing server-side web applications. The framework features seamless authentication, SQL ORM (object-relational mapping), migrations, and database seeding. AdonisJs has a similar architecture to the PHP web application framework Laravel, including the same folder structure and several shared setup concepts.

      By default, AdonisJs uses the Edge template engine that is designed for intuitive use. Just like Laravel, AdonisJs ships with an ORM called Lucid that serves as an interface for communication between an application’s models and the database. With AdonisJs, developers can build a full-stack application where the back-end server will be responsible for applying the business logic, routing, and rendering all the pages for the application. It is also possible to create a web service API to return JSON responses from a controller; these web services can then be consumed using front-end frameworks such as Vue.js, React, and Angular.

      In this tutorial, you’ll build an application with AdonisJs using its CLI. You’ll create routes, controllers, models, and views within your application and you’ll carry out form validations. The example in this tutorial will be an inspirational quote application in which a user can sign up and log in to create an inspirational quote. This demo application will give you the opportunity to carry out CRUD (Create, Read, Update, and Delete) operations.

      Prerequisites

      Before you begin this guide, you will need the following:

      Note: This tutorial uses a macOS machine for development. If you’re using another operating system, you may need to use sudo for npm commands in the first steps.

      Step 1 — Installing the Adonis CLI

      In this section, you will install Adonis CLI and all its required packages on your local machine. The CLI will allow you to scaffold a new AdonisJs project as well as create and generate boilerplate for controllers, middlewares, and models in your application. You’ll also create your database for the project.

      Run the following command to install the AdonisJs CLI globally on your machine via npm:

      Once the installation process is complete, type the following command in the terminal to confirm the installation of AdonisJs and view the current version:

      You will see output showing the current version of AdonisJs:

      Output

      4.1.0

      With the successful installation of the AdonisJs CLI, you now have access to and can use the adonis command to create fresh installations of an AdonisJs project, manage your project, and generate relevant files such as the controllers, models, etc.

      Now, you can proceed to create a new AdonisJs project by using the adonis command as shown here:

      • adonis new adonis-quotes-app

      The preceding command will create an application named adonis-quotes-app in a new directory with the same name in your local project directory with the relevant AdonisJs MVC structure.

      Move into the new application folder:

      Then start your application by running:

      This will start the development server on the default port 3333 as specified inside the root .env file for your application. Navigate to http://localhost:3333 to view the welcome page of AdonisJs.

      Welcome page of AdonisJs

      Now you’ll complete the setup of your database. Here, you’ll install the mysql driver to connect to your MySQL server from your Node.js application via npm. To begin, go back to your terminal where the application is currently running, stop the process with CTRL + C and run the following command:

      Now that you have successfully installed the MySQL Node.js driver for this application, you need to create the application database and set up the appropriate connection to it.

      The latest version of MySQL that you have installed from the prerequisite tutorial uses a default authentication plugin named caching_sha2_password. This is currently not supported by Node.js drivers for MySQL. To avoid any database connection issue from your application, you will need to create a new MySQL user and use the currently supported authentication plugin—mysql_native_password.

      To begin, access the MySQL client using the root account:

      You will be prompted to enter your root account password set up during the MySQL installation.

      Next, create the user and password using the mysql_native_password plugin:

      • CREATE USER 'sammy'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';

      You will see the following output:

      Output

      Query OK, 0 rows affected (0.02 sec)

      Next, create a database for the application with:

      You will see the following output:

      Output

      Query OK, 1 row affected (0.03 sec)

      You’ve now successfully created the database for this application.

      Now, enable access to the created database for the new MySQL user. Run the following command to grant all privileges to the user in the database:

      • GRANT ALL PRIVILEGES ON adonis.* TO 'sammy'@'localhost';

      Reload the grant tables by running the following command to apply the changes that you just made:

      You will see the following output:

      Output

      Query OK, 0 rows affected (0.00 sec)

      Exit the MySQL client with:

      You’ve successfully installed the AdonisJs CLI, created a new AdonisJs project, and installed mysql via npm. You also created the database for this application and set up a MySQL user with the appropriate privileges to it. This is the basic setup for your application and in the next section you will begin to create the necessary views for your application.

      Step 2 — Using the Edge Templating Engine

      AdonisJs is shipped with its own template engine called Edge. It allows you to create a reusable HTML template and enables the introduction of front-end logic into your application with minimal code. Edge provides JavaScript developers with the tools while developing an application to build a component-based layout, write conditionals, use iterations, and create view layers to hold logic. All template files end with the .edge extension and are stored in the resources/views directory.

      The following are the views that your application will need to function properly:

      • Master Layout: With Edge, you can create a page that will contain the CSS, common JavaScript files, jQuery, and common parts of the user interface that will stay the same throughout the application—for example, the navigation bar, logo, header, etc. Once you’ve established the Master Layout page, other views (pages) in your application will inherit it.
      • Index view: This page will use the master layout to inherit common files and will also render contents for the homepage of the application.
      • Login page: This page will also use the master layout and render the form with the input fields for both username and password for users to log in.
      • Register page: Here, users will see a form to register and have their details persisted into the database.
      • Create quote page: Users will use this page to create an inspirational quote.
      • Edit quote page: Users will use this page to edit a quote.
      • View quote page: Users will use this page to view a particular quote.

      To begin, use the adonis command to create the master layout page by running the following command:

      • adonis make:view layouts/master

      You’ll see output similar to the following:

      Output

      ✔ create resources/views/layouts/master.edge

      This command will automatically create a master.edge file in your resources/views/layouts folder. Open the new file:

      • nano resources/views/layouts/master.edge

      Add the following code in it:

      /resources/views/layouts/master.edge

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <meta http-equiv="X-UA-Compatible" content="ie=edge">
          <title>adonis-quotes-app</title>
          {{ style('https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css') }}
          {{ style('style') }}
          {{ script('https://code.jquery.com/jquery-3.3.1.slim.min.js') }}
      </head>
      <body>
          <div class="container-fliud">
              @include('navbar')
              @!section('content')
          </div>
          {{ script('https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js') }}
      
      </body>
      </html>
      

      In this file, you include the CDN files for Bootstrap CSS, Bootstrap JavaScript, and jQuery. You add a global CSS file name of style.css and within the div you include a partial file named navbar. To reuse fragments of HTML code that you require across multiple pages in your application, like nav or footer, you can incorporate partials. These are smaller files containing the repeated code making it quicker to update code for these elements in one place rather than at every instance it occurs. The navbar contains markup for a Login and Register buttons, a logo, and a home link.

      With this in place, all the subsequent pages that will be created for this application can extend the master layout and have the navbar rendered without the need to write the content all over again. You’ll create this navbar file later in the tutorial.

      Finally, you define a section tag @!section() to include content from other pages and have them rendered by the master layout. For this to work as expected, all the new pages that will extend the master layout must also define a section tag with the same name (i.e., @section('content')).

      Save and exit the file once you’re finished editing it.

      Next, you will use the adonis command to create the navigation bar:

      You’ll see output similar to:

      Output

      ✔ create resources/views/navbar.edge

      Open the newly created file:

      • nano resources/views/navbar.edge

      Then add the following code to it:

      /resources/views/navbar.edge

      <nav class="navbar navbar-expand-lg navbar-dark text-white">
          <a class="navbar-brand" >LOGO</a>
          <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
              <span class="navbar-toggler-icon"></span>
          </button>
      
          <div class="collapse navbar-collapse" id="navbarNav">
              <ul class="navbar-nav">
                  <li class="nav-item active ">
                      <a class="btn text-white" href="/">Home</a>
                  </li>
              </ul>
          </div>
          <div class="navbar-right" id="navbarNav">
              @loggedIn
                  <ul class="navbar-nav">
                          <li>
                              <div class="text-right">
                                   <a href="{{route('create.quote')}}" class="btn btn-outline-primary">Create Quote</a>
                              </div>
                          </li>
      
                      <li class="nav-item dropdown">
                          <a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                             {{ auth.user.username}}
                          </a>
                          <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
                              <form method="POST" action="{{route('logout')}}">
                                  {{ csrfField() }}
                                    <button  type="submit" class="dropdown-item" href="">logout</button>
                              </form>
                          </div>
                      </li>
                  </ul>
              @else
                  <ul class="navbar-nav">
                      <li class="nav-item active pr-2">
                          <a href="{{route('login.create')}}" class="btn btn-outline-danger">
                            login
                          </a>
                      </li>
                      <li class="nav-item active pr-2">
                          <a href="{{route('register.create')}}" class="btn btn-outline-primary">
                              Register
                          </a>
                      </li>
                  </ul>
              @endloggedIn
          </div>
      </nav>
      

      In addition to defining the links to the homepage and a button to register and login, you add a @loggedIn tag. With this in place you can write a conditional statement around the authenticated user and display appropriate contents where necessary. For an authenticated user, the application will display their username and a button to create a new quote. If a user is not logged in, your application will display a button to either log in or register. This page will be included as a partial on every page as it was earlier in the master layout for this application.

      Save and exit the file.

      Now, you’ll create the index page that you’ll use for the application’s homepage. It will render and display the list of all inspirational quotes that users write:

      You will see an output similar to the following:

      Output

      ✔ create resources/views/index.edge

      The file created here will be located in resources/views/index.edge. Open the file:

      • nano resources/views/index.edge

      Then add the following code:

      /resources/views/index.edge

      @layout('layouts/master')
      @section('content')
      
      <div class="container">
          <div class="text-center">
              @if(flashMessage('successmessage'))
                  <span class="alert alert-success p-1">{{ flashMessage('successmessage') }}</span>
              @endif
          </div>
          <div class="row">
              @each(quote in quotes)
                  <div class="col-md-4 mb-4 quote-wrapper">
                      <a href="http://www.digitalocean.com/view-quote/{{quote.id}}" class="w-100">
                          <div class="card shadow-lg bg-dark text-white">
                              <div class="card-body">
                                  <blockquote class="blockquote mb-0">
                                      <p>{{quote.body}}</p>
                                      <footer class="blockquote-footer">
                                          <cite title="Source Title"> {{quote.username}}</cite>
                                      </footer>
                                  </blockquote>
                                  @if(auth.user.id == quote.user_id)
                                    <div>
                                      <a  href="http://www.digitalocean.com/edit-quote/{{quote.id}}" class="btn btn-primary">edit</a>
                                      <a href="http://www.digitalocean.com/delete-quote/{{quote.id}}" class="btn btn-danger">delete</a>
                                    </div>
                                  @endif
                              </div>
                          </div>
                      </a>
                  </div>
              @else
               <div class="col-md-12 empty-quote text-center">
                      <p>No inspirational quote has been created</p>
               </div>
              @endeach
          </div>
      </div>
      @endsection
      

      Here, you indicate that this view will use the master layout by extending it. This page can now have access to all the libraries, stylesheets, and the navbar included in the master layout. Next, you iterate over an array of quotes using the built-in @each tag. The quotes array will be passed to this view from the QuoteController that you’ll create later in this tutorial. If there are no quotes, an appropriate message will be displayed.

      Save and exit this file.

      Now, to create the login page, run the following command from the terminal:

      • adonis make:view auth/login

      You will see an output similar to:

      Output

      ✔ create resources/views/auth/login.edge

      This will automatically create an auth folder within resources/views and also create a login.edge file within it. Open the login.edge file:

      • nano resources/views/auth/login.edge

      Add the following content:

      /resources/views/auth/login.edge

      @layout('layouts/master')
      @section('content')
        <div class="container">
          <div class="row">
            <div class="col-md-4 shadow bg-white mt-5 rounded offset-md-4">
              <form method="POST" action="{{route('login.store')}}">
                {{ csrfField() }}
                  <div>
                    @if(flashMessage('successmessage'))
                      <span class="alert alert-success p-1">{{ flashMessage('successmessage') }}</span>
                    @endif
                  </div>
                  <div class="form-group">
                    <label for="email">Email address</label>
                    <input type="email" class="form-control" id="email" name="email" value="{{old('email','')}}"  placeholder="Enter email">
                    {{ elIf('<span class=text-danger>$self</span>', getErrorFor('email'), hasErrorFor('email')) }}
                  </div>
                  <div class="form-group">
                    <label for="pasword">Password</label>
                    <input type="password" class="form-control" id="password" name="password" value="{{old('password','')}}" placeholder="Password">
                    {{ elIf('<span class=text-danger>$self</span>', getErrorFor('password'), hasErrorFor('password')) }}
                  </div>
      
                  <div class="text-center">
                    <button type="submit" class="btn btn-primary">Submit</button>
                  </div>
              </form>
            </div>
          </div>
        </div>
      @endsection
      

      This file holds a form that contains input elements that you’ll use to collect the username and password of a registered user before they can successfully get authenticated and start creating quotes. Another important element to note on this page is the {{ csrfField() }}. It is a global variable that AdonisJs will use to pass the CSRF access token when sending a POST, PUT, and DELETE request from your application.

      This was put in place to protect your application from Cross-Site Request Forgery (CSRF) attacks. It works by generating a unique CSRF secret for each user visiting your website and once your users send an HTTP request from the frontend, a corresponding token is generated for this secret and passed along with the request. This will allow the middleware created for this request within AdonisJs to verify that both the token and CSRF secret is valid and belong to the currently authenticated user.

      Save and exit the file once you’re finished.

      Next, you will create the register page with this command:

      • adonis make:view auth/register

      You will see output similar to this:

      Output

      ✔ create resources/views/auth/register.edge

      Locate and open the newly created file in resources/views/auth/register.edge:

      • nano resources/views/auth/register.edge

      Add the following code:

      resources/views/auth/register.edge

      @layout('layouts/master')
      @section('content')
        <div class="container ">
          <div class="row">
              <div class="col-md-4  bg-white p-3 mt-5 shadow no-border rounded offset-md-4">
                <form method="POST" action="{{route('register.store')}}">
                  {{ csrfField() }}
                    <div class="form-group">
                      <label for="name">Fullname</label>
                      <input type="text" class="form-control" id="name" name="name"  value="{{old('name','')}}" placeholder="Enter Fullname">
                      {{ elIf('<span class=text-danger>$self</span>', getErrorFor('name'), hasErrorFor('name')) }}
                    </div>
                    <div class="form-group">
                      <label for="email">Email address</label>
                      <input type="email" class="form-control" id="email"  name="email" value="{{old('email','')}}" placeholder="Enter email">
                      {{ elIf('<span class=text-danger>$self</span>', getErrorFor('email'), hasErrorFor('email')) }}
                    </div>
                    <div class="form-group">
                      <label for="pasword">Password</label>
                      <input type="password" class="form-control" id="password" name="password" placeholder="Password">
                      {{ elIf('<span class=text-danger>$self</span>', getErrorFor('password'), hasErrorFor('password')) }}
                    </div>
                    <div class="text-center">
                        <button type="submit" class="btn btn-primary">Submit</button>
                    </div>
                </form>
              </div>
          </div>
        </div>
      @endsection
      

      Similarly to what you have on the login page, this file contains an HTML form with input fields to collect the name, email, and password of a user during the registration process. Also included is the {{ csrfField() }} as it is required for each post request for an AdonisJs application.

      Save and exit the file.

      Now, you will generate a new file to create an inspirational quote by running the following command from the terminal:

      • adonis make:view quotes/create-quote

      You will see output like:

      Output

      ✔ create resources/views/quotes/create-quote.edge

      Open resources/views/quotes/create-quote.edge:

      • nano resources/views/quotes/create-quote.edge

      And add the following content to it:

      /resources/views/quotes/create-quote.edge

      @layout('layouts/master')
      @section('content')
      <div class="container">
          <div class="row">
              <div class="col-md-3"></div>
              <div class="col-md-6 shadow bg-white mt-5 rounded p-3">
                  <div class="float-right">
                      <a href="/" class="btn btn-outline-dark ">back</a>
                  </div>
                      <br>
      
                  <div class="clear-fix"></div>
                      <form method="POST" action="{{route('store.quote')}}">
                          {{ csrfField() }}
                          <div class="form-group">
                              <label for="quote">Create Quote</label>
                              <textarea type="text" rows="5"  name='body' id="body" class="form-control" id="quote" placeholder="Write an inspirational quote"></textarea>
                          </div>
      
                          <div class="text-center">
                              <button type="submit" class="btn btn-primary">Submit</button>
                          </div>
                      </form>
                  </div>
              </div>
              <div class="col-md-3"></div>
          </div>
      </div>
      @endsection
      

      This page extends the master layout and contains an HTML form with a text area element that allows a user to input text over multiple rows before being posted and handled by the appropriate route.

      Save and exit the file once you’re finished.

      Next, you will create a page for editing a particular quote. Run the following command from the terminal:

      • adonis make:view quotes/edit-quote

      You will see the following output:

      Output

      ✔ create resources/views/quotes/edit-quote.edge

      Open the file with:

      • nano resources/views/quotes/edit-quote.edge

      Add the following content to resources/views/quotes/edit-quote:

      /resources/views/quotes/edit-quote.edge

      @layout('layouts/master')
      @section('content')
      <div class="container">
          <div class="row">
              <div class="col-md-6 shadow bg-white rounded p-3 offset-md-3">
                  <div class="float-right">
                      <a href="/" class="btn btn-outline-dark ">back</a>
                  </div>
                  <br>
      
                  <div class="clear-fix"></div>
                  <form method="POST" action="/update-quote/{{quote.id}}">
                      {{ csrfField() }}
                      <div class="form-group">
                          <label for="pasword">Edit Quote</label>
                          <textarea type="text" rows="5"  name='body' id="body" class="form-control" id="quote" placeholder="write the inspirational quote">{{quote.body}}</textarea>
                      </div>
                      <div class="text-center">
                          <button type="submit" class="btn btn-primary">Update</button>
                      </div>
      
                  </form>
              </div>
          </div>
      </div>
      @endsection
      

      This page holds similar content as the create-quote.edge file—the difference is that it contains the details of a particular quote that needs to be edited, <form method="POST" action="/update-quote/{{quote.id}}">.

      Save and exit the file.

      Finally, generate a page to view a single inspirational quote:

      • adonis make:view quotes/quote

      You will see an output similar to this:

      Output

      ✔ create resources/views/quotes/quote.edge

      Open the file with:

      • nano resources/views/quotes/quote.edge

      Add the following code:

      /resources/views/quotes/quote.edge

      @layout('layouts/master')
      @section('content')
      <div class="container">
          <div class="row">
              <div class="col-md-6 offset-md-3">
                  <div class="card shadow-lg bg-dark text-white">
                      <div class="card-body">
                          <div class="float-right">
                              <a href="/" class="btn btn-outline-primary ">back</a>
                          </div>
                              <br>
                          <div class="clear-fix"></div>
                          <blockquote class="blockquote mb-0">
                              <p>{{quote.body}}</p>
                              <footer class="blockquote-footer">
                                  <cite title="Source Title">{{quote.username}}</cite>
                              </footer>
                          </blockquote>
                      </div>
                  </div>
              </div>
          </div>
      </div>
      @endsection
      

      This page renders the details of a particular quote, that includes the body of the quote, quote.body, and the author who created it, quote.username.

      Once you’re finished with the file, save and exit.

      You have created all the required pages for your application by using the Edge templating engine. Next, you’ll configure and create a connection to your application’s database.

      Step 3 — Creating a Database Schema

      If you serve your application now it will throw an error as you are yet to connect the application to a database. In this section, you will set up a connection to the database and then use the adonis command to generate a migration file that will be used to create the tables for it.

      AdonisJs ships with an ORM named Lucid ORM, which provides active record implementation for working with your database. It takes away the hassle of writing SQL queries that retrieve data from the database in realtime. This is especially helpful when working on a complex application that requires a lot of queries. As an example, retrieving all the quotes from your application can be achieved by writing this:

      const quotes = await Quote.all()
      

      To proceed with the appropriate configuration for your application database, ensure that you are still within the root directory of your application and create a .env file:

      Open the newly created file and add the following content:

      .env

      HOST=127.0.0.1
      PORT=3333
      NODE_ENV=development
      APP_URL=http://${HOST}:${PORT}
      CACHE_VIEWS=false
      APP_KEY=bTVOEgUvmTCfkvgrK8gEBC3Qxt1xSYr0
      DB_CONNECTION=mysql
      DB_HOST=127.0.0.1
      DB_PORT=3306
      DB_USER=sammy
      DB_PASSWORD=password
      DB_DATABASE=adonis
      SESSION_DRIVER=cookie
      HASH_DRIVER=bcrypt
      

      By default the database connection for an AdonisJs application is SQLite, which you will update to MySQL here. You also specify the PORT for the application, the application environment, and your database credentials. Ensure that you replace the DB_USER, DB_PASSWORD, and DB_DATABASE placeholder with your credentials.

      Next, you will create the model and a migration file for Quote using the Adonis CLI. To accomplish that, run the following command:

      • adonis make:model Quote --migration

      You’ll see output similar to the following:

      Output

      ✔ create app/Models/Quote.js ✔ create database/migrations/1568209992854_quote_schema.js

      This command will create a model for Quote in the app/Models folder and a schema file in the database/migrations folder. The newly created schema file will be prefixed with the current timestamp. Open the schema file with:

      • nano database/migrations/1568209992854_quote_schema.js

      Update its content with the following code:

      database/migrations/…quote_schema.js

      'use strict'
      /** @type {import('@adonisjs/lucid/src/Schema')} */
      const Schema = use('Schema')
      class QuoteSchema extends Schema {
        up () {
          this.create('quotes', (table) => {
            table.increments()
            table.integer('user_id').notNullable()
            table.string('username', 80).notNullable()
            table.string('body').notNullable()
            table.timestamps()
          })
        }
        down () {
          this.drop('quotes')
        }
      }
      module.exports = QuoteSchema
      

      A schema file in AdonisJs requires two different methods, which are:

      • up: Used to create a new table or alter an existing one.
      • down: Used to revert the changes applied in the up method.

      In addition to the timestamps() and increments() fields, you update the content of the schema file with the field attributes user_id, username, and the body of a quote that will be created. The user_id and username fields reference the details of the user who create a particular quote. This defines a one to many relationship and means a user can own an infinite number of quotes while a single quote can only belong to a user.

      Save and exit the file.

      AdonisJs comes installed with a User model and its migration file by default, which requires only a small modification to establish the relationship between the User and Quote model.

      Open the User model in app/Models/User.js:

      Add this method immediately after the tokens() method:

      app/Models/User.js

      ...
      class User extends Model {
        ...
        tokens () {
          return this.hasMany('App/Models/Token')
        }
      
        quote () {
          return this.hasMany('App/Models/Quote')
        }
      }
      
      module.exports = User
      

      This will establish a one to many relationship with the Quote table using user_id as the foreign key.

      Save and exit the file.

      To wrap up this section, use the following command to run migrations, which will execute the up() method of all migration files:

      You will see output similar to the following:

      Output

      migrate: 1503248427885_user.js migrate: 1503248427886_token.js migrate: 1568209992854_quote_schema.js Database migrated successfully in 3.42 s

      You’ve configured and secured a connection with your database. You also created a Quote model and its corresponding schema file and created a one to many relationship between a User and Quote. Next, you’ll generate the routes and create controllers to handle HTTP requests and the business logic to create, edit, and delete an inspirational quote.

      Step 4 — Creating Controllers and Setting Up Routes

      In this section, you will start by creating controllers to handle all the logic for the application and later attach these controllers to a specific route for it to be accessed by users via a URL.

      To start, you’ll use the Adonis CLI to create a new HTTP request controller to handle all authentication processes for your application by running the following command:

      • adonis make:controller Auth --type http

      This command will create an AuthController.js file and save it within app/Controllers/Http folder. You use the flag --type to indicate that you want this controller to be an HTTP controller.

      You will see an output similar to the following:

      Output

      ✔ create app/Controllers/Http/AuthController.js

      Next, open the newly created controller file:

      • nano app/Controllers/Http/AuthController.js

      Update it with the following content:

      app/Controllers/Http/AuthController.js

      'use strict'
      const User = use('App/Models/User')
      class AuthController {
      
          loginView({ view }) {
              return view.render('auth.login')
          }
          registrationView({ view }) {
              return view.render('auth.register')
          }
      
          async postLogin({ request, auth, response}) {
              await auth.attempt(request.input('email'), request.input('password'))
              return response.route('index')
          }
      
          async postRegister({ request, session, response }) {
              const user = await User.create({
                  username: request.input('name'),
                  email: request.input('email'),
                  password: request.input('password')
              })
              session.flash({ successmessage: 'User have been created successfully'})
              return response.route('login.create');
          }
      
          async logout ({ auth, response }) {
              await auth.logout()
              return response.route('/')
          }
      }
      module.exports = AuthController
      

      In this file, you import the User model and then create two methods named loginView() and registerView() to render the login and register pages respectively. Finally, you create the following asynchronous methods:

      • postLogin(): This method will obtain the value of the email and password posted through the help of the inbuilt request method in AdonisJs and then validate this user against the details in the database. If such a user exists in the database and has inputted the correct credential, they will be redirected back to the homepage and authenticated before they can create a new quote. Otherwise, a message indicating the wrong credentials will be displayed.
      • postRegister(): This will receive the value of the username, email, and password for a user to create an account for such user in the database. A message indicating that such user has been created successfully will be passed to the session and the user will be redirected to the login page to get authenticated and start creating a quote.
      • logout(): This method will handle the logout functionality and redirect the user back to the homepage.

      Save and exit the file.

      Now that you have set up the controller to register and authenticate users, you will proceed by creating an HTTP request controller to manage all operations regarding quotes.

      Back in the terminal, run the following command to create the QuoteController:

      • adonis make:controller Quote --type http --resource

      Using the --resource flag will create a controller with predefined resourceful methods to do CRUD (Create, Read, Update, and Delete) operations.

      You will see:

      Output

      ✔ create app/Controllers/Http/QuoteController.js

      Locate this file within app/Controllers/Http/QuoteController.js:

      • nano app/Controllers/Http/QuoteController.js

      Update it with the following content:

      app/Controllers/Http/QuoteController.js

      'use strict'
      const Quote = use('App/Models/Quote')
      
      class QuoteController {
      
        async index ({ view }) {
          const quote = await Quote.all()
          return view.render('index', {
            quotes: quote.toJSON()
          })
        }
      
        async create ({ view }) {
          return view.render('quotes.create-quote')
        }
      
        async store ({ request,auth,session, response }) {
          const quote = await Quote.create({
            user_id: auth.user.id,
            username: auth.user.username,
            body: request.input('body')
          })
          session.flash({ 'successmessage': 'Quote has been created'})
          return response.redirect('/')
        }
      
        async show ({ params, view }) {
          const quote = await Quote.find(params.id)
          return view.render('quotes.view-quote', {
            quote: quote.toJSON()
          })
        }
      
        async edit ({ params, view }) {
          const quote = await Quote.find(params.id)
          return view.render('quotes.edit-quote', {
            quote: quote.toJSON()
          })
        }
      
        async update ({ params, request, response, session }) {
          const quote = await Quote.find(params.id)
          quote.body = request.input('body')
          await quote.save()
          session.flash({'successmessage': 'Quote has been updated'})
          return response.redirect('/')
        }
      
        async destroy ({ params, response, session }) {
          const quote = await Quote.find(params.id)
          await quote.delete()
          session.flash({'successmessage': 'Quote has been deleted'})
          return response.redirect('/')
        }
      }
      module.exports = QuoteController
      

      In this controller, you imported the Quote model and updated the following methods that were automatically created by using AdonisJs CLI:

      • index(): to fetch all quotes from the database and render it on the homepage of the application.
      • create(): to render a page for creating quotes.
      • store(): to persist a newly created quote into the database and return an appropriate response.
      • show(): to obtain the id of a particular quote, retrieve it from the database, and render it on the edit quote page.
      • edit(): to obtain the detail of a particular quote from the database and render it for editing.
      • update(): to process any update to a quote and redirect the user back to the homepage.
      • destroy(): to delete a particular quote and remove it entirely from the database.

      Save and exit the file.

      After creating all the necessary controllers for this application, you can now set up the routes so that users can easily interact with your application. To begin, navigate to start/routes.js file

      Replace its content with the following:

      start/routes.js

      'use strict'
      const Route = use('Route')
      
      Route.get('/','QuoteController.index').as('index')
      Route.get('/register','AuthController.registrationView').as('register.create')
      Route.post('/register-store','AuthController.postRegister').as('register.store').validator('Register')
      Route.get('/login','AuthController.loginView').as('login.create')
      Route.post('/login-store','AuthController.postLogin').as('login.store')
      Route.get('/view-quote/:id','QuoteController.show').as('view.quote')
      
      Route.group(() => {
          Route.get('/create-quote','QuoteController.create').as('create.quote')
          Route.post('/store-quote','QuoteController.store').as('store.quote')
          Route.get('/edit-quote/:id','QuoteController.edit').as('edit.quote')
          Route.post('/update-quote/:id','QuoteController.update').as('update.quote')
          Route.get('/delete-quote/:id','QuoteController.destroy').as('delete.quote')
          Route.post('/logout','AuthController.logout').as('logout')
      }).middleware(['auth'])
      

      Here, you define the path for each route in your application, specify the HTTP verbs for each action, and bound the route to a particular method in each controller. You also name each of these routes as they have been referenced within the controllers and views.

      To ensure that only authenticated users can access all the quotes routes, you assign a group middleware named to it. And lastly, you attach a validator method to the register.store route to validate user input.

      Save and exit the file.

      You’ve created your controllers and set up the routes for your application. Next you’ll create the validator method defined in this step.

      Step 5 — Validating User Input

      AdonisJs does not have validators built-in by default. As a result you’ll install and register the validator for your application manually.

      Run the following command to install it:

      Open the following file to register the validator provider:

      Then register the validator provider by appending it to the list of providers as shown following:

      start/app.js

      ...
      const providers = [
         ...
         '@adonisjs/cors/providers/CorsProvider',
         '@adonisjs/shield/providers/ShieldProvider',
         '@adonisjs/session/providers/SessionProvider',
         '@adonisjs/auth/providers/AuthProvider',
         '@adonisjs/validator/providers/ValidatorProvider'
      ]
      

      Now that you have installed and registered the validator provider within your application, create a custom validator to validate user input during registration with the following command:

      • adonis make:validator Register

      This will create a Register.js file in the App/validators directory. Open the file with:

      • nano app/Validators/Register.js

      Add the following code to the file:

      app/Validators/Register.js

      'use strict'
      class Register {
        get rules () {
          return {
            name:'required',
            email:'required|email|unique:users',
            password:'required|min:8'
          }
        }
      
        get messages(){
          return{
            'name.required':'Full name is required',
            'email.required':'email is required',
            'email.unique':'email already exists',
            'password.required':'password is required',
            'password.min':'password should be at least 8 characters'
          }
        }
      }
      module.exports = Register
      

      You define rules for specific fields in your application. If validations fail at any time, the validator automatically sets the error as a flash message and the user will be redirected back to the form.

      Save and exit the file once you’re finished editing.

      Finally, to add styling for your application, open the following file:

      Replace its contents with the following:

      /public/style.css

      @import url('https://fonts.googleapis.com/css?family=Montserrat:300');
      
      html, body {
        height: 100%;
        width: 100%;
      }
      
      body {
        font-family: 'Montserrat', sans-serif;
        font-weight: 300;
        background-image: url("/splash.png");
        background-color: #220052;
      }
      
      * {
        margin: 0;
        padding: 0;
      }
      
      a {
        color: inherit;
        text-decoration: underline;
      }
      
      p {
        margin: 0.83rem 0;
      }
      
      .quote-wrapper {
        margin-top: 20px;
      }
      
      .quote-wrapper a {
        text-decoration: none;
      }
      
      .quote-wrapper a:hover {
        color: #ffffff;
      }
      
      .empty-quote {
        color: #ffffff;
      }
      
      form {
        padding: 20px;
      }
      

      In this file you update the CSS styling of your application in the style.css file.

      You’ve installed and registered a validator provider for the purpose of checking users’ input during the registration process. You also updated the content of your stylesheet to add more styling to the application. In the final step you’ll test your application.

      Step 6 — Serving the Application

      In this step, you’ll serve your application and create a user and password to test the authentication. You’ll also add a quote to your app and view this on the homepage.

      To test your application, start the development server with the following command from the root directory of your application:

      This will start the application on the port defined inside the root .env file, which is 3333. Navigate to http://localhost:3333 from your browser.

      Quote app homepage

      The homepage is empty at the moment as you have not created any quotes. Click on the Register button.

      Registration page

      Enter your details and click on the Submit button to complete the registration process. You will be redirected to the login page. Enter your email address and password for authentication.

      Login page

      Once you’re authenticated, click on the Create Quote button.

      Create quote page

      Enter a quote and navigate to the View all page to see your quote.

      View all quotes page

      You’ve tested your application by creating and authenticating a user and then writing a quote.

      Conclusion

      In this tutorial you’ve built a web application with AdonisJs. You set up the application using the AdonisJs CLI and leveraged the CLI for creating other relevant files such as controllers, models, and views.

      You can build web applications with this framework irrespective of their size and complexity. Feel free to download the source code for this project here on GitHub. To explore further features, you can also visit the official documentation.

      If you would like to explore some of our other JavaScript framework tutorials, check out the following:



      Source link

      Survey: How Do IT Leaders Grade Their Data Center and Cloud Infrastructure Strategies?


      We’re still merely entering the hybrid and multicloud era of information technology, but according to new survey research from INAP, the transformation is about to hit warp speed, a trend we see continuing in our latest survey. Nearly 9 in 10 organizations with on-premise data centers plan to move at least some of their workloads off-premise into cloud, managed hosting or colocation in the next three years.

      As more companies diversify their infrastructure mix, how confident are IT leaders and managers that they’re taking the right approach?

      For INAP’s second annual installment of the State of IT Infrastructure Management survey, we asked 500 IT leaders and infrastructure managers to assess their data center and cloud strategies, assign a letter grade and give us their thoughts on why they chose a particular rating.

      How do the grades stack up among participants? What factors are most closely associated with A-grade infrastructures? And why do some infrastructure strategies fall short?

      Making the Grade in the Hybrid IT and Multicloud Era

      Grades

      Instead of the classic bell curve so many of us were subject to during our years in academia, most of the IT infrastructure management professionals say their infrastructure strategy deserves an above average grade, with the majority—56.3 percent of respondents—giving their infrastructures a B. Roughly 19 percent think they deserve a C or below. While the results can be read as a vote of confidence for multiplatform, hybrid cloud and multicloud strategies, most respondents say there’s still plenty room for improvement: Only 1 in 4 participants (25.2 percent) gave their infrastructure strategies an A.

      Factors Most Associated with A-Grade Infrastructure

      Still, it’s worth asking: What factors distinguish A’s from the rest of the crowd?

      Four groups in the data, regardless of company size, industry and headcount, are strongly correlated with high marks:

      Off-Premise Migrators

      A’s have a significantly smaller portion of their workloads on-premise (30 percent of workloads, on average) compared to C’s and below (45 percent).

      Colocation Customers

      Thirty-one percent of IT pros who have colocation as part of their infrastructure mix give themselves an A. This is six points higher than the total population.

      Cloud Diversifiers

      For companies already in the cloud, those who only host with public cloud platforms (AWS, Azure, Google) are less likely to give themselves A’s than those who adopt multicloud platform strategies—18 percent vs. 29 percent, respectively.

      Managed Services Super Users

      The more companies rely on third parties or cloud providers to fully manage their hosted environments (up to the application layer), the more likely they are to assign their infrastructure strategy an A. The average share of workloads fully managed: A’s (71 percent), B’s (62 percent), C’s (54 percent).

      Why Some IT Infrastructures Strategies Fall Short

      Click to view full-size image.

      From the above results, no single explanation for why strategies did not earn top marks were selected by a fewer than a fifth of respondents, but two clearly lead the pack:

      • Infrastructure not fully optimized for applications
      • Too much time managing and maintaining the infrastructure

      The first leading factor speaks to a simultaneous benefit and challenge of the multicloud and hybrid IT era. It’s more economical than ever to find a mix of infrastructure solutions that match the needs of individual workloads and applications. The flip side to that benefit is the simple fact that adopting new platforms can quickly lead to environment sprawl and raise the complexity of the overall strategy—making the goal of application optimization a tougher bar to clear.

      The second leading factor—improper time allocation—underscores a central theme of IT infrastructure management that will be discussed in greater depth in a future blog.

      Senior Leaders vs. Non-Senior IT Pros

      As previously noted, only 1 in 4 participants gave their infrastructure strategies an A. That number falls to 1 in 8 (12.6 percent) if we remove senior IT leaders from the mix. Non-senior infrastructure managers are also two times more likely to grade their infrastructure strategy a C. In other areas of the State of IT Infrastructure Management survey, senior leaders generally held a more optimistic outlook, and the infrastructure grades were no exception.

      Why might this be? We can only speculate, but senior leaders may be loath to give a low grade to a strategy they had a large part in shaping. Or perhaps it’s that non-senior leaders deal with more of the day-to-day tasks associated with infrastructure upkeep and don’t feel as positive about the strategy. Whatever the reason, these two groups are not seeing eye to eye.

      Strategizing to Earn the A-Grade

      When considering solutions—be it cloud, colocation and/or managed services—a lesson or two can be taken from those A-grade infrastructure strategies, and maybe from the C’s and below, as well.

      If you’re ready to level-up your strategy, but unsure where to start, INAP can help. We offer high-performance data center, cloud, network and managed services solutions that will earn your infrastructure strategy an A+.

      Laura Vietmeyer


      READ MORE



      Source link

      New Survey Report: The State of IT Infrastructure Management


      What is the state of enterprise IT infrastructure, and what insights can we glean from the perspectives of the IT professionals responsible for its management and operation?

      To answer these questions and more, INAP surveyed 500 IT professionals with data center, server and cloud infrastructure responsibilities at companies in the U.S. and Canada to create the second annual State of IT Infrastructure Management report.

      In this year’s report, we delve further into what’s driving the decline of on-premise data centers and highlight the factors associated with successful infrastructure strategies in the hybrid and multicloud era. Plus, we highlight where the results show an acceleration of the major themes established in last year’s survey.

      Download the report and read on to learn what we discovered.

      DOWNLOAD THE REPORT

      Key Trends and Takeaways from the Latest Survey

      Strategic Room for Improvement

      We asked IT pros to assign a letter grade to their current infrastructure strategy and found that a majority of IT pros don’t think their current infrastructure strategies deserves a top grade. Only 1 in 4 (25.2 percent) respondents, gave their infrastructures an A. In the report, we narrow down what factors earned the top grade, and the areas for improvement for those who assigned their infrastructures a lower grade.

      The Decline of On-Prem Accelerates

      The next three years will see a significant reduction in the number of workloads powered by on-premise data centers or server rooms. Continuing the trend noted in last year’s report, 88 percent of survey participants expect to move at least part of their workloads off-premise over the next three years. Learn which solutions will be top destinations for these latest migrations in the report.

      9 in 10

      Performance Trumps Economics

      Network performance emerges as the top reason for moving more workloads to colocation facilities or the cloud, while economic factors like expected cost savings of closing down on-premise facilities come in fifth. We’ve identified the ‘Big 4’ reasons driving the off-prem migration, all of which make a compelling case for why the death of the on-premise data center is perhaps inevitable within the next decade.

      Monitoring Leads List of Routine Time Drains

      Nearly half of IT professionals who say infrastructure monitoring is among their job responsibilities feel they are spending too much time on it—the No. 1 time drain for the second consecutive year. We asked these professionals again what they would do if they were able to remove routine activities like server monitoring and maintenance. Last year, the No. 1 answer was reclaiming work-life balance. This year, that answer fell to the No. 3 spot. Learn more about what professionals would do with 16 hours back by downloading the report below.

      monitoring

      The Leadership Disconnect

      On several issues—department headcount, optimism around strategy, efficacy of hybrid and multicloud—senior IT leaders hold starkly different views than non-senior infrastructure managers. Throughout the report, we explore these disparities and point to potential reasons for these differences in opinion.

      Take a Deeper Dive

      To read about these insights and more, download the report below—and keep an eye on our ThinkIT blog over the next few weeks as we break down each of these topics in greater depth.

      New Survey Report: The State of IT Infrastructure Management

      READ THE REPORT

      Laura Vietmeyer


      READ MORE



      Source link