Skip to content

Commit 132bacb

Browse files
Better error handling
1 parent 66ff2c7 commit 132bacb

29 files changed

+719
-472
lines changed

README.md

Lines changed: 75 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ npm install linkedapi-node
1616

1717
## ⚡ Quick Start
1818

19+
> **⚠️ Note:** This package is currently in beta. Features and APIs are subject to change.
20+
1921
This official Linked API package simplifies interaction with LinkedIn's functionalities by wrapping the [Linked API](https://linkedapi.io), making it easier to build applications without dealing with complex API calls.
2022

2123
You can find various examples in the `/examples` folder to help you get started.
@@ -50,7 +52,7 @@ const searchCompaniesWorkflow = await linkedapi.searchCompanies({
5052
industries: ["Software Development", "Robotics Engineering"],
5153
},
5254
});
53-
const companies = await searchCompaniesWorkflow.result();
55+
const companiesResult = await searchCompaniesWorkflow.result();
5456

5557
// Retrieving company basic info, employees
5658
const companyWorkflow = await linkedapi.fetchCompany({
@@ -62,7 +64,7 @@ const companyWorkflow = await linkedapi.fetchCompany({
6264
},
6365
},
6466
});
65-
const company = await companyWorkflow.result();
67+
const companyResult = await companyWorkflow.result();
6668
```
6769

6870
---
@@ -104,6 +106,7 @@ const workflow = await linkedapi.executeCustomWorkflow({
104106
term: "Tech Inc",
105107
then: { actionType: "st.doForCompanies", ... }
106108
});
109+
const result = await workflow.result();
107110
```
108111

109112
---
@@ -139,14 +142,14 @@ const personHandler = await linkedapi.restoreWorkflow(
139142
"workflow-id-123",
140143
"fetchPerson"
141144
);
142-
const personData = await personHandler.result();
145+
const personResult = await personHandler.result();
143146

144147
// Restore a company fetching workflow
145148
const companyHandler = await linkedapi.restoreWorkflow(
146149
"workflow-id-456",
147150
"fetchCompany"
148151
);
149-
const companyData = await companyHandler.result();
152+
const companyResult = await companyHandler.result();
150153
```
151154

152155
---
@@ -181,7 +184,7 @@ const personWorkflow = await linkedapi.fetchPerson({
181184
since: "2024-01-01", // Retrieve reactions since this date
182185
},
183186
});
184-
const personData = await personWorkflow.result();
187+
const personResult = await personWorkflow.result();
185188
```
186189

187190
---
@@ -197,6 +200,7 @@ Retrieve person data through Sales Navigator for enhanced prospecting capabiliti
197200
const nvPersonWorkflow = await linkedapi.salesNavigatorFetchPerson({
198201
personHashedUrl: "https://www.linkedin.com/in/ABC123",
199202
});
203+
const personResult = await nvPersonWorkflow.result();
200204
```
201205

202206
---
@@ -235,7 +239,7 @@ const companyWorkflow = await linkedapi.fetchCompany({
235239
limit: 5, // Maximum number of decision makers to retrieve
236240
},
237241
});
238-
const companyData = await companyWorkflow.result();
242+
const companyResult = await companyWorkflow.result();
239243
```
240244

241245
---
@@ -268,7 +272,7 @@ const nvCompanyWorkflow = await linkedapi.salesNavigatorFetchCompany({
268272
limit: 10, // Maximum number of decision makers to retrieve (1-20)
269273
},
270274
});
271-
const companyData = await nvCompanyWorkflow.result();
275+
const companyResult = await nvCompanyWorkflow.result();
272276
```
273277

274278
---
@@ -284,6 +288,7 @@ Retrieve detailed information about a LinkedIn post including content, engagemen
284288
const postWorkflow = await linkedapi.fetchPost({
285289
postUrl: "https://www.linkedin.com/posts/john-doe_activity-123456789",
286290
});
291+
const postResult = await postWorkflow.result();
287292
```
288293

289294
---
@@ -305,6 +310,7 @@ const companySearchWorkflow = await linkedapi.searchCompanies({
305310
},
306311
limit: 50, // Maximum number of results to return (1-100, default: 10)
307312
});
313+
const companiesResult = await companySearchWorkflow.result();
308314
```
309315

310316
---
@@ -330,6 +336,7 @@ const nvCompanySearch = await linkedapi.salesNavigatorSearchCompanies({
330336
},
331337
limit: 75, // Maximum number of results to return (1-100)
332338
});
339+
const companiesResult = await nvCompanySearch.result();
333340
```
334341

