-
Notifications
You must be signed in to change notification settings - Fork 6
Add support for request options #29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
9da684f
39ca5c3
b74eb37
776d5be
86cc3bb
e986287
94e3413
f6c53ea
291b207
faca477
6b45021
9032a1e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -114,6 +114,39 @@ await getJson({ engine: "google", q: "coffee" }); // uses the API key defined in | |||||||||||||||||||||
await getJson({ engine: "google", api_key: API_KEY_2, q: "coffee" }); // API_KEY_2 will be used | ||||||||||||||||||||||
``` | ||||||||||||||||||||||
|
||||||||||||||||||||||
### Using a Proxy | ||||||||||||||||||||||
|
||||||||||||||||||||||
You can use a proxy by passing `requestOptions` with an `HttpsProxyAgent` | ||||||||||||||||||||||
instance. This can be done either globally through the config object or | ||||||||||||||||||||||
per-request in the parameters. | ||||||||||||||||||||||
|
||||||||||||||||||||||
First, install the required package: | ||||||||||||||||||||||
|
||||||||||||||||||||||
```bash | ||||||||||||||||||||||
npm install https-proxy-agent | ||||||||||||||||||||||
``` | ||||||||||||||||||||||
Comment on lines
+125
to
+127
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we also show guide for
Suggested change
Let's also update where we guide users to install serpapi: Line 26 in 38dcecb
# If you use npm:
npm install serpapi
# Or if you use Yarn:
yarn add serpapi |
||||||||||||||||||||||
|
||||||||||||||||||||||
Then use it in your code: | ||||||||||||||||||||||
|
||||||||||||||||||||||
```js | ||||||||||||||||||||||
import { config, getJson } from "serpapi"; | ||||||||||||||||||||||
import { HttpsProxyAgent } from "https-proxy-agent"; | ||||||||||||||||||||||
|
||||||||||||||||||||||
// Global configuration | ||||||||||||||||||||||
config.requestOptions = { | ||||||||||||||||||||||
agent: new HttpsProxyAgent("http://proxy-server:port"), | ||||||||||||||||||||||
}; | ||||||||||||||||||||||
|
||||||||||||||||||||||
// Or per-request configuration | ||||||||||||||||||||||
await getJson({ | ||||||||||||||||||||||
engine: "google", | ||||||||||||||||||||||
q: "coffee", | ||||||||||||||||||||||
requestOptions: { | ||||||||||||||||||||||
agent: new HttpsProxyAgent("http://proxy-server:port"), | ||||||||||||||||||||||
}, | ||||||||||||||||||||||
}); | ||||||||||||||||||||||
``` | ||||||||||||||||||||||
|
||||||||||||||||||||||
## Pagination | ||||||||||||||||||||||
|
||||||||||||||||||||||
Built-in pagination is not supported. Please refer to our pagination examples | ||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
*/ | ||
|
||
const Dotenv = require("dotenv"); | ||
const process = require("process"); | ||
const { | ||
config, | ||
getJson, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ | |
*/ | ||
|
||
import Dotenv from "dotenv"; | ||
import process from "process"; | ||
import { | ||
config, | ||
getAccount, | ||
|
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
@@ -1,7 +1,10 @@ | ||||||||
import { version } from "../version.ts"; | ||||||||
import https from "node:https"; | ||||||||
import http from "node:http"; | ||||||||
import qs from "node:querystring"; | ||||||||
import { RequestTimeoutError } from "./errors.ts"; | ||||||||
import { config } from "./config.ts"; | ||||||||
import process from "node:process"; | ||||||||
|
||||||||
/** | ||||||||
* This `_internals` object is needed to support stubbing/spying of | ||||||||
|
@@ -12,12 +15,15 @@ import { RequestTimeoutError } from "./errors.ts"; | |||||||
*/ | ||||||||
export const _internals = { | ||||||||
execute: execute, | ||||||||
getBaseUrl: getBaseUrl, | ||||||||
getHostnameAndPort: getHostnameAndPort, | ||||||||
}; | ||||||||
|
||||||||
/** Facilitates stubbing in tests, e.g. localhost as the base url */ | ||||||||
function getBaseUrl() { | ||||||||
return "https://serpapi.com"; | ||||||||
function getHostnameAndPort() { | ||||||||
return { | ||||||||
hostname: "serpapi.com", | ||||||||
port: 443, | ||||||||
}; | ||||||||
} | ||||||||
|
||||||||
export function getSource() { | ||||||||
|
@@ -27,9 +33,7 @@ export function getSource() { | |||||||
if (denoVersion) { | ||||||||
return `deno@${denoVersion},${moduleSource}`; | ||||||||
} | ||||||||
// @ts-ignore: scope of nodejs | ||||||||
} else if (typeof process == "object") { | ||||||||
// @ts-ignore: scope of nodejs | ||||||||
const nodeVersion = process.versions?.node; | ||||||||
if (nodeVersion) { | ||||||||
return `nodejs@${nodeVersion},${moduleSource}`; | ||||||||
|
@@ -38,40 +42,56 @@ export function getSource() { | |||||||
return `nodejs,${moduleSource}`; | ||||||||
} | ||||||||
|
||||||||
export function buildUrl( | ||||||||
export function buildRequestOptions( | ||||||||
path: string, | ||||||||
parameters: qs.ParsedUrlQueryInput, | ||||||||
): string { | ||||||||
): http.RequestOptions { | ||||||||
const clonedParams = { ...parameters }; | ||||||||
for (const k in clonedParams) { | ||||||||
if (clonedParams[k] === undefined) { | ||||||||
if ( | ||||||||
k === "requestOptions" || | ||||||||
k === "timeout" || | ||||||||
clonedParams[k] === undefined | ||||||||
) { | ||||||||
delete clonedParams[k]; | ||||||||
} | ||||||||
} | ||||||||
return `${_internals.getBaseUrl()}${path}?${qs.stringify(clonedParams)}`; | ||||||||
const basicOptions = { | ||||||||
..._internals.getHostnameAndPort(), | ||||||||
path: `${path}?${qs.stringify(clonedParams)}`, | ||||||||
method: "GET", | ||||||||
}; | ||||||||
|
||||||||
return { | ||||||||
...config.requestOptions, | ||||||||
...(parameters.requestOptions as http.RequestOptions), | ||||||||
...basicOptions, | ||||||||
}; | ||||||||
} | ||||||||
|
||||||||
export function execute( | ||||||||
path: string, | ||||||||
parameters: qs.ParsedUrlQueryInput, | ||||||||
timeout: number, | ||||||||
): Promise<string> { | ||||||||
const url = buildUrl(path, { | ||||||||
const options = buildRequestOptions(path, { | ||||||||
...parameters, | ||||||||
source: getSource(), | ||||||||
}); | ||||||||
|
||||||||
return new Promise((resolve, reject) => { | ||||||||
let timer: number; | ||||||||
const req = https.get(url, (resp) => { | ||||||||
|
||||||||
const handleResponse = (resp: http.IncomingMessage) => { | ||||||||
resp.setEncoding("utf8"); | ||||||||
let data = ""; | ||||||||
|
||||||||
// A chunk of data has been recieved. | ||||||||
// A chunk of data has been received | ||||||||
resp.on("data", (chunk) => { | ||||||||
data += chunk; | ||||||||
}); | ||||||||
|
||||||||
// The whole response has been received. Print out the result. | ||||||||
// The whole response has been received | ||||||||
resp.on("end", () => { | ||||||||
try { | ||||||||
if (resp.statusCode == 200) { | ||||||||
|
@@ -85,10 +105,14 @@ export function execute( | |||||||
if (timer) clearTimeout(timer); | ||||||||
} | ||||||||
}); | ||||||||
}).on("error", (err) => { | ||||||||
}; | ||||||||
|
||||||||
const handleError = (err: Error) => { | ||||||||
reject(err); | ||||||||
if (timer) clearTimeout(timer); | ||||||||
}); | ||||||||
}; | ||||||||
|
||||||||
const req = https.get(options, handleResponse).on("error", handleError); | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
||||||||
zyc9012 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||
if (timeout > 0) { | ||||||||
timer = setTimeout(() => { | ||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for bumping the Node.js version to 22.x for the build environment, should we also add Node.js v20.x and v21.x to the test matrices? This would help ensure compatibility with all current stable versions.