Files
twenty/packages/twenty-server/src/engine/api/rest/rest-api.service.ts
T
Shubham Singh 01535a3b3e fix(server): handle network errors in RestApiService catch block (#20644)
## Summary
- Added safe null check for `err.response?.data?.errors` in
`RestApiService.call()` catch block
- When the internal HTTP client fails with a network-level error
(ECONNREFUSED, timeout), `err.response` is `undefined` — accessing
`.data.errors` on it throws a `TypeError` which gets silently swallowed,
returning an empty 500
- Now falls back to throwing the raw error message for network failures
instead of crashing

## Changes
- `packages/twenty-server/src/engine/api/rest/rest-api.service.ts`

Fixes #20136

---------

Co-authored-by: Marie Stoppa <marie@twenty.com>
2026-05-18 09:51:42 +00:00

59 lines
1.6 KiB
TypeScript

import { Injectable } from '@nestjs/common';
import { type AxiosResponse } from 'axios';
import { type Query } from 'src/engine/api/rest/core/types/query.type';
import { RestApiException } from 'src/engine/api/rest/errors/RestApiException';
import { type RequestContext } from 'src/engine/api/rest/types/RequestContext';
import { SecureHttpClientService } from 'src/engine/core-modules/secure-http-client/secure-http-client.service';
import { isDefined } from 'twenty-shared/utils';
export enum GraphqlApiType {
CORE = 'core',
METADATA = 'metadata',
}
@Injectable()
export class RestApiService {
constructor(
private readonly secureHttpClientService: SecureHttpClientService,
) {}
async call(
graphqlApiType: GraphqlApiType,
requestContext: RequestContext,
data: Query,
) {
let response: AxiosResponse;
const url = `${requestContext.baseUrl}/${
graphqlApiType === GraphqlApiType.CORE
? 'graphql'
: GraphqlApiType.METADATA
}`;
// Internal request to the server's own GraphQL endpoint
const httpClient = this.secureHttpClientService.getInternalHttpClient();
try {
response = await httpClient.post(url, data, {
headers: {
'Content-Type': 'application/json',
Authorization: requestContext.headers.authorization,
},
});
} catch (err) {
if (isDefined(err.response?.data?.errors)) {
throw new RestApiException(err.response.data.errors);
}
throw err;
}
if (isDefined(response.data.errors) && response.data.errors.length > 0) {
throw new RestApiException(response.data.errors);
}
return response;
}
}