335342
---
@@ -356,6 +363,7 @@ const peopleSearchWorkflow = await linkedapi.searchPeople({
356363
},
357364
limit: 20, // Maximum number of results to return (1-100, default: 10)
358365
});
366+
const peopleResult = await peopleSearchWorkflow.result();
359367
```
360368

361369
---
@@ -383,6 +391,7 @@ const nvPeopleSearch = await linkedapi.salesNavigatorSearchPeople({
383391
yearsOfExperience: ["lessThanOne", "oneToTwo", "threeToFive"],
384392
},
385393
});
394+
const prospectsResult = await nvPeopleSearch.result();
386395
```
387396

388397
---
@@ -414,8 +423,7 @@ Check the current connection status with a LinkedIn user.
414423
const statusWorkflow = await linkedapi.checkConnectionStatus({
415424
personUrl: "https://www.linkedin.com/in/john-doe",
416425
});
417-
const status = await statusWorkflow.result();
418-
console.log("Connection status:", status.connectionStatus); // 'connected', 'pending', 'not_connected'
426+
const statusResult = await statusWorkflow.result();
419427
```
420428

421429
---
@@ -444,8 +452,8 @@ Retrieve all pending connection requests sent by your account.
444452

445453
```typescript
446454
const pendingWorkflow = await linkedapi.retrievePendingRequests();
447-
const pending = await pendingWorkflow.result();
448-
console.log("Pending requests:", pending.requests);
455+
const pendingResult = await pendingWorkflow.result();
456+
console.log("Pending requests:", pendingResult.data.length);
449457
```
450458

451459
---
@@ -526,8 +534,7 @@ Retrieve your LinkedIn Social Selling Index (SSI) score and rankings.
526534

527535
```typescript
528536
const ssiWorkflow = await linkedapi.retrieveSSI();
529-
const ssi = await ssiWorkflow.result();
530-
console.log("SSI Score:", ssi.ssi, "Industry Top:", ssi.industryTop);
537+
const ssiResult = await ssiWorkflow.result();
531538
```
532539

533540
---
@@ -541,9 +548,7 @@ Retrieve LinkedIn account performance metrics including profile views and post e
541548

542549
```typescript
543550
const performanceWorkflow = await linkedapi.retrievePerformance();
544-
const metrics = await performanceWorkflow.result();
545-
console.log("Profile views:", metrics.profileViewsLast90Days);
546-
console.log("Post views:", metrics.postViewsLast7Days);
551+
const performanceResult = await performanceWorkflow.result();
547552
```
548553

549554
---
@@ -788,6 +793,7 @@ try {
788793
#### Retrieving Results After App Restart
789794

790795
If your application restarts or you need to check workflow status later, you can:
796+
791797
- Restore a `WorkflowHandler` using `restoreWorkflow(workflowId, functionName)` with full type safety
792798

793799
```typescript
@@ -797,8 +803,10 @@ const rawHandler = await linkedapi.restoreWorkflow(savedWorkflowId);
797803
// 2) Streamlined restoration with function name (wide result type with full type safety)
798804
const handler = await linkedapi.restoreWorkflow(savedWorkflowId, "fetchPerson");
799805
const result = await handler.result();
800-
console.log("Person name:", result.name);
801-
console.log("Experience count:", result.experiences?.length);
806+
if (result.data) {
807+
console.log("Person name:", result.data.name);
808+
console.log("Experience count:", result.data.experiences?.length);
809+
}
802810
```
803811

804812
See `examples/restore-workflow.ts` for a full example.
@@ -807,28 +815,46 @@ See `examples/restore-workflow.ts` for a full example.
807815

808816
## 🚨 Error Handling
809817

810-
Linked API provides structured error handling for different failure scenarios.
818+
Linked API provides structured error handling for different failure scenarios. There are two types of errors to handle:
819+
820+
### 1. Exceptions (try/catch)
811821

812822
- **`LinkedApiError`** - throws if a [common error](https://linkedapi.io/docs/making-requests/#common-errors) occurs
813-
- **`LinkedApiWorkflowError`** - throws in case of the [workflow execution](https://linkedapi.io/docs/actions-overview/#result-options) error (like invalid URL or messaging not allowed)
814823
- **`LinkedApiWorkflowTimeoutError`** - throws in case of timeout. Contains `workflowId` and `functionName` for future restoration
815824

825+
### 2. Action Errors (errors array)
826+
827+
- **Partial failures** - when some actions in a workflow succeed but others fail
828+
- **Action-specific errors** - errors from individual actions within a workflow that don't cause the entire workflow to fail
829+
816830
```typescript
817-
import LinkedApi from "linkedapi-node";
831+
import LinkedApi, { LinkedApiError } from 'linkedapi-node';
818832

