refactor: Migrate users.create endpoint to OpenAPI with AJV validation

Closed
AM
6mo ago
+120-109

Proposed changes

Migrates the users.create endpoint from the legacy addRoute() pattern to the new OpenAPI-compatible chained route pattern with inline AJV validation schemas.

Resolves: RocketChat/Rocket.Chat-Open-API#150

Changes

apps/meteor/app/api/server/v1/users.ts

  • Replaced legacy API.v1.addRoute('users.create', ...) with the new chained .post('users.create', ...) pattern on the existing usersEndpoints variable
  • Added local UserCreateParamsPOST type, userCreateParamsPostSchema, and isUserCreateParamsPOST validator (moved from rest-typings, names preserved exactly)
  • Added body: isUserCreateParamsPOST replacing deprecated validateParams
  • Added response validation schemas:
    • 200 with $ref: '#/components/schemas/IUser' via Typia
    • 400 with validateBadRequestErrorResponse
    • 401 with validateUnauthorizedErrorResponse
  • Used async function action() named handler (not arrow function)
  • Business logic, permissions, and side effects are completely unchanged
  • Types are automatically picked up via existing ExtractRoutesFromAPI<typeof usersEndpoints> + declare module augmentation at the bottom of the file

packages/rest-typings/src/v1/users.ts

  • Removed /v1/users.create entry from the UsersEndpoints interface (now auto-generated via ExtractRoutesFromAPI)
  • Removed import type { UserCreateParamsPOST } (no longer needed in this file)

packages/rest-typings/src/v1/users/UserCreateParamsPOST.ts

  • Removed the AJV schema (userCreateParamsPostSchema), compiled validator (isUserCreateParamsPOST), and ajv import — these are now defined locally in the endpoint file
  • Kept the UserCreateParamsPOST type export because it is imported by client code (AdminUserForm.tsx) for form typing

.changeset/migrate-users-create-openapi.md

  • Added changeset with minor bump for @rocket.chat/meteor and @rocket.chat/rest-typings

Test results

image

Note on the 1 failing test: The should create a new user with default roles test fails due to a pre-existing Typia schema mismatch — IUser.inactiveReason is typed as 'deactivated' | 'pending_approval' | 'idle_too_long' (optional), but the database returns null for newly created users. The Typia-generated $ref schema for IUser rejects null because the TypeScript type doesn't include it. This is not caused by this migration — any endpoint using $ref: '#/components/schemas/IUser' in response validation would hit this same issue. The fix belongs in core-typings (updating the inactiveReason type to include null) as a separate PR.

Summary by CodeRabbit

  • Documentation

    • OpenAPI support added for the users.create endpoint with formal request/response schemas and updated docs.
  • New Features

    • Stronger request/response validation for user creation and more consistent success/error responses.
  • Bug Fixes

    • Post-creation output cleaned up (null inactiveReason removed) and created user returned with a stable projection.