Skip to content

fix: error handling for intent api endpoints#1560

Merged
pranalidhanavade merged 4 commits intomainfrom
fix/error-handling-for-intent-api-endpoints
Feb 11, 2026
Merged

fix: error handling for intent api endpoints#1560
pranalidhanavade merged 4 commits intomainfrom
fix/error-handling-for-intent-api-endpoints

Conversation

@pranalidhanavade
Copy link
Contributor

@pranalidhanavade pranalidhanavade commented Feb 10, 2026

What

  • fix: error handling for intent api endpoints

Summary by CodeRabbit

  • New Features

    • Automatic trimming for incoming fields (including intentName and verifierOrgId) and clearer required-field messages.
    • orgId for intent-template creation/update is now optional.
  • Bug Fixes

    • Consistent UUID validation with explicit invalid-ID errors across ecosystem, intent, and template endpoints.
    • Stronger existence checks and clearer not-found/conflict responses for ecosystems, intents, and templates.
    • Added ecosystem-specific error messages for missing intents and intentId.

@coderabbitai
Copy link

coderabbitai bot commented Feb 10, 2026

📝 Walkthrough

Walkthrough

Adds input trimming and UUID validation to API Gateway ecosystem endpoints, tightens DTO validation, changes some public user parameter types, adds existence and duplicate checks with explicit error responses in ecosystem service, relaxes repository not-found behavior to return null, and adds new ecosystem error messages.

Changes

