Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Add consistent field-level filtering to list endpoints via a shared query DTO base

Open
#230 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
25/100
Issue type
Refactor
Clarity
Mostly clear
Activity status
Active
Tech stack
nodejs, typescript
Domain
api, backend

Research direction

Start with the listFiles handler in src/infrastructure/file-upload/file-upload.controller.ts (around lines 116-121) and the QueryAuditLogDto used in src/infrastructure/audit/audit-log.service.ts, then read the existing cursor utility in src/common/pagination/. Done means the shared pagination and sort DTO bases exist, the file-upload query is migrated with its limit?: number annotation fixed, and tests cover default, boundary and over-limit values. Parameter renames are breaking, so each endpoint needs its own PR and a CHANGELOG.md entry.

Written by the indexing model from the issue text.

Description

enhancement help wanted intermediate

Problem

List endpoints take ad-hoc query parameters. src/infrastructure/file-upload/file-upload.controller.ts:116-121 is representative:

async listFiles(
  @Query("name") name?: string,
  @Query("category") category?: string,
  @Query("limit") limit?: number,
  @Query("offset") offset?: number,
) {

Note the type annotation limit?: number on a @Query() value — with transform: true the value arrives as a string, so this annotation is wrong and the ceiling is limit || 20 with no maximum.

Meanwhile src/infrastructure/audit/audit-log.service.ts uses a proper QueryAuditLogDto. The two approaches coexist, and there are 61 DTO files with no shared base.

Why it matters

Without a shared base, each list endpoint invents its own parameter names and semantics: page+limit in one place, limit+offset in another, unbounded in a third. Clients cannot predict the API, and each new endpoint repeats the same mistakes — unbounded limits, unvalidated strings, no sort control.

The @Query("limit") limit?: number annotation is also actively misleading: it tells a reader the value is a number when it is a string, which is precisely the kind of thing that produces a NaN reaching a database query.

Suggested Direction

  1. Create shared query DTOs in src/common/pagination/ (or a new src/common/dto/) alongside the existing cursor utility:
    export class PaginationQueryDto {
      @IsOptional() @Type(() => Number) @IsInt() @Min(1) @Max(100)
      limit?: number = 20;
      @IsOptional() @IsString()
      cursor?: string;
    }
    
    export class SortQueryDto {
      @IsOptional() @IsIn(['createdAt', 'updatedAt', 'name'])
      sortBy?: string;
      @IsOptional() @IsIn(['ASC', 'DESC'])
      sortDirection?: 'ASC' | 'DESC' = 'DESC';
    }
    
    Note @Type(() => Number) from class-transformer — required for transform: true to coerce query strings.
  2. Have every list DTO extend them, so limit, sortBy, sortDirection and cursor semantics are identical everywhere.
  3. Migrate incrementally, one controller at a time, starting with file-upload.controller.ts and the audit query. Fixing the wrong limit?: number annotation is a natural first step.
  4. Reject unknown query parameters. The global pipe already sets forbidNonWhitelisted: true, but that only applies to DTO-typed bodies/queries — a @Query("name") string parameter bypasses validation entirely. Moving to DTOs closes that gap.

Constraints

  • Changing parameter names is a breaking API change for affected endpoints. Migrate one endpoint per PR, and note each in CHANGELOG.md.
  • Keep the structured 400 validation-error shape intact — clients depend on it.
  • Ensure @Max() ceilings are set; see the pagination-bounds issue, which is complementary.
  • forbidUnknownValues: true is already set on the global pipe; verify it behaves correctly with these DTOs.

Acceptance Criteria

  • Shared pagination and sort DTO bases exist and are documented.
  • Every list DTO extends the base, or a documented migration list names those that do not yet.
  • No @Query("...") x?: number patterns remain (values are strings until transformed).
  • Every list endpoint enforces a maximum limit.
  • Unknown query parameters on migrated endpoints return 400.
  • Tests cover default, boundary, and over-limit values.
Dominant language
TypeScript
Stars
7
Forks
55
Avg merge
1d 17h
Merged PRs (30d)
5

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from SourceXXL/alian_structure-api

All issues in SourceXXL/alian_structure-api

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.