Adonisjs rest API crud setup

I will help you get started with Adonisjs by performing an API CRUD operation in this article. So, we are going to develop a simple Post module by using AdonisJs.

Firstly, we will install the Adonisjs version 5.

$ npm init adonis-ts-app crud

After successful installation Adonisjs version 5, run the following below command to start the application

You can purchase your hosting from Cloudsurph.comCloudsurph hosting is a reliable hosting option for business and personal projects. We offer insight and help on system configuration issues and code errors or bugs.
$ node ace serve --watch

Now, when you enter http://localhost:3333, you will see the Adonisjs front page.

AdonisJS-v5-A-Simple-API-CRUD-Application-Home-Page-Show

Also, we have to need to install the @adonisjs/lucid package for database support.

$ npm i @adonisjs/lucid

When installing the package, we should configure the database that we are ready to use. My choice is MySQL

$ node ace configure @adonisjs/lucid

Now, based on the database selection, Adonisjs will automatically copy the environmental variables to the .env file like the following below.

MYSQL_HOST=localhost
MYSQL_PORT=3306
MYSQL_USER=lucid
MYSQL_PASSWORD=
MYSQL_DB_NAME=lucid

So, now let’s create a migration and model file in Adonisjs, you can perform both with only a simple command.

$ node ace make:model Post -m

You can open the migration file under the database folder and add the necessary columns.

import BaseSchema from '@ioc:Adonis/Lucid/Schema'

export default class Posts extends BaseSchema {
protected tableName = 'posts'

public async up() {
this.schema.createTable(this.tableName, (table) => {
table.increments('id')
table.string('title', 255)
table.text('content', 'long')
table.specificType('status', 'tinyint(1)').unsigned().defaultTo(1);
table.timestamp('created_at', { useTz: true })
table.timestamp('updated_at', { useTz: true })
})
}

public async down() {
this.schema.dropTable(this.tableName)
}
}

When the migration file is ready, then let’s check the migration status before you migrate.

$ node ace migration:status

You can see, that our migration file is pending, so we can go ahead and run the migration

$ node ace migration:run

Perfectly done! Now we have the table migrated and set up. Now we can focus on the model file.

import { DateTime } from 'luxon'
import { BaseModel, column } from '@ioc:Adonis/Lucid/Orm'

export default class Post extends BaseModel {
@column({ isPrimary: true })
public id: number

@column()
public title: string

@column()
public content: string

@column()
public status: string

@column.dateTime({ autoCreate: true })
public createdAt: DateTime

@column.dateTime({ autoCreate: true, autoUpdate: true })
public updatedAt: DateTime
}

So, here as you can see, we have to explicitly mention all the columns as properties on the model file, or else the typescript compiler would throw Property not exist on the Post model.

IF you want then buy a good, reliable, secure web hosting service  from here: click here

Now we need to configure the necessary routes on the routes.ts file.

import Route from '@ioc:Adonis/Core/Route'

Route.resource('posts', 'PostsController').apiOnly()

The above code will create all the post module routes for us. Kindly note, that I’ve added apiOnly() at the end of the line.

This means both CREATE and SHOW routes will be ignored.

So, now our routes, model, and migration files are ready, need to create a controller file.

$ node ace make:controller Post
export default class PostsController {

}

Here we will add relevant methods to PostsController now

Listing

When we enter the route /posts on GET method, we should receive all the posts.

So, we need to add the index method on the PostsController and pull all the records from the Post model.

import Post from 'App/Models/Post'

export default class PostsController {
public async index({ response }) {
const posts = await Post.all()

return response.ok(posts)
}
}

Create

When we try to create a post by entering /posts on POST method, first we should validate whether we are receiving all the params from the client.

If not, then we have to validate the parameters and throw errors accordingly.

Adonisjs provides an easy inbuilt Validator which comes in handy for scenarios like this.

import Post from 'App/Models/Post'
import { schema, rules } from '@ioc:Adonis/Core/Validator'

export default class PostsController {

public async index({ response }) {
}

public async store({ request, response }) {
const postSchema = schema.create({
title: schema.string({ trim: true }, [
rules.maxLength(255)
]),
content: schema.string({ escape: true }, [
rules.maxLength(1000)
]),
})

const payload: any = await request.validate({ schema: postSchema })
const post: Post = await Post.create(payload)

return response.ok(post)
}
}