Cohort / File(s) Summary
API Gateway Controller
apps/api-gateway/src/ecosystem/ecosystem.controller.ts
Applied TrimStringParamPipe and ParseUUIDPipe to many path/query params, trim IDs before service calls, and changed several handler user parameter types from IUserRequest to Prisma user.
API Gateway Service
apps/api-gateway/src/ecosystem/ecosystem.service.ts
Updated intent-template methods to accept Prisma user (use user.id), and propagate trimmed/validated IDs in NATS/service payloads.
DTOs
apps/api-gateway/src/utilities/dtos/get-intent-template-by-intent-and-org.dto.ts, apps/api-gateway/src/utilities/dtos/intent-template.dto.ts
Added @Transform trimming and explicit IsNotEmpty messages for intentName/verifierOrgId; made orgId optional in create/update intent-template DTOs.
Ecosystem Controller (microservice)
apps/ecosystem/src/ecosystem.controller.ts
Message-pattern handlers now accept payload objects ({ intentId }, { orgId }, { id }) instead of primitive string params and forward extracted fields to service methods.
Ecosystem Service (business logic)
apps/ecosystem/src/ecosystem.service.ts
Added existence checks for ecosystems/intents/templates, duplicate-detection with CONFLICT, NotFound/RpcException error paths, and additional contextual logging.
Repository
apps/ecosystem/repositories/ecosystem.repository.ts
getIntentTemplateById now returns `Promise<intent_templates
Common Messages
libs/common/src/response-messages/index.ts
Added ecosystem.error.intentNotFound and ecosystem.error.intentIdIsRequired message entries.

Sequence Diagram(s)

sequenceDiagram
    rect rgba(200,200,255,0.5)
    participant Client
    end
    rect rgba(200,255,200,0.5)
    participant API_Gateway as API Gateway
    end
    rect rgba(255,200,200,0.5)
    participant Ecosystem_MS as Ecosystem Service
    end
    participant Repo as Repository/DB

    Client->>API_Gateway: HTTP request (path/query with IDs)
    Note right of API_Gateway: TrimStringParamPipe\nParseUUIDPipe validate & trim IDs
    API_Gateway->>Ecosystem_MS: call with trimmed UUIDs and user.id
    Ecosystem_MS->>Repo: existence checks (ecosystem / intent / template)
    alt found
        Repo-->>Ecosystem_MS: record(s)
        Ecosystem_MS-->>API_Gateway: success payload
        API_Gateway-->>Client: 200 OK
    else missing or duplicate
        Repo-->>Ecosystem_MS: null or conflict
        Ecosystem_MS-->>API_Gateway: NotFound / Conflict (RpcException)
        API_Gateway-->>Client: 4xx error response
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • sujitaw
  • shitrerohit

Poem

"🐰 I trim each string with careful paws,

UUIDs checked with tidy laws,
Services ask if records stay,
Repos may yield null today,
Hopping through logs, I bless the cause."

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the primary focus of the changeset, which involves comprehensive error handling improvements and input validation enhancements across intent-related API endpoints.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/error-handling-for-intent-api-endpoints

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/api-gateway/src/ecosystem/ecosystem.controller.ts (1)

659-659: ⚠️ Potential issue | 🟡 Minor

Missing TrimStringParamPipe and ParseUUIDPipe on id param for deleteIntentTemplate.

Same inconsistency as updateIntentTemplate — the id param should be validated.

Proposed fix
- async deleteIntentTemplate(`@Param`('id') id: string, `@Res`() res: Response): Promise<Response> {
+ async deleteIntentTemplate(
+   `@Param`(
+     'id',
+     TrimStringParamPipe,
+     new ParseUUIDPipe({
+       exceptionFactory: (): Error => {
+         throw new BadRequestException(ResponseMessages.oid4vpIntentToTemplate.error.invalidId);
+       }
+     })
+   )
+   id: string,
+   `@Res`() res: Response
+ ): Promise<Response> {
🤖 Fix all issues with AI agents
In `@apps/api-gateway/src/ecosystem/ecosystem.controller.ts`:
- Around line 632-633: The id parameter in updateIntentTemplate needs the same
validation as other endpoints—apply TrimStringParamPipe and ParseUUIDPipe to the
`@Param`('id') decorator so whitespace-trimmed values and invalid UUIDs are
rejected; locate the updateIntentTemplate method and change its `@Param`('id')
usage to include TrimStringParamPipe and ParseUUIDPipe (matching the pattern
used in getIntentTemplateById/deleteIntent) so the id argument is validated and
trimmed before use.
- Around line 746-748: The optional query param intentId is only trimmed but not
validated as a UUID; update the controller method (the parameter and call to
ecosystemService.getIntents) to validate intentId with Nest's ParseUUIDPipe when
present: import ParseUUIDPipe and, before calling
this.ecosystemService.getIntents, if (intentId) run new ParseUUIDPipe({ version:
'4' }).transform(intentId.trim(), { type: 'query', metatype: String }) (or apply
an equivalent parameter pipe that only runs when a value exists), then pass the
validated value to getIntents to prevent invalid DB queries.

In `@apps/api-gateway/src/utilities/dtos/intent-template.dto.ts`:
- Around line 28-31: Update UpdateIntentTemplateDto.intentId to be required to
match service validation: remove the `@IsOptional`() decorator from the intentId
property on the UpdateIntentTemplateDto class so the DTO enforces presence of
intentId (and ensure the TypeScript property is not optional — e.g., no trailing
? — to match the decorator change); this keeps DTO validation consistent with
the required check in ecosystem.service (the code path that currently expects a
required intentId).

In `@apps/ecosystem/src/ecosystem.service.ts`:
- Around line 687-689: The error message thrown when userId is missing is
grammatically incorrect; update the BadRequestException call that checks if
(!userId) to use a correct message such as "userId is required" (or "userId is
required."). Locate the conditional that throws new BadRequestException('userId
are required') and replace the string with the corrected message so the check in
the function that references userId and the BadRequestException reflects proper
grammar.
- Around line 575-582: The method in ecosystem.service.ts that accepts
templateData (typed so intentId is required) must be updated to match
UpdateIntentTemplateDto where intentId is optional: change the method signature
so templateData.intentId is typed as string | undefined (e.g., accept
templateData: UpdateIntentTemplateDto or declare intentId?: string in the
parameter destructure), update any internal uses to handle undefined
accordingly, and adjust callers if necessary so TypeScript enforces the
optionality instead of relying on the runtime guard; reference
UpdateIntentTemplateDto and the templateData.intentId usage to locate the
change.
🧹 Nitpick comments (3)
apps/ecosystem/src/ecosystem.service.ts (3)

629-633: Good: validates ecosystem existence before creating an intent.

This aligns with the design that intent records always require a valid ecosystemId.

One minor inconsistency: this throws NotFoundException (NestJS HTTP exception) while the similar check in getIntentTemplatesByIntentId (line 496) throws RpcException. In a microservice context, RpcException is the canonical way to propagate errors back to the API gateway. Consider using RpcException here for consistency.

Proposed fix for consistency
      if (!ecosystem) {
-       throw new NotFoundException(ResponseMessages.ecosystem.error.ecosystemNotFound);
+       throw new RpcException({
+         statusCode: HttpStatus.NOT_FOUND,
+         message: ResponseMessages.ecosystem.error.ecosystemNotFound
+       });
      }

Based on learnings: "ecosystemId is NOT NULL because intent records are never created without an ecosystemId in the application workflow."


691-696: Consider validating that the intent exists before updating.

updateIntentTemplate (line 585) validates the record exists before updating; updateIntent does not. If the intent is missing, Prisma will throw a generic P2025 error that gets wrapped as "Failed to update intent" — a proper 404 would be more helpful to callers. This is especially relevant given the PR's stated goal of improving error handling for intent API endpoints.

Proposed fix
      if (!userId) {
        throw new BadRequestException('userId is required');
      }

+     const existingIntent = await this.ecosystemRepository.findIntentById(updateIntentDto.intentId);
+     if (!existingIntent) {
+       throw new RpcException({
+         statusCode: HttpStatus.NOT_FOUND,
+         message: ResponseMessages.ecosystem.error.intentNotFound
+       });
+     }
+
      const intent = await this.ecosystemRepository.updateIntent({

713-721: deleteIntent lacks error handling, inconsistent with the rest of the PR.

This method has no try/catch, no existence validation, and no ErrorHandler.categorize — unlike every other intent method in this file (including deleteIntentTemplate at line 609). Given the PR's goal of improving error handling for intent endpoints, this seems like an oversight.

Proposed fix
  async deleteIntent(data: { ecosystemId: string; intentId: string; userId: string }): Promise<object> {
    const { ecosystemId, intentId, userId } = data;
-
-   return this.ecosystemRepository.deleteIntent({
-     ecosystemId,
-     intentId,
-     userId
-   });
+   try {
+     const intent = await this.ecosystemRepository.findIntentById(intentId);
+     if (!intent) {
+       throw new RpcException({
+         statusCode: HttpStatus.NOT_FOUND,
+         message: ResponseMessages.ecosystem.error.intentNotFound
+       });
+     }
+
+     return await this.ecosystemRepository.deleteIntent({
+       ecosystemId,
+       intentId,
+       userId
+     });
+   } catch (error) {
+     const errorResponse = ErrorHandler.categorize(error, 'Failed to delete intent');
+     this.logger.error(
+       `[deleteIntent] - ${errorResponse.statusCode}: ${errorResponse.message}`,
+       ErrorHandler.format(error)
+     );
+     throw new RpcException(errorResponse);
+   }
  }

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@apps/api-gateway/src/ecosystem/ecosystem.controller.ts`:
- Around line 755-763: The ParseUUIDPipe on the optional query param intentId
will error when intentId is omitted; update the ParseUUIDPipe instantiation used
on the intentId parameter so it allows undefined by passing optional: true into
its options (i.e., new ParseUUIDPipe({ optional: true, exceptionFactory: ...
})), ensuring the BadRequestException behavior remains for invalid UUIDs but
does not reject requests that omit intentId in the ecosystem.controller.ts
endpoint.

