Skip to content

Commit ad4496b

Browse files
committed
adds a working n8n node to interact with searchapi
1 parent c0fec67 commit ad4496b

File tree

8 files changed

+952
-11
lines changed

8 files changed

+952
-11
lines changed

.tool-versions

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
nodejs 22.14.0
2+
pnpm 10.9.0

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ This repo contains example nodes to help you get started building your own custo
66

77
To make your custom node available to the community, you must create it as an npm package, and [submit it to the npm registry](https://docs.npmjs.com/packages-and-modules/contributing-packages-to-the-registry).
88

9+
## Plan
10+
11+
- Node type: Action
12+
- Style: Declarative
13+
914
## Prerequisites
1015

1116
You need the following installed on your development machine:
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import {
2+
IAuthenticateGeneric,
3+
ICredentialType,
4+
INodeProperties,
5+
} from 'n8n-workflow';
6+
7+
export class SearchAPI implements ICredentialType {
8+
name = 'searchApi';
9+
displayName = 'SearchAPI';
10+
11+
// Uses the link to this tutorial as an example
12+
// Replace with your own docs links when building your own nodes
13+
documentationUrl = 'https://www.searchapi.io/docs/google';
14+
properties: INodeProperties[] = [
15+
{
16+
displayName: 'API Key',
17+
name: 'apiKey',
18+
type: 'string',
19+
default: '',
20+
required: true,
21+
},
22+
];
23+
authenticate = {
24+
type: 'generic',
25+
properties: {
26+
qs: { api_key: '={{ $credentials.apiKey }}' },
27+
headers: {
28+
"X-SearchApi-Source": "N8N"
29+
}
30+
}
31+
} as IAuthenticateGeneric;
32+
}

nodes/SearchAPI/SearchAPI.node.json

Whitespace-only changes.

nodes/SearchAPI/SearchAPI.node.ts

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import { IDataObject, INodeType, INodeTypeDescription } from 'n8n-workflow';
2+
3+
export class SearchAPI implements INodeType {
4+
description: INodeTypeDescription = {
5+
displayName: 'SearchAPI',
6+
name: 'searchapi',
7+
icon: 'file:searchApi.svg',
8+
group: ['output'],
9+
version: 1,
10+
description: 'Search the web via SearchAPI.io (declarative)',
11+
subtitle: '={{ $parameter["engine"] }}',
12+
defaults: { name: 'SearchAPI', color: '#4338ca' },
13+
inputs: ['main'],
14+
outputs: ['main'],
15+
16+
credentials: [{ name: 'searchApi', required: true }],
17+
18+
requestDefaults: {
19+
baseURL: 'https://www.searchapi.io/api/v1',
20+
method: 'GET',
21+
url: '/search',
22+
headers: { Accept: 'application/json' },
23+
qs: {
24+
api_key: '={{ $credentials.apiKey }}', // generic-auth pattern :contentReference[oaicite:3]{index=3}
25+
},
26+
},
27+
28+
properties: [
29+
{
30+
displayName: 'Query (q)',
31+
name: 'q',
32+
type: 'string',
33+
default: '={{ $json.q }}',
34+
required: true,
35+
description: 'Search phrase to use in the engine of your choice.',
36+
routing: {
37+
request: {
38+
qs: {
39+
q: '={{ $value }}',
40+
},
41+
},
42+
},
43+
},
44+
{
45+
displayName: 'Engine (engine)',
46+
name: 'engine',
47+
type: 'string',
48+
default: 'google',
49+
required: true,
50+
description: 'Search engine to use for the query.',
51+
routing: {
52+
request: {
53+
qs: {
54+
engine: '={{ $value }}',
55+
},
56+
},
57+
},
58+
},
59+
{
60+
displayName: 'Additional Parameters',
61+
name: 'additionalParams',
62+
type: 'fixedCollection',
63+
typeOptions: { multipleValues: true },
64+
default: {},
65+
hint: 'You can ignore this and add "additionalParams" to the node input.',
66+
description: 'Add any extra query-string keys your SearchAPI request should include.',
67+
options: [
68+
{
69+
displayName: 'Parameter',
70+
name: 'parameter',
71+
values: [
72+
{
73+
displayName: 'Name',
74+
name: 'name',
75+
type: 'string',
76+
default: '',
77+
},
78+
{
79+
displayName: 'Value',
80+
name: 'value',
81+
type: 'string',
82+
default: '',
83+
},
84+
],
85+
},
86+
],
87+
/**
88+
* Build an object like { hl: 'en', gl: 'us' } out of
89+
* the collection entries and merge it into qs.
90+
*/
91+
routing: {
92+
request: {
93+
// We are doing this cast here because we need to
94+
// build an object out of the collection entries
95+
// and merge it into qs, but qs expects an object.
96+
qs: '={{ Object.fromEntries(($value.parameter ?? $json.additionalParams ?? []).map(p => [p.name, p.value])) }}' as unknown as IDataObject,
97+
},
98+
},
99+
}
100+
101+
],
102+
103+
};
104+
}

nodes/SearchAPI/searchApi.svg

Lines changed: 1 addition & 0 deletions
Loading

package.json

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "n8n-nodes-<...>",
2+
"name": "n8n-nodes-searchapi",
33
"version": "0.1.0",
44
"description": "",
55
"keywords": [
@@ -13,7 +13,7 @@
1313
},
1414
"repository": {
1515
"type": "git",
16-
"url": "https://github.com/<...>/n8n-nodes-<...>.git"
16+
"url": "https://github.com/SearchApi/n8n-nodes-searchapi.git"
1717
},
1818
"engines": {
1919
"node": ">=18.10",
@@ -37,11 +37,13 @@
3737
"n8nNodesApiVersion": 1,
3838
"credentials": [
3939
"dist/credentials/ExampleCredentialsApi.credentials.js",
40-
"dist/credentials/HttpBinApi.credentials.js"
40+
"dist/credentials/HttpBinApi.credentials.js",
41+
"dist/credentials/SearchAPI.credentials.js"
4142
],
4243
"nodes": [
4344
"dist/nodes/ExampleNode/ExampleNode.node.js",
44-
"dist/nodes/HttpBin/HttpBin.node.js"
45+
"dist/nodes/HttpBin/HttpBin.node.js",
46+
"dist/nodes/SearchAPI/SearchAPI.node.js"
4547
]
4648
},
4749
"devDependencies": {
@@ -50,6 +52,7 @@
5052
"eslint-plugin-n8n-nodes-base": "^1.16.1",
5153
"gulp": "^4.0.2",
5254
"prettier": "^3.3.2",
55+
"sqlite3": "^5.1.7",
5356
"typescript": "^5.5.3"
5457
},
5558
"peerDependencies": {

0 commit comments

Comments
 (0)