Two ways to wire this up in a Next.js App Router project: a plain client component hitting the free, no-key autocomplete endpoint directly (simplest — no server involved), or a route handler that proxies the authenticated search API so your RapidAPI key never reaches the browser.
Type a Japanese city, in Japanese or English:
// app/components/CityAutocomplete.tsx
'use client';
import { useState, useEffect } from 'react';
export function CityAutocomplete({ countryIso, lang }: { countryIso: string; lang: string }) {
const [query, setQuery] = useState('');
const [results, setResults] = useState<any[]>([]);
useEffect(() => {
const prefix = query.trim().toLowerCase();
if (!prefix) { setResults([]); return; }
const timer = setTimeout(() => {
fetch(`https://oneshot.geomelon.dev/${countryIso}/${lang}/${encodeURIComponent(prefix)}`)
.then((res) => (res.ok ? res.json() : []))
.then(setResults)
.catch(() => setResults([]));
}, 150);
return () => clearTimeout(timer);
}, [countryIso, lang, query]);
return (
<div>
<input value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Start typing a city..." />
<ul>
{results.map((c) => (
<li key={c.id}>{c.name}</li>
))}
</ul>
</div>
);
}Keeps your RapidAPI key server-side, and gives you sorting/pagination/multilingual params the free endpoint doesn't have:
// app/api/cities/route.ts
import { NextRequest, NextResponse } from 'next/server';
export async function GET(req: NextRequest) {
const { searchParams } = new URL(req.url);
const name = searchParams.get('name') ?? '';
const countryCode = searchParams.get('countryCode') ?? '';
const res = await fetch(
`https://geomelon.p.rapidapi.com/cities/search?name=${encodeURIComponent(name)}&countryCode=${countryCode}&sort=population_desc&limit=10`,
{
headers: {
'x-rapidapi-host': 'geomelon.p.rapidapi.com',
'x-rapidapi-key': process.env.GEOMELON_API_KEY!,
},
},
);
const cities = await res.json();
return NextResponse.json(cities);
}Then call /api/cities?name=par&countryCode=fr from your client component instead of the external URL directly — the key stays in an environment variable on the server, never shipped to the browser.