In `@apps/ecosystem/src/ecosystem.service.ts`:
- Around line 642-646: Replace the HTTP NotFoundException thrown after the call
to this.ecosystemRepository.getEcosystemById(ecosystemId) with an RpcException
that carries the same message and HttpStatus.NOT_FOUND (mirror the pattern
already used earlier), and do the same change in the getIntents flow at the
corresponding check; ensure RpcException and HttpStatus are imported/available
and use the same ResponseMessages.ecosystem.error.ecosystemNotFound message so
transport-aware microservice clients receive the statusCode correctly.
🧹 Nitpick comments (1)
apps/ecosystem/src/ecosystem.service.ts (1)

696-709: updateIntent does not verify the intent exists before updating.

Other mutating methods (updateIntentTemplate at line 582, createIntent at line 642) now validate entity existence before proceeding. updateIntent skips this — if the intentId refers to a non-existent record, the repository call will either silently no-op or throw an opaque Prisma error. Consider adding a findIntentById check before the update, consistent with the pattern established elsewhere in this PR.

Proposed addition before line 704
+     const existingIntent = await this.ecosystemRepository.findIntentById(updateIntentDto.intentId);
+     if (!existingIntent) {
+       throw new RpcException({
+         statusCode: HttpStatus.NOT_FOUND,
+         message: ResponseMessages.ecosystem.error.intentNotFound
+       });
+     }
+
      const intent = await this.ecosystemRepository.updateIntent({

Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>
Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>
Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>
Signed-off-by: pranalidhanavade <pranali.dhanavade@ayanworks.com>
@pranalidhanavade pranalidhanavade force-pushed the fix/error-handling-for-intent-api-endpoints branch from dac75b5 to 55d2688 Compare February 11, 2026 15:25
@sonarqubecloud
Copy link

@pranalidhanavade pranalidhanavade merged commit bbc11bb into main Feb 11, 2026
7 of 8 checks passed
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@apps/ecosystem/src/ecosystem.service.ts`:
- Around line 731-735: The null-checks in ecosystem.service.ts are dead because
ecosystemRepository.getEcosystemById and getIntents already throw
NotFoundException on missing records; remove the unreachable guards (the if
(!ecosystem) throw ... block around the call to getEcosystemById and the
analogous if (!intents) check around getIntents) so the service relies on the
repository to raise NotFoundException, or alternatively change the repository
methods (getEcosystemById/getIntents) to return null and move the
NotFoundException into the service—pick one consistent approach (prefer removing
the redundant checks in the service to match current repository behavior).

In `@libs/common/src/response-messages/index.ts`:
- Line 215: The response-messages export includes an unused constant
intentIdIsRequired; remove the intentIdIsRequired entry from the messages object
in libs/common/src/response-messages/index.ts (leaving intentNotFound intact,
which is used by ecosystem.service.ts) and run a quick search for
intentIdIsRequired to confirm it has no references before committing; if you
intended to validate/messaging in ecosystem logic instead, add usage of
intentIdIsRequired in the appropriate validation path (e.g., the method in
ecosystem.service that checks for a missing intent id) rather than keeping an
unused constant.
🧹 Nitpick comments (1)
apps/ecosystem/repositories/ecosystem.repository.ts (1)

643-660: Log message is misleading when the template is not found.

Line 654 logs fetched id ${id} regardless of whether the record was actually found. This can be confusing when debugging null-return cases.

Proposed fix
-      this.logger.log(`[getIntentTemplateById] fetched id ${id}`);
+      this.logger.log(`[getIntentTemplateById] id=${id} found=${!!intentTemplate}`);

Comment on lines +731 to 735
const ecosystem = await this.ecosystemRepository.getEcosystemById(ecosystemId);

if (!name || !ecosystemId || !userId) {
throw new BadRequestException('name, ecosystemId and userId are required');
if (!ecosystem) {
throw new NotFoundException(ResponseMessages.ecosystem.error.ecosystemNotFound);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Dead code: getEcosystemById never returns null.

The repository method getEcosystemById (Line 614–627 of ecosystem.repository.ts) throws NotFoundException when the ecosystem is not found, so it never returns a falsy value. The if (!ecosystem) check here is unreachable. The same applies to getIntents at Lines 761–765.

Either remove the dead checks or change the repository to return null (like getIntentTemplateById was changed in this PR) and handle the not-found case here.

🤖 Prompt for AI Agents
In `@apps/ecosystem/src/ecosystem.service.ts` around lines 731 - 735, The
null-checks in ecosystem.service.ts are dead because
ecosystemRepository.getEcosystemById and getIntents already throw
NotFoundException on missing records; remove the unreachable guards (the if
(!ecosystem) throw ... block around the call to getEcosystemById and the
analogous if (!intents) check around getIntents) so the service relies on the
repository to raise NotFoundException, or alternatively change the repository
methods (getEcosystemById/getIntents) to return null and move the
NotFoundException into the service—pick one consistent approach (prefer removing
the redundant checks in the service to match current repository behavior).

failInvitationUpdate: 'Failed to update Ecosystem Invitation',
ecosystemIdIsRequired: 'ecosystemId is required',
notCreated: 'Error while creating ecosystem',
intentNotFound: 'Ecosystem intent not found',
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

rg -n "intentIdIsRequired" --type ts

Repository: credebl/platform

Length of output: 156


🏁 Script executed:

rg -n "intentNotFound" --type ts

Repository: credebl/platform

Length of output: 269


Remove unused error message intentIdIsRequired.

intentNotFound (line 215) is properly consumed in ecosystem.service.ts:587. However, intentIdIsRequired (line 275) is defined but never referenced anywhere in the codebase. Either use it in the corresponding service/controller logic or remove it to keep the message constants clean.

🤖 Prompt for AI Agents
In `@libs/common/src/response-messages/index.ts` at line 215, The
response-messages export includes an unused constant intentIdIsRequired; remove
the intentIdIsRequired entry from the messages object in
libs/common/src/response-messages/index.ts (leaving intentNotFound intact, which
is used by ecosystem.service.ts) and run a quick search for intentIdIsRequired
to confirm it has no references before committing; if you intended to
validate/messaging in ecosystem logic instead, add usage of intentIdIsRequired
in the appropriate validation path (e.g., the method in ecosystem.service that
checks for a missing intent id) rather than keeping an unused constant.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants