Spring til indhold

Grundfast
Guide · Checkout

Adressefelt med autocomplete i din checkout

Et adressefelt, der foreslår rigtige danske adresser, fjerner de tastefejl, der senere bliver til returpakker og manuelle rettelser. Her er hele vejen: et debounced felt i frontend, et proxy-endpoint der holder nøglen på serveren, og ét kald der giver dig både visningsteksten og de felter, formularen skal udfyldes med.

  1. Kunden skriverEfter et par tegn spørger feltet din egen backend, som kalder /v1/adresse/search.
  2. Forslag med postnummer og byHvert forslag har vejnavn, husnummer, postnummer og by med, så valget ikke kræver et kald mere.
  3. Valget udfylder formularenGem adgangsadresse_id og bfe_nummer med ordren, ikke kun den tekst, kunden så.

Uden backend: vil du ikke bygge feltet og proxyen selv, så brug vores færdige adressefelt med en offentlig nøgle — ét script-tag, og browseren kalder Grundfast direkte. Denne guide er til dig, der vil styre feltet og kaldene selv.

Ét kald — ikke to

De fleste adresse-felter slår forslaget op to gange: først for at vise listen, og så igen for at hente de strukturerede felter, når brugeren har valgt. /v1/adresse/search returnerer begge dele på én gang, så valget kan udfylde formularen med det samme:

GET /v1/adresse/search?q=rentemestervej 10json
{
  "results": [
    {
      "betegnelse": "Rentemestervej 10, 2400 København NV",
      "adgangsadresse_id": "0a3f507a-e17e-32b8-e044-0003ba298018",
      "bfe_nummer": 6022755,
      "vejnavn": "Rentemestervej",
      "husnr": "10",
      "postnr": "2400",
      "postnrnavn": "København NV",
      "kommunekode": "0101",
      "koordinat": { "lon": 12.5347335, "lat": 55.7050242 }
    }
  ]
}

Bemærk adgangsadresse_id og bfe_nummer. Gem dem sammen med ordren i stedet for kun den fritekst, kunden så: id'et er stabilt, og bfe_nummer er nøglen til resten af ejendommen, hvis du senere får brug for den. Alle felter og parametre står i API-referencen for /v1/adresse/search.

Frontend: felt med forslag

De to detaljer, der afgør, om feltet føles rigtigt: debounce, så hvert tastetryk ikke bliver et kald — og afbrydelse af det forrige kald, så et langsomt svar ikke overskriver et nyere.

adressefelt.jsjavascript
// Adressefelt med forslag. Debounce, afbryd det forrige kald, og
// udfyld de øvrige felter ud fra det valgte forslag.
const input = document.querySelector('#adresse');
const liste = document.querySelector('#forslag');
const form = input.form;
let inflight;
let timer;

input.addEventListener('input', () => {
  clearTimeout(timer);
  timer = setTimeout(async () => {
    const q = input.value.trim();
    if (q.length < 2) return (liste.innerHTML = '');

    // Afbryd det forrige kald, så et langsomt svar ikke overskriver et nyere.
    inflight?.abort();
    inflight = new AbortController();

    // Kald dit eget backend-endpoint — nøglen må aldrig ligge i browseren.
    let results;
    try {
      const res = await fetch('/api/adresse?q=' + encodeURIComponent(q), {
        signal: inflight.signal,
      });
      ({ results } = await res.json());
    } catch (err) {
      if (err.name === 'AbortError') return; // et nyere kald har overtaget
      throw err;
    }

    liste.innerHTML = '';
    for (const r of results) {
      const li = document.createElement('li');
      li.textContent = r.betegnelse;
      li.addEventListener('click', () => {
        input.value = r.betegnelse;
        // Felterne kommer med i samme svar — ingen ekstra opslag.
        form.vejnavn.value = r.vejnavn ?? '';
        form.husnr.value = r.husnr ?? '';
        form.postnr.value = r.postnr ?? '';
        form.by.value = r.postnrnavn ?? '';
        // Gem nøglerne: adgangsadresse_id er stabil, bfe_nummer peger på ejendommen.
        form.adresse_id.value = r.adgangsadresse_id;
        liste.innerHTML = '';
      });
      liste.append(li);
    }
  }, 150);
});

