npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@melchyore/adonis-form-request

v1.0.0

Published

Use dedicated classes to authorize and validate requests

Downloads

1,065

Readme

Introduction

There is a division of opinion as to how controllers files should be simplified. Some suggest to create service classes that will handle all the logic but we will still have the same problem. To solve this, we can create a Request class that will handle both authorization and validation, in addition to lifecycle hooks to perform some actions before and after validation.

Form requests should be used to authorize only a specific request. If you have the same authorization logic for multiple requests, you should use a middleware.

Pre-requisites

Node.js >= 16.17.0

Installation

npm install @melchyore/adonis-form-request
# or
yarn add @melchyore/adonis-form-request
# or
pnpm install @melchyore/adonis-form-request

Configure

node ace configure @melchyore/adonis-form-request

Usage

node ace make:request StoreUser

It will create a file named StoreUserRequest.ts in App/Requests.

// App/Requests/StoreUserRequest.ts

import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

import { schema } from '@ioc:Adonis/Core/Validator'
import { FormRequest } from '@ioc:Adonis/Addons/FormRequest'

export default class StoreUserRequest extends FormRequest {
  constructor(protected context: HttpContextContract) {
    super(context)
  }

  /**
   * Determine if the user is authorized to make the incoming request.
   * Can be safely deleted if you don't have any authorization logic.
   */
  public async authorize() {
    return true
  }

  /**
   * Validation rules.
   * Can also return a Validator class.
   */
  public rules() {
    return {
      schema: schema.create({})
    }
  }

  /**
   * Before hook to be executed before validation.
   */
  protected async before() {}

  /**
   * After hook to be executed after successful validation.
   */
  protected async after() {}
}
  • authorize() returns a boolean. This method is used to authorize the incoming request. If you don't have an authorization logic, you can delete the method as it always returns true in the parent class. When it returns false, an HTTP response with status code 403 will be returned and the controller method will not be executed.

  • rules() returns a schema validator or a validator class.

  • before() doesn't return anything. You can perform some actions before validation. If you want to access request data, you can do it through this.context.request.

  • after() doesn't return anything. You can perform some actions after validation. If you want to access validated data, you can do it through this.validated().

Then, in a controller, you need to import the formRequest decorator and your file and type-hint the request argument with your form request class.

// App/Controllers/Http/UsersController.ts

import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

import { formRequest } from '@melchyore/adonis-form-request/build'

import StoreUserRequest from 'App/Requests'

export default class UsersController {
  @formRequest()
  public async store(context: HttpContextContract, request: StoreUserRequest) {
    await User.create(request.validated())
  }
}

When using a Form request class, you should never use request from context, always use the request argument.

It has the same methods and properties as the default Request class, in addition to new methods.

  • validated() returns the validated data.

  • safe() returns in instance of ValidatedInput.

  • safe().all() returns the same data as validated().

  • safe().only(['foo', 'bar']) returns only the specified validated keys.

  • safe().except(['foo', 'bar']) returns all validated data except specified keys.

  • safe().merge({ foo: 'Foo' }) merges and returns the specified data with the validated data.

Note

All the above methods are typed.

Note

If the validation fails, an HTTP response with status code 422 will be returned and the controller method will not be executed.

Usage with route model binding

When using route model binding and form request on the same controller method (same request), the request argument must be the last one.

// App/Controllers/Http/PostsController.ts

import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

import { bind } from '@adonisjs/route-model-binding'
import { formRequest } from '@melchyore/adonis-form-request/build'

import Post from 'App/Models/Post'
import UpdatePostRequest from 'App/Requests/UpdatePostRequest'

export default class PostsController {
  @bind()
  @formRequest()
  public async update ({ response }: HttpContextContract, post: Post, request: UpdatePostRequest) {
    const { title, content } = request.validated()

    await post.merge({
      title,
      content
    })
      .save()

    return response.ok(post)
  }
}

You have also access to the bindings in the form request class. You can use them to authorize the requests.

// App/Requests/UpdatePostRequest.ts

import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

import { schema } from '@ioc:Adonis/Core/Validator'
import { FormRequest } from '@ioc:Adonis/Addons/FormRequest'

export default class UpdatePostRequest extends FormRequest {
  private post: Post // ⬅ Will automatically have the post instance as value.

  constructor(protected context: HttpContextContract) {
    super(context)
  }

  /**
   * Determine if the user is authorized to make the incoming request.
   * Can be safely deleted if you don't have any authorization logic.
   */
  public async authorize() {
    return this.context.auth.user.id === this.post.userId
  }

  /**
   * Validation rules.
   * Can also return a Validator class.
   */
  public rules() {
    return {
      schema: schema.create({
        title: schema.string({ trim: true }),
        content: schema.string({ trim: true })
      })
    }
  }

  /**
   * Before hook to be executed before validation.
   */
  protected async before() {}

  /**
   * After hook to be executed after successful validation.
   */
  protected async after() {}
}

Note

The Request class has the method post() which is deprecated, and the form request class returns an instance of Request, so if you are still using it, don't name your argument post as it will override the method.

Note

Bindings are not available in the form request constructor.

Run tests

yarn run test

Author

👤 Oussama Benhamed

🤝 Contributing

Contributions, issues and feature requests are welcome!Feel free to check issues page. You can also take a look at the contributing guide.

Show your support

Give a ⭐️ if this project helped you!

📝 License

Copyright © 2022 Oussama Benhamed. This project is MIT licensed.