Show

Now for retrieving a post resource, we’ve to enter the show API with the post identifier passed on the URL that is, /posts/1 on GET method.

import Post from 'App/Models/Post'
import { schema, rules } from '@ioc:Adonis/Core/Validator'

export default class PostsController {
public async index({ response }) {
}

public async store({ request, response }) {
}

public async show({ params, response }) {
const { id }: { id: Number } = params

const post: any = await Post.find(id)
if (!post) {
return response.notFound({ message: 'Post not found' })
}

return response.ok(post)
}
}

Update

When you need to update a post resource, we need two checks.

  1. Validate the input params
  2. Make sure the post resource exists on the database

Now, borrowing some of the code from store() and show() method, our update method will typically look like the following.

Here we can optimize the code by eliminating the code duplication of validation and post resource check but keeping them simple for now.

import Post from 'App/Models/Post'
import { schema, rules } from '@ioc:Adonis/Core/Validator'

export default class PostsController {
public async index({ response }) {
}

public async store({ request, response }) {
}

public async show({ params, response }) {
}

public async update({ request, params, response }) {
const postSchema = schema.create({
title: schema.string({ trim: true }, [
rules.maxLength(255)
]),
content: schema.string({ escape: true }, [
rules.maxLength(1000)
]),
})

const payload: any = await request.validate({ schema: postSchema })

const { id }: { id: Number } = params

const post: any = await Post.find(id)
if (!post) {
return response.notFound({ message: 'Post not found' })
}

post.title = payload.title
post.content = payload.content

await post.save()

return response.ok(post)
}
}

Destroy

Now, Similar to the show() method, we’ve to first check the resource availability before we can delete the resource.

import Post from 'App/Models/Post'
import { schema, rules } from '@ioc:Adonis/Core/Validator'

export default class PostsController {
public async index({ response }) {
}

public async store({ request, response }) {
}

public async show({ params, response }) {
}

public async update({ params, response }) {
}

public async destroy({ params, response }) {
const { id }: { id: Number } = params

const post: any = await Post.find(id)
if (!post) {
return response.notFound({ message: 'Post not found' })
}

await post.delete()

return response.ok({ message: 'Post deleted successfully.' })
}
}

Finally, our PostsController will look like this below:

import Post from 'App/Models/Post'
import { schema, rules } from '@ioc:Adonis/Core/Validator'

export default class PostsController {
public async index({ response }) {
const posts = await Post.all()

return response.ok(posts)
}

public async store({ request, response }) {
const postSchema = schema.create({
title: schema.string({ trim: true }, [
rules.maxLength(255)
]),
content: schema.string({ escape: true }, [
rules.maxLength(1000)
]),
})

const payload: any = await request.validate({ schema: postSchema })
const post: Post = await Post.create(payload)

return response.ok(post)
}

public async show({ params, response }) {
const { id }: { id: Number } = params

const post: any = await Post.find(id)
if (!post) {
return response.notFound({ message: 'Post not found' })
}

return response.ok(post)
}

public async update({ request, params, response }) {
const postSchema = schema.create({
title: schema.string({ trim: true }, [
rules.maxLength(255)
]),
content: schema.string({ escape: true }, [
rules.maxLength(1000)
]),
})

const payload: any = await request.validate({ schema: postSchema })

const { id }: { id: Number } = params

const post: any = await Post.find(id)
if (!post) {
return response.notFound({ message: 'Post not found' })
}

post.title = payload.title
post.content = payload.content

await post.save()

return response.ok(post)
}

public async destroy({ params, response }) {
const { id }: { id: Number } = params

const post: any = await Post.find(id)
if (!post) {
return response.notFound({ message: 'Post not found' })
}

await post.delete()

return response.ok({ message: 'Post deleted successfully.' })
}
}

That’s it for CRUD. Now we have got a fully functional Post module built on Adonisjs.

That’s it. If you enjoyed reading this article and have more questions please reach out to our support team via live chat or email and we would be glad to help you. we provide server hosting for all types of need and we can even get your server up and running with the service of your choice.