Backend: hold nøglen på serveren

En API-nøgle i browseren kan læses af enhver besøgende og bruges på din regning. Læg et lille proxy-endpoint i din egen backend — så bliver nøglen, hvor den hører til, og du kan cache og rate-limite, før kaldene rammer os.

server.jsjavascript
// Proxy i din backend. Nøglen bliver på serveren, og du kan
// cache + rate-limite, før kaldene rammer os.
app.get('/api/adresse', async (req, res) => {
  const q = String(req.query.q ?? '');
  if (q.length < 2) return res.json({ results: [] });

  const upstream = await fetch(
    'https://api.grundfast.dk/v1/adresse/search?per_side=8&q=' +
      encodeURIComponent(q),
    { headers: { Authorization: 'Bearer ' + process.env.GRUNDFAST_API_KEY } },
  );
  if (!upstream.ok) return res.status(502).json({ results: [] });

  res.set('Cache-Control', 'private, max-age=60');
  res.json(await upstream.json());
});

Forslagene fanger ikke alt: browserens autoudfyld og en indsat adresse går uden om listen. Tjek derfor adressen igen, når formularen sendes — adressevalidering svarer med godkend, “mente du …?” eller afvis.

De adresser, du allerede har

Et nyt felt retter kun fremtidige ordrer. Kartoteket bagud kan vaskes mod DAR i stedet for at blive tastet om — du får rangerede kandidater med A/B/C-konfidensbånd og bfe_nummer, så det sikre kan rettes automatisk og resten sendes til et menneske.

datavask.shbash
# Har du allerede en liste med adresser — fx et gammelt kundekartotek —
# så vask dem i stedet for at få dem tastet igen.
curl -sS "https://api.grundfast.dk/v1/datavask/adgangsadresser?betegnelse=rentemestervej%2010%2C%202400%20kbh%20nv" \
  -H "Authorization: Bearer $GRUNDFAST_API_KEY"

Spørgsmål

Ofte stillede spørgsmål

Til et checkout-felt: /v1/adresse/search. Den returnerer de strukturerede felter (vejnavn, husnr, postnr, postnrnavn, kommunekode, koordinat og bfe_nummer) direkte i svaret, så du kan udfylde formularen uden et ekstra opslag. /v1/autocomplete giver tekst + vaerdi og er tænkt som DAWA-kompatibel drop-in, hvor du selv slår værdien op bagefter.

Nej. En nøgle i browseren kan læses af enhver besøgende og bruges på din regning. Læg et lille proxy-endpoint i din egen backend, som sætter Authorization-headeren — så kan du samtidig cache og rate-limite, før kaldene rammer os.

Med 150 ms debounce og afbrydelse af det forrige kald lander en typisk adresse-indtastning på nogle få kald. Free-planen er 5.000 kald/md, hvilket rækker til et mindre checkout-flow; derover fortsætter betalte planer automatisk til 1 kr pr. 1.000 ekstra kald.

Ja. En gf_test_-nøgle giver rigtige svar, faktureres aldrig og har 5.000 kald/md. Byg feltet færdigt på testnøglen, og skift til en gf_live_-nøgle, når du går i produktion.

Vask dem mod DAR med /v1/datavask/adgangsadresser. Du får rangerede kandidater med A/B/C-konfidensbånd og bfe_nummer, så du kan rette de sikre automatisk og lade et menneske se på resten. Har du mange, tager :batch-varianten dem i ét kald.

Se også

Byg feltet på en testnøgle

En gf_test_-nøgle giver rigtige svar, faktureres aldrig og har 5.000 kald/md. Byg feltet færdigt, og skift nøgle, når du går i produktion.

Gratis op til 5.000 kald/md · intet kreditkort · data fra Klimadatastyrelsen/Datafordeler, CC BY 4.0