Skip to content

Driver: Add Query String Driver for URL-based Storage #668

@tupe12334

Description

@tupe12334

Describe the feature

Motivation

Currently, unstorage provides excellent support for various storage backends including localStorage, sessionStorage,
memory, and numerous cloud providers. However, there's a missing piece for browser-based applications that need to
persist lightweight state in URLs - a query string driver.

This driver would be invaluable for:

  1. Shareable State: Store application state directly in the URL, making it easily shareable via links
  2. Bookmarkable Views: Enable users to bookmark specific application states (filters, search params, view preferences)
  3. Back/Forward Navigation: Leverage browser history for state management without additional complexity
  4. Server-Side Rendering: Access state on the server during SSR without cookies or sessions
  5. Analytics & Tracking: URL parameters are automatically captured by most analytics tools
  6. Zero-Dependency State: No external storage required - the URL itself is the storage medium

Use Cases

  • E-commerce filters (price range, categories, sorting)
  • Search interfaces with complex query builders
  • Dashboard configurations and view settings
  • Form wizards with step state
  • Data table pagination and sorting preferences
  • Feature flags and A/B testing parameters

Implementation Plan

  1. Driver Specification
  interface QueryStringOptions {
    /**
     * Base URL or window.location to use
     * @default window?.location
     */
    url?: URL | Location;

    /**
     * Prefix for all keys to avoid conflicts
     * @default ""
     */
    base?: string;

    /**
     * Whether to update browser history
     * @default true
     */
    updateHistory?: boolean;

    /**
     * History update method
     * @default "replaceState"
     */
    historyMethod?: "pushState" | "replaceState";

    /**
     * Custom serializer for complex values
     */
    serializer?: {
      serialize: (value: any) => string;
      deserialize: (value: string) => any;
    };

    /**
     * Window object for browser environments
     */
    window?: Window;
  }
  1. Core Implementation

The driver will implement the standard Driver interface with these key behaviors:

  • Storage: Use URLSearchParams API for robust query string manipulation
  • Key Normalization: Convert unstorage keys to URL-safe parameter names
  • Value Serialization: JSON stringify/parse for complex objects, with fallback to string values
  • Browser Integration: Optional history API integration for seamless navigation
  • SSR Support: Work with both browser Location and Node.js URL objects
  1. Method Implementations
  // Pseudo-code structure
  export default defineDriver((opts: QueryStringOptions = {}) => {
    const getSearchParams = () => new URLSearchParams(opts.url?.search || "");
    const updateURL = (params: URLSearchParams) => {
      // Update URL with new params
      // Optionally update browser history
    };

    return {
      name: "query-string",
      hasItem(key) {
        return getSearchParams().has(normalizeKey(key));
      },
      getItem(key) {
        const value = getSearchParams().get(normalizeKey(key));
        return value ? deserialize(value) : null;
      },
      setItem(key, value) {
        const params = getSearchParams();
        params.set(normalizeKey(key), serialize(value));
        updateURL(params);
      },
      removeItem(key) {
        const params = getSearchParams();
        params.delete(normalizeKey(key));
        updateURL(params);
      },
      getKeys() {
        return Array.from(getSearchParams().keys());
      },
      clear() {
        updateURL(new URLSearchParams());
      },
      watch(callback) {
        // Listen to popstate events for browser navigation
      }
    };
  });
  1. Special Considerations
  • URL Length Limits: Add option to warn/error when approaching browser URL limits (~2000 chars)
  • Value Encoding: Proper encoding/decoding for special characters
  • Array Values: Support for repeated parameters (e.g., ?tag=a&tag=b)
  • Nested Objects: Flatten nested structures or use bracket notation
  • Performance: Debounce URL updates to avoid excessive history entries

Testing Strategy

  1. Unit tests for all driver methods
  2. Browser environment tests with history API
  3. SSR compatibility tests with Node.js URL
  4. Edge cases: special characters, large values, concurrent updates
  5. Integration tests with unstorage mounting system

Documentation Requirements

  • Basic usage examples
  • Browser vs SSR configuration
  • Best practices for URL-safe keys
  • Performance considerations
  • Migration guide from other state management solutions

Backwards Compatibility

This is a new driver addition with no breaking changes to existing functionality.

Alternative Approaches Considered

  1. Using hash fragments (#key=value) - Limited browser support and conflicts with routing
  2. Cookie driver enhancement - Cookies have different use cases and limitations
  3. External library wrapper - Native implementation provides better integration

References


This driver would be a valuable addition to unstorage's already comprehensive driver ecosystem, filling a gap in
URL-based state persistence that many modern web applications require.

Additional information

  • Would you be willing to help implement this feature?

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions