Bas van Dijk
Bas van Dijk

Reputation: 10703

Automatically parse query parameter to object when defined in NestJS

I am writing a NestJS application. Some of the endpoints support sorting e.g. http://127.0.0.1:3000/api/v1/members?sort=-id&take=100 Which means sort by id descending.

This parameter arrives as a @Query parameter and is passed to my service. This service transforms it into an object which is used by TypeORM:

{
  id: 'DESC'
}

I don't want to call this conversion method manually every time I need sorting.

I've tried an intercepter but this one could not easily change the request parameters into the desired object.

A pipe worked but then I still need to add @Query(new SortPipe()) for every endpoint definition.

Another option is in the repository itself. The NestJS documentation is very well written, but misses guidance in where to put what.

Is there someone who had a similar issue with converting Query parameters before they are used in NestJS, and can explain what approach is the best within NestJS?

This question might look like an opinion based question, however I am looking for the way it is supposed to be done with the NestJS philosophy in mind.

Upvotes: 4

Views: 7311

Answers (1)

dols3m
dols3m

Reputation: 1945

Pipes are probably the easiest way to accomplish this. Instead of adding your pipe for every endpoint definition you can add a global pipe that will be called on every endpoint. In your main.ts:

async function bootstrap() {
  ...
  app.useGlobalPipes(new SortPipe());
  ...
}

You can then create a pipe like this:

import { PipeTransform, Injectable, ArgumentMetadata } from '@nestjs/common';

@Injectable()
export class SortPipe implements PipeTransform {
  transform(value: any, metadata: ArgumentMetadata) {
    const { type } = metadata;
    // Make sure to only run your logic on queries
    if (type === 'query') return this.transformQuery(value);

    return value;
  }

  transformQuery(query: any) {
    if (typeof query !== 'object' || !value) return query;

    const { sort } = query;
    if (sort) query.sort = convertForTypeOrm(sort);

    return query;
  }
}

If you do not want sort value on ALL endpoints to be automatically converted, you can pass custom parameter to @Query(), for example @Query('sort'). And then:

  transform(value: any, metadata: ArgumentMetadata) {
    const { type, data } = metadata;
    // Make sure to only run your logic on queries when 'sort' is supplied
    if (type === 'query' && data === 'sort') return this.transformQuery(value);

    return value;
  }

Upvotes: 3

Related Questions