Skip to content

Repository files navigation

@unirate/preact

npm ci License: MIT

Preact hooks and a context provider for the UniRate currency-exchange API.

  • useRate(from, to) — single exchange rate
  • useRates(from) — full rate table for a base
  • useConversion(from, to, amount) — converted amount
  • useCurrencies() — list of supported codes (~600)
  • useVatRates(country?) — EU/global VAT rates
  • useHistoricalRate(date, from, to) — historical rate (Pro)
  • useUniRate() — grab the client for imperative calls
  • <UniRateProvider> — one client for the whole tree
  • Zero runtime deps. Native fetch. AbortController cleanup on unmount.

Built on preact + preact/hooks. preact is a peer dep (>=10), so the package adds nothing to your bundle beyond a few hundred lines of hook code.

Install

npm install @unirate/preact
# or
pnpm add @unirate/preact
# or
yarn add @unirate/preact

Peer dep: preact >=10. Requires Node 18.17+ for build/server use.

Quickstart

import { UniRateProvider, useRate, useConversion } from "@unirate/preact";

export function App() {
  return (
    <UniRateProvider apiKey={import.meta.env.VITE_UNIRATE_API_KEY}>
      <Cart />
    </UniRateProvider>
  );
}

function Cart() {
  const { data: rate, loading } = useRate("USD", "EUR");
  const { data: total } = useConversion("USD", "EUR", 42.99);
  if (loading) return <p>Loading…</p>;
  return (
    <p>
      1 USD = {rate} EUR. Your total: {total} EUR
    </p>
  );
}

Get a free API key at unirateapi.com — the free tier covers latest rates, conversions, and VAT rates for ~600 currencies including crypto. Historical rates, time-series, and commodity feeds require Pro.

Hooks

Every hook returns the same shape:

interface QueryState<T> {
  data: T | undefined;
  error: Error | undefined;
  loading: boolean;    // true while a request is in flight
  refetch: () => void; // re-run the request manually
}

Every hook also accepts an options object:

{
  client?: UniRateClient;  // override the provider's client
  enabled?: boolean;       // skip the fetch until true (default true)
}

useRate(from, to, options?)

const { data, error, loading } = useRate("USD", "EUR");
// data: 0.92

useRates(from, options?)

Returns the full rate table for a base.

const { data } = useRates("USD");
// data: { EUR: 0.92, GBP: 0.80, JPY: 154.21, ... }

useConversion(from, to, amount, options?)

const { data } = useConversion("USD", "EUR", 100);
// data: 92.50

useCurrencies(options?)

const { data: codes } = useCurrencies();
// data: ["USD", "EUR", "GBP", "JPY", "BTC", ...]

useVatRates(country?, options?)

Pass a country code for one country, or undefined for the full table. The result is a discriminated union — narrow on vat_data vs vat_rates.

const { data } = useVatRates("DE");
// data: { country: "DE", vat_data: { country_code: "DE", country_name: "Germany", vat_rate: 19 } }

const { data: all } = useVatRates(undefined);
// data: { total_countries: 50, date: "…", vat_rates: { DE: { vat_rate: 19 }, ... } }

useHistoricalRate(date, from, to, amount?, options?)

Pro endpoint. Returns ProRequiredError on the free tier.

const { data } = useHistoricalRate("2025-01-01", "USD", "EUR");
// data: 0.851

useUniRate(override?)

Returns the UniRateClient from the nearest provider. Use it when you want to call the client imperatively from an event handler or effect rather than via a query hook.

import { useUniRate } from "@unirate/preact";

function ConvertButton() {
  const client = useUniRate();
  return (
    <button
      onClick={async () => {
        const eur = await client.convert("EUR", 100, "USD");
        console.log(eur);
      }}
    >
      Convert
    </button>
  );
}

Browser security

Putting an API key directly in client-side Preact means the key ships to every visitor's browser. For production deployments you have two options:

  1. Proxy through your backend. Point baseUrl at your own endpoint and have that endpoint hold the real UNIRATE_API_KEY:

    <UniRateProvider apiKey="placeholder" baseUrl="/api/unirate" />

    The placeholder still passes the client's "apiKey is required" check; your server inspects requests and inserts the real key before forwarding to api.unirateapi.com.

  2. Free-tier-only public key. Free-tier UniRate keys are rate-limited per key; if a leaked key only unlocks endpoints you don't mind being shared, shipping it client-side is acceptable.

Server-side (SSR, prerender, or any Node context): you can use the raw UniRateClient directly without the provider.

import { UniRateClient } from "@unirate/preact/client";

const client = new UniRateClient({ apiKey: process.env.UNIRATE_API_KEY! });
const rate = await client.getRate("USD", "EUR");

Errors

The same error classes the hooks expose are also exported for instanceof checks:

  • AuthenticationError — 401, bad / missing key
  • RateLimitError — 429
  • InvalidCurrencyError — 404, unknown currency code
  • InvalidRequestError — 400, bad params
  • ProRequiredError — 403, endpoint requires a Pro subscription
  • UniRateError — base class for any other failure
import { InvalidCurrencyError } from "@unirate/preact";

const { error } = useRate("USD", "XYZ");
if (error instanceof InvalidCurrencyError) {
  return <p>Unsupported currency.</p>;
}

Other UniRate clients

UniRate ships official client libraries and framework integrations across the ecosystem. The repos below are all maintained under the UniRate-API org.

Get a free API key at unirateapi.com.

License

MIT © Unirate Team

About

Preact hooks and context provider for the UniRate currency-exchange API — useRate, useConversion, useCurrencies, useVatRates + UniRateProvider. Zero runtime deps.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages