Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/core/components/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,11 @@ export abstract class AbstractRequest<ResponseType, ServiceResponse extends obje
if (headers) request.headers = headers;

// Attach body (if required).
if (request.method === TransportMethod.POST || request.method === TransportMethod.PATCH) {
if (
request.method === TransportMethod.POST ||
request.method === TransportMethod.PATCH ||
request.method === TransportMethod.PUT
) {
const [body, formData] = [this.body, this.formData];
if (formData) request.formData = formData;
if (body) request.body = body;
Expand Down
4 changes: 4 additions & 0 deletions src/core/types/transport-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ export enum TransportMethod {
* Request will be sent using `PATCH` method.
*/
PATCH = 'PATCH',
/**
* Request will be sent using `PUT` method.
*/
PUT = 'PUT',
/**
* Request will be sent using `DELETE` method.
*/
Expand Down
52 changes: 52 additions & 0 deletions src/errors/pubnub-api-error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,29 @@ export class PubNubAPIError extends Error {
) {
errorData = errorResponse;
status = errorResponse.status;
} else if (
'errors' in errorResponse &&
Array.isArray(errorResponse.errors) &&
errorResponse.errors.length > 0
) {
// Handle DataSync-style structured error responses:
// { errors: [{ errorCode: "SYN-0008", message: "...", path: "/id" }] }
errorData = errorResponse;

const errors = errorResponse.errors as Array<{
errorCode?: string;
message?: string;
path?: string;
}>;

message = errors
.map((e) => {
const parts: string[] = [];
if (e.errorCode) parts.push(e.errorCode);
if (e.message) parts.push(e.message);
return parts.join(': ');
})
.join('; ');
} else errorData = errorResponse;

if ('error' in errorResponse && errorResponse.error instanceof Error) errorData = errorResponse.error;
Expand Down Expand Up @@ -229,6 +252,35 @@ export class PubNubAPIError extends Error {
};
}

/**
* Format a user-facing error message for this API error.
*
* When the error contains structured details extracted from the service response
* (e.g., DataSync `errors` array), those details are included in the message.
* Otherwise, falls back to a generic description.
*
* @param operation - Request operation during which error happened.
*
* @returns Formatted error message string.
*/
public toFormattedMessage(operation: RequestOperation): string {
const fallback = 'REST API request processing error, check status for details';

// When errorData contains a structured `errors` array, `this.message` was already
// constructed from it in `createFromServiceResponse` — prefer it over the generic fallback.
if (
this.errorData &&
typeof this.errorData === 'object' &&
!('name' in this.errorData && 'message' in this.errorData && 'stack' in this.errorData) &&
'errors' in this.errorData &&
Array.isArray((this.errorData as Record<string, unknown>).errors)
) {
return `${operation}: ${this.message}`;
}

return fallback;
}

/**
* Convert API error object to PubNub client error object.
*
Expand Down
Loading