Skip to content

Commit 0145697

Browse files
authored
Merge pull request #16 from getlate-dev/fix/error-handling-account-validation
Fix: error handling and account validation for post operations
2 parents 560484a + a6794f9 commit 0145697

File tree

3 files changed

+79
-11
lines changed

3 files changed

+79
-11
lines changed

late/resources/posts.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { LateResourceModule } from "../types";
2-
import { postsCreatePreSend, postsUpdatePreSend } from "../utils/routingHooks";
2+
import { postsCreatePreSend, postsUpdatePreSend, handleApiErrorResponse } from "../utils/routingHooks";
33
import {
44
buildPlatformSelector,
55
buildAccountSelectors,
@@ -46,10 +46,15 @@ export const postsResource: LateResourceModule = {
4646
request: {
4747
method: "POST",
4848
url: "/posts",
49+
ignoreHttpStatusErrors: true,
50+
returnFullResponse: true,
4951
},
5052
send: {
5153
preSend: [postsCreatePreSend],
5254
},
55+
output: {
56+
postReceive: [handleApiErrorResponse],
57+
},
5358
},
5459
},
5560
{
@@ -60,10 +65,15 @@ export const postsResource: LateResourceModule = {
6065
request: {
6166
method: "PUT",
6267
url: "=/posts/{{ $parameter.postId }}",
68+
ignoreHttpStatusErrors: true,
69+
returnFullResponse: true,
6370
},
6471
send: {
6572
preSend: [postsUpdatePreSend],
6673
},
74+
output: {
75+
postReceive: [handleApiErrorResponse],
76+
},
6777
},
6878
},
6979
{
@@ -74,6 +84,11 @@ export const postsResource: LateResourceModule = {
7484
request: {
7585
method: "DELETE",
7686
url: "=/posts/{{ $parameter.postId }}",
87+
ignoreHttpStatusErrors: true,
88+
returnFullResponse: true,
89+
},
90+
output: {
91+
postReceive: [handleApiErrorResponse],
7792
},
7893
},
7994
},
@@ -85,6 +100,11 @@ export const postsResource: LateResourceModule = {
85100
request: {
86101
method: "POST",
87102
url: "=/posts/{{ $parameter.postId }}/retry",
103+
ignoreHttpStatusErrors: true,
104+
returnFullResponse: true,
105+
},
106+
output: {
107+
postReceive: [handleApiErrorResponse],
88108
},
89109
},
90110
},
@@ -107,6 +127,8 @@ export const postsResource: LateResourceModule = {
107127
request: {
108128
method: "POST",
109129
url: "/posts/bulk-upload",
130+
ignoreHttpStatusErrors: true,
131+
returnFullResponse: true,
110132
headers: {
111133
"Content-Type": "multipart/form-data",
112134
},
@@ -117,6 +139,9 @@ export const postsResource: LateResourceModule = {
117139
file: "={{ { value: $parameter.csvFile, options: { filename: 'bulk-upload.csv', contentType: 'text/csv' } } }}",
118140
},
119141
},
142+
output: {
143+
postReceive: [handleApiErrorResponse],
144+
},
120145
},
121146
},
122147
],

late/utils/platformHelpers.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,15 +83,15 @@ export async function loadPlatformAccounts(
8383
);
8484

8585
if (!response?.accounts) {
86-
return [{ name: `No ${platform} accounts found`, value: "none" }];
86+
return [{ name: `No ${platform} accounts found - connect at getlate.dev first`, value: "none" }];
8787
}
8888

8989
const platformAccounts = response.accounts.filter(
9090
(account: PlatformAccount) => account.platform === platform
9191
);
9292

9393
if (platformAccounts.length === 0) {
94-
return [{ name: `No ${platform} accounts connected`, value: "none" }];
94+
return [{ name: `No ${platform} accounts connected - connect at getlate.dev first`, value: "none" }];
9595
}
9696

