Create a Websockets App in NestJS

NestJS is one of the things I have been playing around a bit in the recent days. Here’s how you can create a websocket application quickly on NestJS. Did I say this is a sample app that serves no real-world value other than poking around the application? Setup project in NestJS First.. install NextJS if you have not done so. yarn global add @nestjs/cli Create a new project. nest new websocket-proj Now, install support for sockets. ...

Using Lucid vs. Database Raw in AdonisJS

Lucid ORM, the official ORM of AdonisJS, is based on knex.js. It is one of the friendlier ORMs that provides the ease of using a readable syntax along with a better performance than some of the feature-heavy ORMs. But, I have been recently torn between using one or the other. Consider the below query that fetches a bunch of related fields - const statusByParSub = await Database.select("sub.sub_num", "sub.status_cd") .from("sub") .innerJoin("par", "sub.par_id", "par.id") .innerJoin("users", "par.owner_id", "users.id") .where("par.start_date", ">", queryFilter) .groupBy("sub.sub_num") .groupBy("sub.status_cd") .count(); While the above query is certainly more readable than using a SQL, I doubt whether it can achieve the same level of performance as a raw SQL. The main reasons for the thought process being the layers involved in ORM, the end-query built from 1:M and M:M relationships, and the time that I personally take in creating an efficient ORM vs. writing a raw SQL. ...

Manage incremental changes to database in AdonisJS

Use database migration utilities in Adonis to its complete potential. Carry out incremental updates - may it be a new table, or changes to existing table using distinct migration files that are version controlled. You have a beautiful Todo application that has a todos table with the following columns: description status end_date Now, let’s say our users ask for a new field called planned_end_date. Your first instinct may be to add the column to the database, change controller code if required, and call it a day. But, what if you to start making changes at different times to - ...

Handle Creation of Single or Multiple Records in AdonisJS

Support creation of a single record or a group of records using same business logic and in the same controller in AdonisJS. Typically you create the following controller to handle record creation - // TodoController.js async create({ request, auth }) { const data = request.all(); //single record return await Todo.create(data); } create will happily create a single record as per the input data. What if you want to create multiple records in one go? The first idea that one may have is to handle everything in the controller. Since the business logic is going to remain the same, and there may be a lot of reuse for auxiliary functions, one is tempted to just do the following. ...

Custom Configuration Parameters in AdonisJS

AdonisJS stores its configuration values in config folder in root. For e.g. you will set database environment values in database.js, authentication params in auth.js and so on. You can update or set new configuration parameters required by your application in those files. You could also create a new configuration file for your application variables and refer to those values from services, controllers, or from any place where it makes sense. ...

Pagination in AdonisJS

AdonisJS provides a standard way to handle pagination and query only a pre-defined number of records in your query result. A typical controller without any pagination looks like the below - // TodoController.js const Todo = use("App/Models/Todo"); class TodoController { async index({ request, response, view }) { return await Todo.query().fetch(); } } The index method outlined in the code block just queries all records and returns everything to caller. This is good as long as you have limited set of records within your database. If the to do records are in hundreds, thousands or more, you have a problem on your hand. ...

Role-based Access to Routes in AdonisJS

AdonisJS provides a standard way to define a middleware and enable access to routes based on defined validation rules. This middleware is leveraged to allow role-based access to routes. Your start | routes.js file will have something akin to below - const Route = use("Route"); Route.get("/", () => { return { greeting: "Hello world!" }; }); First, we will group routes for the different roles and introduce the middleware. // start | Routes.js Route.group(() => { Route.post("/user-register", "UserController.register"); Route.post("/user-login", "UserController.login"); }); Route.group(() => { Route.get("/todo", "TodoController.index"); Route.post("/todo", "TodoController.create"); }).middleware("auth"); Route.group(() => { Route.delete("/todo", "TodoController.delete"); }).middleware(["auth", "admin"]); register and login methods are available to unauthenticated and authenticated users To do create and index are available only to authenticated users. auth is provided by AdonisJS Deleting to do is allowed only for admin Now, we write the actual middleware for admin. ...

Change Date Formats in AdonisJS

AdonisJS internally uses moment.js and processes all dates in YYYY-MM-DD format. The format, being an international standard, should have been the standard everywhere. Since it is not, let us see how we can modify the date format. Consider an example - Todo has a end_date field against every record. Your model will look like the below - const Model = use("Model"); class Todo extends Model { /* model code */ } module.exports = Todo; First, inform Adonis that end_date is a valid date field. This is done by using a super that is applicable for all fields. Else, the value will not be serialized as date (not even in the international format). ...

Return Related Record Post Saving Record in AdonisJS

AdonisJS automatically returns the base/parent record to the caller from the controller. However, you may have to custom code all of one statement to return a related record after the parent record is committed to the database. Consider an example - // TodoController.js async create({ request, auth }) { const user = await auth.getUser(); const data = request.all(); const todo = new Todo(); todo.fill(data); // commit todo and any related entities sent // through data to the database await todo.save(); // this will populate any changes made by Adonis/DB await todo.load("user"); // user is related entity // query and popular user entity within todo // follows same serializer as rest of the application return todo; } When you create a Todo, the controller takes the data sent in the request and commits that to the database. Post commit todo variable will have the data from database after committing the data. ...

Simple Role-based Validation Techniques for AdonisJS

AdonisJS does not provide an access control list (ACL) feature out of the box. Here’s are a few simple ways to provide the right access to the right user when using AdonisJS. Use ACL plugins There are two plugins available for AdonisJS - Adonis ACL Advanced Adonis ACL The usage is pretty simple. Follow the instructions in the package to install package as a provider. Create a view based the role/permission data structure for ease-of-use. You could now create specific roles and permissions. ...