819833
try {
820-
const result = await linkedapi.fetchPerson({
834+
const workflow = await linkedapi.fetchPerson({
821835
personUrl: "https://www.linkedin.com/in/invalid-profile",
822836
});
823-
const data = await result.result();
837+
const result = await workflow.result();
838+
839+
// Check for partial errors in the response
840+
if (result.errors && result.errors.length > 0) {
841+
console.warn("Workflow completed with errors:");
842+
result.errors.forEach((error) => {
843+
console.warn(`- ${error.type}: ${error.message}`);
844+
});
845+
}
846+
847+
// Access the data (may be undefined if workflow failed completely)
848+
if (result.data) {
849+
console.log("Person data:", result.data);
850+
} else {
851+
console.log("No data returned");
852+
}
824853
} catch (error) {
825-
if (error instanceof LinkedApi.LinkedApiError) {
854+
if (error instanceof LinkedApiError) {
826855
console.error("Linked API Error:", error.message);
827856
console.error("Error Type:", error.type);
828857
console.error("Details:", error.details);
829-
} else if (error instanceof LinkedApi.LinkedApiWorkflowError) {
830-
console.error("Linked API Workflow Error:", error.message);
831-
console.error("Reason:", error.reason);
832858
} else {
833859
console.error("Unexpected error:", error);
834860
}
@@ -843,6 +869,28 @@ try {
843869
- **`invalidIdentificationToken`** - Invalid Identification Token
844870
- **`subscriptionRequired`** - No purchased subscription seats available for this LinkedIn account.
845871
- **`invalidRequestPayload`** - Invalid request body/parameters: {validation_message}.
872+
- **`invalidWorkflow`** - Workflow configuration is not valid due to violated action constraints or invalid action parameters: {validation_details}.
873+
- **`plusPlanRequired`** - Some actions in this workflow require the Plus plan.
874+
- **`linkedinAccountSignedOut`** - Your LinkedIn account has been signed out in our cloud browser. This occasionally happens as LinkedIn may sign out accounts after an extended period. You'll need to visit our platform and reconnect your account.
875+
- **`languageNotSupported`** - Your LinkedIn account uses a language other than English, which is currently the only supported option.
876+
- **`timeout`** - Local execution timeout. Contains `workflowId` and `functionName` for future restoration.
877+
878+
### Common Action Error Types
879+
880+
- **`personNotFound`** - Provided URL is not an existing LinkedIn person. (sendMessage, syncConversation, checkConnectionStatus, sendConnectionRequest, withdrawConnectionRequest, removeConnection, fetchPerson, salesNavigatorSendMessage, salesNavigatorSyncConversation, salesNavigatorFetchPerson)
881+
- **`messagingNotAllowed`** - Sending a message to the person is not allowed. (sendMessage, salesNavigatorSendMessage)
882+
- **`alreadyPending`** - Connection request to this person has already been sent and is still pending.(sendConnectionRequest)
883+
- **`alreadyConnected`** - Your LinkedIn account is already connected with this person. (sendConnectionRequest)
884+
- **`emailRequired`** - Person requires an email address to send a connection request. (sendConnectionRequest)
885+
- **`requestNotAllowed`** - LinkedIn has restricted sending a connection request to this person. (sendConnectionRequest)
886+
- **`notPending`** - There is no pending connection request to this person. (withdrawConnectionRequest)
887+
- **`connectionNotFound`** - Person is not in your connections. (removeConnection)
888+
- **`searchingNotAllowed`** - LinkedIn has blocked performing the search due to exceeding limits or other restrictions. (searchCompanies, searchPeople, salesNavigatorSearchCompanies, salesNavigatorSearchPeople)
889+
- **`companyNotFound`** - Provided URL is not an existing LinkedIn company. (fetchCompany, salesNavigatorFetchCompany)
890+
- **`retrievingNotAllowed`** - LinkedIn has blocked performing the retrieval due to exceeding limits or other restrictions. (retrieveConnections, fetchCompany, salesNavigatorFetchCompany)
891+
- **`postNotFound`** - Provided URL is not an existing LinkedIn post. (fetchPost, reactToPost, commentOnPost)
892+
- **`commentingNotAllowed`** - Commenting is not allowed on this post. This could be due to the post author's privacy settings, LinkedIn restrictions on commenting, or because the post type does not support comments. (commentOnPost)
893+
- **`noSalesNavigator`** - Your account does not have Sales Navigator subscription. (salesNavigatorSendMessage, salesNavigatorSyncConversation, salesNavigatorSearchCompanies, salesNavigatorSearchPeople, salesNavigatorFetchCompany, salesNavigatorFetchPerson)
846894

847895
---
848896

0 commit comments

Comments
 (0)