9797
const platformConfig = SUPPORTED_PLATFORMS.find(
@@ -108,7 +108,7 @@ export async function loadPlatformAccounts(
108108
(error as any)?.cause?.code === "ECONNREFUSED"
109109
? "Cannot connect to LATE API. Please check your internet connection."
110110
: (error as Error).message || "Failed to load accounts";
111-
return [{ name: `Error: ${errorMsg}`, value: "error" }];
111+
return [{ name: `Connection error: ${errorMsg} - check API key`, value: "error" }];
112112
}
113113
}
114114

late/utils/routingHooks.ts

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,35 @@ import { processParametersWithExpressions } from "./expressionProcessor";
44
* Utility functions for routing hooks that process expressions
55
*/
66

7+
/**
8+
* Post-receive hook that surfaces API error messages in n8n UI.
9+
* Requires ignoreHttpStatusErrors: true and returnFullResponse: true on the request.
10+
*/
11+
export async function handleApiErrorResponse(
12+
this: any,
13+
items: any[],
14+
responseData: any,
15+
): Promise<any[]> {
16+
const statusCode = responseData?.statusCode;
17+
if (statusCode && statusCode >= 400) {
18+
const body = responseData.body;
19+
let errorMessage = `LATE API Error (${statusCode})`;
20+
21+
if (typeof body === 'object' && body !== null) {
22+
if (body.error) errorMessage += `: ${body.error}`;
23+
if (body.details) {
24+
errorMessage += ` - ${typeof body.details === 'string' ? body.details : JSON.stringify(body.details)}`;
25+
}
26+
if (body.code) errorMessage += ` [${body.code}]`;
27+
} else if (typeof body === 'string') {
28+
errorMessage += `: ${body}`;
29+
}
30+
31+
throw new Error(errorMessage);
32+
}
33+
return items;
34+
}
35+
736
/**
837
* Builds the platforms array from selected platforms and accounts
938
*/
@@ -24,10 +53,12 @@ function buildPlatformsArray(
2453
itemIndex,
2554
[]
2655
) as string[];
27-
return accounts.map((id: string) => ({
28-
platform,
29-
accountId: id,
30-
}));
56+
return accounts
57+
.filter((id: string) => id && id !== "none" && id !== "error" && id.length === 24)
58+
.map((id: string) => ({
59+
platform,
60+
accountId: id,
61+
}));
3162
})
3263
.flat();
3364
}
@@ -103,14 +134,26 @@ export async function postsCreatePreSend(
103134
0
104135
);
105136

137+
// Build platforms and validate before sending
138+
const platforms = buildPlatformsArray(this, 0);
139+
const publishNow = this.getNodeParameter("publishNow", 0, false);
140+
const isDraft = this.getNodeParameter("isDraft", 0, false);
141+
142+
if (!isDraft && platforms.length === 0) {
143+
throw new Error(
144+
'No valid accounts selected. Please select at least one account for each platform you want to post to. ' +
145+
'If no accounts appear in the dropdown, make sure you have connected accounts in your LATE dashboard (https://getlate.dev).'
146+
);
147+
}
148+
106149
// Build the body with processed parameters
107150
requestOptions.body = {
108151
content: this.getNodeParameter("content", 0),
109-
platforms: buildPlatformsArray(this, 0),
152+
platforms,
110153
scheduledFor: this.getNodeParameter("scheduledFor", 0, undefined),
111154
timezone: this.getNodeParameter("timezone", 0, "UTC"),
112-
publishNow: this.getNodeParameter("publishNow", 0, false),
113-
isDraft: this.getNodeParameter("isDraft", 0, false),
155+
publishNow,
156+
isDraft,
114157
visibility: this.getNodeParameter("visibility", 0, "public"),
115158
tags: buildTagsArray(this, 0),
116159
mediaItems: processedParams.mediaItems?.items || [],

0 commit comments

Comments
 (0)