Skip to content

queryString option always prepends "?" even when result is empty #458

@fooddilsn

Description

@fooddilsn

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the issue has not already been raised

Issue

Use case

I'm building a proxy that strips certain authentication-related query params (e.g. token, workspaceId) before forwarding to the upstream. When those are the only params, the result is an empty query string, and the upstream receives a trailing ?.

app.get('/proxy/*', (request, reply) => {
  return reply.from('http://upstream/path', {
    queryString: (search, reqUrl) => {
      const params = new URLSearchParams(search);
      params.delete('token');
      params.delete('workspaceId');
      return params.toString();
    },
  });
});

Problem

The getQueryString function always prepends ? to the result of the queryString option, both for the function form and the object form, even when the result is an empty string:

function getQueryString (search, reqUrl, opts, request) {
  if (typeof opts.queryString === 'function') {
    return '?' + opts.queryString(search, reqUrl, request)
  }

  if (opts.queryString) {
    return '?' + querystring.stringify(opts.queryString)
  }

  if (search.length > 0) {
    return search
  }

  const queryIndex = reqUrl.indexOf('?')

  if (queryIndex > 0) {
    return reqUrl.slice(queryIndex)
  }

  return ''
}

This means there's no way to signal "no query string". Returning '' from the function (or passing an empty object {}) produces a trailing ? on the upstream request path (e.g., a request to /proxy/items?token=secret results in the upstream receiving /path? instead of /path).

By contrast, the default code path (no queryString option) correctly returns '' when there's no query string to forward.

Expected behavior

When the queryString result is an empty/falsy string, no ? should be appended, matching the behavior of the default code path.

Suggested fix

if (typeof opts.queryString === 'function') {
  const qs = opts.queryString(search, reqUrl, request)
  return qs ? '?' + qs : ''
}

if (opts.queryString) {
  const qs = querystring.stringify(opts.queryString)
  return qs ? '?' + qs : ''
}

Environment

  • @fastify/reply-from: 12.6.0
  • Node.js: 24.x

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions