DEV Community

Elowen
Elowen

Posted on

Build a SERP API Query Builder That Keeps Search Settings Explicit

When a teammate asks for “mobile results in Canada” or “news results in English,” the request should become a visible configuration before it becomes an HTTP call. Hidden defaults make search output hard to explain and harder to reuse.

This generic example builds a small JavaScript query builder. It keeps engine, q, device, location, language, and the json: 2 response setting in one object, validates the contract, and returns request options that another workflow can inspect.

Start with a readable query contract

const queryConfig = {
  engine: 'google',
  q: 'technical SEO audit',
  device: 'desktop',
  location: 'United States',
  google_domain: 'google.com',
  gl: 'us',
  hl: 'en',
  json: 2,
  num: 10
};
Enter fullscreen mode Exit fullscreen mode

This is a generic configuration example. The values describe an intended request; they are not presented as a measured result.

The object answers the questions that usually stay implicit: which search engine, which phrase, which device, which market, which language, and which response format.

Validate before building a request

function validateQuery(config) {
  const required = ['engine', 'q', 'device', 'hl', 'json'];
  const missing = required.filter((key) => !config[key]);
  if (missing.length) {
    throw new Error(`Missing query settings: ${missing.join(', ')}`);
  }

  const allowedDevices = new Set(['desktop', 'mobile', 'tablet']);
  if (!allowedDevices.has(config.device)) {
    throw new Error(`Unsupported device: ${config.device}`);
  }

  if (config.json !== 2) {
    throw new Error('json must be the numeric value 2');
  }

  if (!Number.isInteger(config.num) || config.num < 1 || config.num > 100) {
    throw new Error('num must be an integer between 1 and 100');
  }
}
Enter fullscreen mode Exit fullscreen mode

Validation turns an incomplete business request into a clear configuration error before the network layer is involved. Add project-specific checks for supported locations, engines, or result types as your API contract grows.

Build form data from the same object

TalorData accepts the query as form-encoded parameters. The builder below maps only fields that have values, so a caller can see exactly which settings will be sent.

function buildSerpRequest(config, token) {
  validateQuery(config);

  const body = new URLSearchParams();
  const fields = [
    'engine', 'q', 'device', 'location', 'google_domain',
    'gl', 'hl', 'num', 'json'
  ];

  for (const field of fields) {
    const value = config[field];
    if (value !== undefined && value !== '') body.set(field, String(value));
  }

  return {
    method: 'POST',
    url: 'https://serpapi.talordata.net/serp/v1/request',
    headers: {
      Authorization: `Bearer ${token}`,
      'Content-Type': 'application/x-www-form-urlencoded'
    },
    body
  };
}
Enter fullscreen mode Exit fullscreen mode

Call it with a secret loaded from your runtime environment. Keep the token outside the configuration object so logs can safely print the query settings without exposing credentials.

const request = buildSerpRequest(queryConfig, process.env.TALORDATA_TOKEN);
console.log(Object.fromEntries(request.body));
Enter fullscreen mode Exit fullscreen mode

The console output shows the intended form fields. It does not require an API call, which makes this layer easy to unit test with generic configurations.

Use named presets for repeated tasks

Teams often repeat the same market and device combinations. A preset keeps those decisions reviewable while allowing the query text to change.

const presets = {
  usDesktop: {
    device: 'desktop', location: 'United States', gl: 'us', hl: 'en'
  },
  ukMobile: {
    device: 'mobile', location: 'United Kingdom', gl: 'uk', hl: 'en'
  }
};

function makeConfig(preset, overrides) {
  return {
    engine: 'google',
    json: 2,
    num: 10,
    ...preset,
    ...overrides
  };
}

const config = makeConfig(presets.usDesktop, {
  q: 'technical SEO audit'
});
Enter fullscreen mode Exit fullscreen mode

Presets reduce copy-and-paste drift. The final object still contains every setting, so a saved request can be understood without opening the preset definition.

Make the configuration the hand-off artifact

Store the resolved configuration with the job definition or pass it between workflow steps as data. Useful fields include engine, q, device, location, google_domain, gl, hl, num, and json (set to 2).

When a result looks surprising, the first check becomes concrete: inspect the resolved request object. That is faster than reconstructing defaults from several code paths.

The builder remains small because it owns one job: turn an explicit search configuration into a request. Authentication, scheduling, response parsing, and downstream analysis can stay in their own modules.

TalorData can serve as the collection layer for this pattern. New accounts receive 500 responses immediately after registration

Top comments (0)