Créer un RESTFul API avec AdonisJS 5.0 (incluant l'authentification par token)
Tags: adonis, javascript, french, beginners
Published: 2021-07-25 11:35:22

---
title: Créer un RESTFul API avec AdonisJS 5.0 (incluant l'authentification par token)
published: true
description: AdonisJS est à Javascript ce que Laravel est à PHP. Adonis est donc un framework backend construit avec l'idée d'apporter une expérience développeur (DX) extraordinaire. 

tags: adonis, javascript, french, beginner
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t1kb0jy0zbz2trhy2uoa.png
canonical_url: https://www.ericlecodeur.com/creer-un-restful-api-avec-adonisjs-50-incluant-lauthentification-par-token
---
Si vous désirez plus de contenu francophone comme celui-ci, cliquer <strong>Follow<string> ou <a href="https://twitter.com/EricLeCodeur" class="twitter-follow-button">suivez-moi sur Twitter</a>
<hr>

AdonisJS est à Javascript ce que Laravel est à PHP. Adonis est donc un framework backend construit avec l'idée d'apporter une expérience développeur (DX) extraordinaire. 

Adonis rend disponible tous les outils que vous avez besoin pour bâtir une application fullstack de A à Z

Aujourd'hui vous allez découvrir comment bâtir un RESTful API avec Adonis. Vous allez même découvrir comment intégré l'authentification par token à votre API.

L'API que vous allez construire est une gestion de tâches. Vous aller créer un API pour créer des tâches, lire, effacer et mettre à jour des tâches

Vous allez également créer un API qui pourra créer un user et faire l'authentification. Ce dernier point peut vous sembler compliqué mais en faite Adonis à un package Auth qui s'occupe de presque tout.

<h1>Pré-requis</h1>
Avoir des connaissances de base sur les Restful API et sur les frameworks backend MVC

<h1>Partie 1 : Création du projet et de l'authentification</h1>
Créer un nouveau projet Adonis

```jsx
$ npm init adonis-ts-app@latest my-project-name

  choisir project structure API
```

 Une fois le project créé, vous pouvez lancer le serveur local :

```jsx
cd my-project-name
node ace serve -w
```

Installer et configurer le module de base de données

```jsx
npm i @adonisjs/lucid
node ace configure @adonisjs/lucid

  choisir SQLite
```
Ici Adonis va créer une base de donnée SQLite qui sera pré-configuré et accessible de votre application

Installer and configurer le module auth

```jsx
npm i @adonisjs/auth
node ace configure @adonisjs/auth
    
    - choisir Lucid
    - Saisir modèle User
    - choisir API Tokens
    - choisir créer la migration
    - choisir utiliser une base de donnée et créer la table pour stocker les Tokens 
```
Le module Auth va vous permettre faire un login avec token

Ajouter le champ username au modèle User
(app/models/user.ts)
```jsx
@column()
public username: string
```
Par défaut le champ username n'est pas créer, vous allez donc en créer un.

Ajouter le champ username au fichier de migration User
(database/migrations/xxxxxxxxx_users.ts)

```jsx
table.string('username', 255).notNullable()
table.string('email', 255)->notNullable().unique()
```

Lancer la migration (afin de créer la table users)

```jsx
node ace migration:run
```
La migration s'occupe de créer et mettre à jour les tables et champs de votre base de données.

Installer le module pour hasher le mot de passe

```jsx
npm i phc-argon2
```
Ce module vous servira à crypter le mot de passe de l'utilisateur

Création de la route post pour permettre d'ajouter un User
(start/routes.ts)

```jsx
Route.post('users', 'AuthController.register')
```

Création du validator:
(validators/Auth/StoreUserValidator.ts)

```jsx
node ace make:validator Auth/StoreUser
```
Les Validator permettent d'annuler un requête si cette requête ne passe pas la validation. 

Les Validator retournent également un message d'erreur de validation si la validation de passe pas

```jsx
import { schema, rules } from @ioc:Adonis/Core/Validator

public schema = schema.create({
    email: schema.string({ trim: true }, [
      rules.email(),
      rules.unique({ table: 'users', column: 'email ' }),
    ]),
    username: schema.string({ trim: true }),
    password: schema.string(),
})
```

Création du controller

```jsx
node ace make:controller Auth
```
Les controller contient toutes les fonctions que les routes vont exécuter

Ajouter une fonction 'register' au controller
(app/controllers/Http/AuthController.ts)

```jsx
public async register({ request, response } : HttpContextContract) {
  
  const payload = await request.validate(StoreUserValidator)

  const user = await User.create(payload.user)

  return response.created(user) // 201 CREATED
}
```
Cette fonction permet de créer un 'user' selon les informations soumis par l'API (email, username et password)

Login

```jsx
Route.post('users/login', 'AuthController.login')
```

Création du validator: Validators/Auth/LoginValidator.ts

```jsx
node ace make:validator Auth/Login
```

```jsx
import { schema, rules } from @ioc:Adonis/Core/Validator

public schema = schema.create({
    email: schema.string({}, [rules.email()]),
    password: schema.string()
})
```

Création de la fonction login dans le controller Auth

```jsx
public async login({ auth, request, response }: HttpContextContract) {

    const { email, password } = await request.validate(LoginValidator)

    const token = await auth.attempt(email, password)
    const user = auth.user!

    return response.ok({
      "token": token,
      ...user.serialize(),
    })
}
```
Cette fonction s'occupe de faire l'authentification et retourne un token que le client pourra utiliser pour accéder aux routes protégé.

Get user (start/route.ts)
```jsx
Route.get('user', 'AuthController.me').middleware(['auth'])
```

```jsx
public async me({auth, response} : HttpContextContract) {

  return response.ok({ auth.user })
}
```

Auth middleware (start/kernel.ts)

```jsx
Server.middleware.registerNamed({ auth: () => import('App/Middleware/Auth') })
```
Création du middleware qui permettre de vérifier le token

Création de la route put pour update User

```jsx
Route.put('users', 'AuthController.update').middleware(['auth'])
```

Création du validator: Validators/Auth/UpdateUserValidator.ts

```jsx
node ace make:validator Auth/UpdateUser
```

```jsx
import { schema, rules } from @ioc:Adonis/Core/Validator

public schema =  schema.create({
  email: schema.string.optional({ trim: true }, [ 
    rules.email(),
    rules.unique({ table: 'users', column: 'email' }),
  ]),
  username: schema.string.optional({ trim: true }),
  password: schema.string.optional(),
})
```

Création de la fonction update du controller Auth
(app/Controllers/Http/AuthController.ts)

```jsx
public async update({ auth, request, response } : HttpContextContract) {
  
  const payload = await request.validate(UpdateUserValidator)

  const user = await auth.user!.merge(payload).save()

  return response.ok(user) // 200 OK
}
```

<h1>Partie 2 - Création du modèle Task</h1>
Création du modèle, de la migration et du controller

```jsx
node ace make:model Task -cm
```

L'option -cm va créer le fichier de la migration et le fichier du controller

Ouvrir la migration et ajouter les champs voulus:

```jsx
public async up () {
    this.schema.createTable(this.tableName, (table) => {
      table.increments('id')
      table.integer('user_id').unsigned().references('users.id').onDelete('CASCADE')
      table.string('name').notNullable()
      table.boolean('is_done').defaultTo(false)
      table.timestamp('created_at', { useTz: true })
      table.timestamp('updated_at', { useTz: true })
    })
  }
```

Ouvrir le modèle et ajouter les columns et la relation belongTo

```jsx
import { DateTime } from 'luxon'
import { BaseModel, BelongsTo, belongsTo, column, hasMany, HasMany } from '@ioc:Adonis/Lucid/Orm'
import User from './User'

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

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

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

  @column()
  public name: string

  @column()
  public is_done: boolean

  @belongsTo(() => User)
  public user: BelongsTo<typeof User>
}
```

Ouvrir le fichier modèle User et ajouter le HasMany

```jsx
@hasMany(() => Task)
  public tasks: HasMany<typeof Task>
```

Créer les routes pour le CRUD de Tasks

```jsx
Route.resource('tasks', 'TaskController').apiOnly()

// Cette ligne de code va créer 5 chemin urls pour le CRUD

// Liste des tâches: GET /tasks (tasks.index)
// Sauvegarder une tâches: POST /tasks (tasks.store)
// Lire une tâche: GET tasks/:id (tasks.show)
// Mise à jour d'une tâche: PUT tasks/:id (tasks.update)
// Effacer une tâche: DELETE tasks/:id (tasks.destroy)

```

Dans le fichier TasksController créer les 5 actions CRUD

```jsx
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import Task from 'App/Models/Task'
import StoreTaskValidator from 'App/Validators/Tasks/StoreTaskValidator'
import UpdateTaskValidator from 'App/Validators/Tasks/UpdateTaskValidator'

export default class TasksController {
  public async index ({response}: HttpContextContract) {
    const tasks = await Task.all()
    return response.ok(tasks)
  }

  public async store ({ request, response }: HttpContextContract) {
    const payload = await request.validate(StoreTaskValidator)
    const task = await Task.create(payload)
    return response.created(task)
  }

  public async show ({ response, params }: HttpContextContract) {
    console.log(params)
    const task = await Task.findOrFail(params.id)
    return response.ok(task)
  }

  public async update ({ request, response, params }: HttpContextContract) {
    const task = await Task.findOrFail(params.id)
    const payload = await request.validate(UpdateTaskValidator)
    task.merge(payload).save()
    return response.ok(task)
  }

  public async destroy ({ response, params }: HttpContextContract) {
    const task = await Task.findOrFail(params.id)
    task.delete()
    return response.ok(task)
  }
}
```

Créer le StoreTaskValidator

```jsx
node ace make:validator Tasks/StoreTask

public schema = schema.create({
    name: schema.string(),
    is_done: schema.boolean(),
  })
```

Créer le UpdateTaskValidator

```jsx
node ace make:validator Tasks/UpdateTask

public schema = schema.create({
    name: schema.string.optinal(),
    is_done: schema.boolean.optional(),
  })
```

<h1>Conclusion</h1>
Comme vous avez sans douter constater, la syntaxe de Adonis pour créer un Restful API est très propre. Adonis est un des premiers, sinon le premier framework javascript qui rappel le plaisir et l'efficacité pour les développeurs d'utiliser un framework comme Laravel.