# Kassalapp API - Komplett PHP-guide ## Innledning Kassalapp API gir deg tilgang til Norges mest omfattende database over dagligvarepriser. Med over 50 000 produkter fra alle de store kjedene kan du bygge kraftige prissammenligningstjenester, handleliste-apper eller analyseverktøy for norske forbrukere. Denne guiden viser deg hvordan du kommer i gang med API-et ved hjelp av PHP, med praktiske eksempler du kan bruke direkte i dine egne prosjekter. ## Innholdsfortegnelse 1. [Kom i gang](#kom-i-gang) 2. [Autentisering](#autentisering) 3. [Produktsøk](#produktsøk) 4. [Filtrering og sortering](#filtrering-og-sortering) 5. [Strekkode-oppslag](#strekkode-oppslag) 6. [Butikklokasjoner](#butikklokasjoner) 7. [Kategorier og merker](#kategorier-og-merker) 8. [Avanserte eksempler](#avanserte-eksempler) 9. [Feilhåndtering](#feilhåndtering) 10. [Ytelse og beste praksis](#ytelse-og-beste-praksis) ## Kom i gang ### Steg 1: Registrer deg for API-nøkkel Først må du registrere deg for å få en API-nøkkel: 1. Gå til [https://kassal.app/api](https://kassal.app/api) 2. Opprett en gratis konto 3. Kopier din API-nøkkel fra dashboardet ### Steg 2: Installer Guzzle Vi bruker Guzzle HTTP-klient for å gjøre API-kall enklere: ```bash composer require guzzlehttp/guzzle ``` ### Steg 3: Grunnleggende oppsett ```php apiKey = $apiKey; $this->client = new Client([ 'base_uri' => self::BASE_URL, 'timeout' => 10.0, 'headers' => [ 'Authorization' => 'Bearer ' . $this->apiKey, 'Accept' => 'application/json', 'Content-Type' => 'application/json' ] ]); } public function request(string $endpoint, array $params = []) { try { $response = $this->client->get($endpoint, [ 'query' => $params ]); return json_decode($response->getBody(), true); } catch (RequestException $e) { $this->handleError($e); } } private function handleError(RequestException $e) { if ($e->hasResponse()) { $statusCode = $e->getResponse()->getStatusCode(); $body = json_decode($e->getResponse()->getBody(), true); switch ($statusCode) { case 401: throw new Exception('Ugyldig API-nøkkel'); case 429: throw new Exception('For mange forespørsler - vent litt'); case 404: throw new Exception('Ressursen ble ikke funnet'); default: throw new Exception($body['message'] ?? 'En feil oppstod'); } } throw new Exception('Kunne ikke koble til API-et'); } } ``` ## Autentisering API-et bruker Bearer Token-autentisering. Send med din API-nøkkel i `Authorization`-headeren: ```php $apiKey = 'din-api-nøkkel-her'; $api = new KassalappAPI($apiKey); ``` ### Rate limiting - **Gratis tier**: 100 forespørsler per minutt - **Pro tier**: 1000 forespørsler per minutt - **Enterprise**: Ubegrenset Hvis du overskrider grensen, får du en `429 Too Many Requests`-respons. Vent 60 sekunder før du prøver igjen. ## Produktsøk ### Enkelt søk Søk etter produkter med fritekst: ```php // Søk etter melk $resultater = $api->request('products', [ 'search' => 'melk' ]); foreach ($resultater['data'] as $produkt) { echo "📦 {$produkt['name']}\n"; echo " Pris: {$produkt['current_price']['price']} kr hos {$produkt['current_price']['store']['name']}\n"; echo " EAN: {$produkt['ean']}\n\n"; } ``` ### Søk med paginering API-et returnerer maks 100 produkter per side: ```php function hentAlleProdukter($api, $søkeord) { $alleProdukter = []; $side = 1; do { $respons = $api->request('products', [ 'search' => $søkeord, 'page' => $side ]); $alleProdukter = array_merge($alleProdukter, $respons['data']); $side++; // Sjekk om det er flere sider $harFlereSider = $respons['pagination']['current_page'] < $respons['pagination']['last_page']; } while ($harFlereSider); return $alleProdukter; } // Hent alle melkeprodukter $alleMelkeprodukter = hentAlleProdukter($api, 'melk'); echo "Fant totalt " . count($alleMelkeprodukter) . " melkeprodukter\n"; ``` ## Filtrering og sortering ### Filtrer på kategori Reduser antall API-kall ved å filtrere på kategori: ```php // Hent alle kategorier først $kategorier = $api->request('categories'); // Finn meieri-kategorien $meieriKategori = null; foreach ($kategorier['data'] as $kategori) { if (stripos($kategori['name'], 'meieri') !== false) { $meieriKategori = $kategori['id']; break; } } // Søk kun i meieriprodukter $meieriProdukter = $api->request('products', [ 'category_id' => $meieriKategori, 'search' => 'yoghurt' ]); ``` ### Filtrer på pris Finn produkter innenfor et prisintervall: ```php // Finn billige alternativer (under 20 kr) $billigeProdukter = $api->request('products', [ 'search' => 'brød', 'price_max' => 20, 'sort' => 'price_asc' // Sorter billigste først ]); echo "🍞 Brød under 20 kr:\n"; foreach ($billigeProdukter['data'] as $produkt) { $pris = $produkt['current_price']; echo "- {$produkt['name']}: {$pris['price']} kr hos {$pris['store']['name']}\n"; } ``` ### Filtrer på merke ```php // Finn alle Tine-produkter $tineProdukter = $api->request('products', [ 'brand' => 'Tine', 'sort' => 'name_asc' ]); // Eller finn produkter fra flere merker $premiumMerker = $api->request('products', [ 'brand' => 'First Price', // Billigmerke 'category' => 'Kjøtt' ]); ``` ## Strekkode-oppslag Perfekt for barcode-scanning i apper: ```php class StrekkkodeScanner { private $api; public function __construct(KassalappAPI $api) { $this->api = $api; } public function skannProdukt(string $ean) { try { $produkt = $this->api->request("products/ean/{$ean}"); if (empty($produkt['data'])) { return null; } return $this->formaterProduktInfo($produkt['data']); } catch (Exception $e) { return null; } } private function formaterProduktInfo($produkt) { $info = [ 'navn' => $produkt['name'], 'merke' => $produkt['brand'] ?? 'Ukjent', 'beskrivelse' => $produkt['description'], 'bilde' => $produkt['image'], 'priser' => [], 'næringsinnhold' => [] ]; // Samle priser fra alle butikker foreach ($produkt['pricing'] as $pris) { $info['priser'][] = [ 'butikk' => $pris['store']['name'], 'pris' => $pris['price'], 'tilbud' => $pris['price'] < $produkt['current_price']['price'] ]; } // Sorter etter pris usort($info['priser'], fn($a, $b) => $a['pris'] <=> $b['pris']); // Legg til næringsinnhold hvis tilgjengelig if (!empty($produkt['nutrition'])) { $info['næringsinnhold'] = $produkt['nutrition']; } return $info; } } // Bruk scanner $scanner = new StrekkkodeScanner($api); $produktInfo = $scanner->skannProdukt('7035620033148'); // Norvegia ost if ($produktInfo) { echo "🧀 {$produktInfo['navn']}\n"; echo "Billigste pris: {$produktInfo['priser'][0]['pris']} kr hos {$produktInfo['priser'][0]['butikk']}\n"; } ``` ## Butikklokasjoner Finn nærmeste butikker basert på posisjon: ```php class ButikkFinner { private $api; public function __construct(KassalappAPI $api) { $this->api = $api; } public function finnNærmesteButikker($lat, $lng, $radius = 5) { $alleButikker = $this->api->request('physical-stores'); $nærmesteButikker = []; foreach ($alleButikker['data'] as $butikk) { $avstand = $this->beregnAvstand( $lat, $lng, $butikk['lat'], $butikk['lng'] ); if ($avstand <= $radius) { $butikk['avstand'] = round($avstand, 1); $nærmesteButikker[] = $butikk; } } // Sorter etter avstand usort($nærmesteButikker, fn($a, $b) => $a['avstand'] <=> $b['avstand']); return $nærmesteButikker; } private function beregnAvstand($lat1, $lng1, $lat2, $lng2) { // Haversine-formel for å beregne avstand $jordRadius = 6371; // km $deltaLat = deg2rad($lat2 - $lat1); $deltaLng = deg2rad($lng2 - $lng1); $a = sin($deltaLat/2) * sin($deltaLat/2) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * sin($deltaLng/2) * sin($deltaLng/2); $c = 2 * atan2(sqrt($a), sqrt(1-$a)); return $jordRadius * $c; } public function grupperButikkerEtterKjede($butikker) { $kjeder = []; foreach ($butikker as $butikk) { $kjede = $butikk['chain'] ?? 'Annet'; if (!isset($kjeder[$kjede])) { $kjeder[$kjede] = []; } $kjeder[$kjede][] = $butikk; } return $kjeder; } } // Finn butikker nær Oslo sentrum $butikkFinner = new ButikkFinner($api); $nærmesteButikker = $butikkFinner->finnNærmesteButikker(59.9139, 10.7522, 3); echo "📍 Butikker innen 3 km:\n"; foreach ($nærmesteButikker as $butikk) { echo "- {$butikk['name']} ({$butikk['chain']}): {$butikk['avstand']} km\n"; echo " Adresse: {$butikk['address']}\n"; if (!empty($butikk['opening_hours'])) { echo " Åpningstider: {$butikk['opening_hours']}\n"; } echo "\n"; } ``` ## Kategorier og merker ### Hent alle kategorier ```php class KategoriNavigator { private $api; private $kategorier = []; public function __construct(KassalappAPI $api) { $this->api = $api; $this->lastKategorier(); } private function lastKategorier() { $respons = $this->api->request('categories'); foreach ($respons['data'] as $kategori) { $this->kategorier[$kategori['id']] = [ 'navn' => $kategori['name'], 'antall_produkter' => $kategori['products_count'] ?? 0 ]; } } public function visKategoritre() { echo "📂 Produktkategorier:\n"; foreach ($this->kategorier as $id => $kategori) { echo " [{$id}] {$kategori['navn']} ({$kategori['antall_produkter']} produkter)\n"; } } public function finnKategoriId($søkeord) { foreach ($this->kategorier as $id => $kategori) { if (stripos($kategori['navn'], $søkeord) !== false) { return $id; } } return null; } } $navigator = new KategoriNavigator($api); $navigator->visKategoritre(); // Finn produkter i en spesifikk kategori $fruktKategori = $navigator->finnKategoriId('frukt'); if ($fruktKategori) { $fruktProdukter = $api->request('products', [ 'category_id' => $fruktKategori, 'sort' => 'price_asc' ]); } ``` ## Avanserte eksempler ### Prissammenligning for handleliste ```php class Handleliste { private $api; private $produkter = []; public function __construct(KassalappAPI $api) { $this->api = $api; } public function leggTilProdukt($søkeord, $antall = 1) { $resultat = $this->api->request('products', [ 'search' => $søkeord, 'unique' => true // Få kun unike produkter ]); if (!empty($resultat['data'])) { $produkt = $resultat['data'][0]; $this->produkter[] = [ 'produkt' => $produkt, 'antall' => $antall ]; return true; } return false; } public function beregnTotalpriser() { $butikkPriser = []; foreach ($this->produkter as $item) { $produkt = $item['produkt']; $antall = $item['antall']; // Gå gjennom alle butikker som har produktet foreach ($produkt['pricing'] as $pris) { $butikk = $pris['store']['name']; if (!isset($butikkPriser[$butikk])) { $butikkPriser[$butikk] = [ 'total' => 0, 'produkter' => [], 'mangler' => [] ]; } $butikkPriser[$butikk]['total'] += $pris['price'] * $antall; $butikkPriser[$butikk]['produkter'][] = [ 'navn' => $produkt['name'], 'pris' => $pris['price'], 'antall' => $antall, 'sum' => $pris['price'] * $antall ]; } } // Sorter butikker etter totalpris uasort($butikkPriser, fn($a, $b) => $a['total'] <=> $b['total']); return $butikkPriser; } public function visAnbefaling() { $priser = $this->beregnTotalpriser(); if (empty($priser)) { echo "Handlelisten er tom!\n"; return; } $billigste = array_key_first($priser); $billigstePris = $priser[$billigste]; echo "\n💰 ANBEFALING:\n"; echo "Handle hos {$billigste} - Total: {$billigstePris['total']} kr\n\n"; echo "📋 Din handleliste hos {$billigste}:\n"; foreach ($billigstePris['produkter'] as $produkt) { echo "- {$produkt['antall']}x {$produkt['navn']}: {$produkt['sum']} kr\n"; } echo "\n💸 Sammenligning med andre butikker:\n"; foreach ($priser as $butikk => $info) { $forskjell = $info['total'] - $billigstePris['total']; $prosent = round(($forskjell / $billigstePris['total']) * 100, 1); if ($butikk !== $billigste) { echo "- {$butikk}: {$info['total']} kr (+{$forskjell} kr / +{$prosent}%)\n"; } } } } // Lag handleliste $handleliste = new Handleliste($api); $handleliste->leggTilProdukt('melk lettmelk', 2); $handleliste->leggTilProdukt('brød grovt', 1); $handleliste->leggTilProdukt('egg 12 stk', 1); $handleliste->leggTilProdukt('norvegia', 1); $handleliste->leggTilProdukt('bananer', 1); $handleliste->visAnbefaling(); ``` ### Tilbudsovervåking ```php class Tilbudsovervåker { private $api; private $favoritter = []; public function __construct(KassalappAPI $api) { $this->api = $api; } public function leggTilFavoritt($ean, $ønsketPris = null) { $this->favoritter[$ean] = $ønsketPris; } public function sjekkTilbud() { $tilbud = []; foreach ($this->favoritter as $ean => $ønsketPris) { try { $produkt = $this->api->request("products/ean/{$ean}"); if (empty($produkt['data'])) { continue; } $data = $produkt['data']; $laveste = $this->finnLavestePris($data['pricing']); // Sjekk om produktet er på tilbud if ($data['current_price']['price'] > $laveste['price']) { $besparelse = $data['current_price']['price'] - $laveste['price']; $prosent = round(($besparelse / $data['current_price']['price']) * 100); $tilbud[] = [ 'produkt' => $data['name'], 'butikk' => $laveste['store']['name'], 'tilbudspris' => $laveste['price'], 'normalpris' => $data['current_price']['price'], 'besparelse' => $besparelse, 'prosent' => $prosent, 'under_ønsket' => $ønsketPris && $laveste['price'] <= $ønsketPris ]; } } catch (Exception $e) { // Ignorer feil for enkeltprodukter } } // Sorter etter besparelse usort($tilbud, fn($a, $b) => $b['besparelse'] <=> $a['besparelse']); return $tilbud; } private function finnLavestePris($priser) { return array_reduce($priser, function($lavest, $pris) { return !$lavest || $pris['price'] < $lavest['price'] ? $pris : $lavest; }); } public function sendVarsler($tilbud) { echo "🔔 TILBUDSVARSLER:\n\n"; foreach ($tilbud as $t) { $emoji = $t['under_ønsket'] ? '🎯' : '💸'; echo "{$emoji} {$t['produkt']}\n"; echo " {$t['butikk']}: {$t['tilbudspris']} kr (spar {$t['besparelse']} kr / -{$t['prosent']}%)\n"; if ($t['under_ønsket']) { echo " ✅ Under ønsket pris!\n"; } echo "\n"; } } } // Overvåk favoritter $overvåker = new Tilbudsovervåker($api); $overvåker->leggTilFavoritt('7035620033148', 100); // Norvegia, ønsket pris 100 kr $overvåker->leggTilFavoritt('7037710000457', 25); // Pepsi Max $tilbud = $overvåker->sjekkTilbud(); $overvåker->sendVarsler($tilbud); ``` ### Næringsinnhold-analyse ```php class NæringsAnalyse { private $api; public function __construct(KassalappAPI $api) { $this->api = $api; } public function analyserProdukt($ean) { $produkt = $this->api->request("products/ean/{$ean}"); if (empty($produkt['data']['nutrition'])) { return null; } $næring = $produkt['data']['nutrition']; $navn = $produkt['data']['name']; return $this->vurderSunnhet($navn, $næring); } private function vurderSunnhet($navn, $næring) { $vurdering = [ 'produkt' => $navn, 'score' => 0, 'advarsler' => [], 'positive' => [] ]; // Sjekk sukkerinnhold (per 100g) if (isset($næring['sugars_per_100g'])) { $sukker = $næring['sugars_per_100g']; if ($sukker > 15) { $vurdering['advarsler'][] = "⚠️ Høyt sukkerinnhold ({$sukker}g/100g)"; $vurdering['score'] -= 2; } elseif ($sukker < 5) { $vurdering['positive'][] = "✅ Lavt sukkerinnhold ({$sukker}g/100g)"; $vurdering['score'] += 1; } } // Sjekk mettet fett if (isset($næring['saturated_fat_per_100g'])) { $fett = $næring['saturated_fat_per_100g']; if ($fett > 5) { $vurdering['advarsler'][] = "⚠️ Høyt mettet fett ({$fett}g/100g)"; $vurdering['score'] -= 1; } } // Sjekk fiber if (isset($næring['fiber_per_100g'])) { $fiber = $næring['fiber_per_100g']; if ($fiber > 6) { $vurdering['positive'][] = "✅ Høyt fiberinnhold ({$fiber}g/100g)"; $vurdering['score'] += 2; } } // Sjekk protein if (isset($næring['protein_per_100g'])) { $protein = $næring['protein_per_100g']; if ($protein > 20) { $vurdering['positive'][] = "✅ Høyt proteininnhold ({$protein}g/100g)"; $vurdering['score'] += 1; } } // Gi en totalvurdering if ($vurdering['score'] >= 2) { $vurdering['konklusjon'] = '🌟 Sunt valg!'; } elseif ($vurdering['score'] <= -2) { $vurdering['konklusjon'] = '⚠️ Bør nytes med måte'; } else { $vurdering['konklusjon'] = '👍 OK valg'; } return $vurdering; } public function sammenlignAlternativer($søkeord) { $produkter = $this->api->request('products', [ 'search' => $søkeord, 'unique' => true ]); $alternativer = []; foreach ($produkter['data'] as $produkt) { if (!empty($produkt['nutrition'])) { $vurdering = $this->vurderSunnhet($produkt['name'], $produkt['nutrition']); $vurdering['pris'] = $produkt['current_price']['price']; $vurdering['ean'] = $produkt['ean']; $alternativer[] = $vurdering; } } // Sorter etter sunnhet-score usort($alternativer, fn($a, $b) => $b['score'] <=> $a['score']); return $alternativer; } } // Analyser næringsinnhold $analyse = new NæringsAnalyse($api); // Sammenlign ulike yoghurt-alternativer $alternativer = $analyse->sammenlignAlternativer('yoghurt'); echo "🥛 YOGHURT-SAMMENLIGNING:\n\n"; foreach (array_slice($alternativer, 0, 5) as $alt) { echo "{$alt['konklusjon']} {$alt['produkt']} - {$alt['pris']} kr\n"; foreach ($alt['positive'] as $pos) { echo " {$pos}\n"; } foreach ($alt['advarsler'] as $adv) { echo " {$adv}\n"; } echo "\n"; } ``` ## Feilhåndtering ### Robust feilhåndtering ```php class RobustKassalappAPI extends KassalappAPI { private $maxRetries = 3; private $retryDelay = 1; // sekunder public function requestWithRetry(string $endpoint, array $params = []) { $forsøk = 0; $sisteFeil = null; while ($forsøk < $this->maxRetries) { try { return $this->request($endpoint, $params); } catch (Exception $e) { $sisteFeil = $e; $forsøk++; // Sjekk om det er en midlertidig feil if ($this->erMidlertidigFeil($e)) { $this->loggFeil("Forsøk {$forsøk} feilet: {$e->getMessage()}"); if ($forsøk < $this->maxRetries) { sleep($this->retryDelay * $forsøk); // Eksponentiell backoff continue; } } // Permanent feil, ikke prøv igjen throw $e; } } throw $sisteFeil; } private function erMidlertidigFeil(Exception $e) { $midlertidigeFeilkoder = [429, 500, 502, 503, 504]; if ($e instanceof RequestException && $e->hasResponse()) { $statusCode = $e->getResponse()->getStatusCode(); return in_array($statusCode, $midlertidigeFeilkoder); } return false; } private function loggFeil($melding) { error_log("[Kassalapp API] " . $melding); } public function håndterRateLimiting() { static $forespørsler = []; $nå = time(); // Fjern gamle forespørsler (eldre enn 60 sekunder) $forespørsler = array_filter($forespørsler, fn($tid) => $nå - $tid < 60); // Sjekk om vi nærmer oss grensen if (count($forespørsler) >= 95) { // 95 av 100 tillatte if (!empty($forespørsler)) { $eldsteForespørsel = min($forespørsler); $ventetid = max(0, 60 - ($nå - $eldsteForespørsel)); if ($ventetid > 0 && $ventetid <= 60) { sleep($ventetid); } // Rens kun gamle forespørsler, ikke alle $forespørsler = array_filter($forespørsler, fn($tid) => $nå - $tid < $ventetid); } } $forespørsler[] = $nå; } } ``` ### Validering av input ```php class InputValidator { public static function validerEAN($ean) { // Fjern mellomrom og bindestrek $ean = preg_replace('/[\s-]/', '', $ean); // Sjekk lengde (EAN-8 eller EAN-13) if (!in_array(strlen($ean), [8, 13])) { throw new InvalidArgumentException("EAN må være 8 eller 13 siffer"); } // Sjekk at det kun er tall if (!ctype_digit($ean)) { throw new InvalidArgumentException("EAN kan kun inneholde tall"); } // Valider kontrollsiffer if (!self::validerKontrollsiffer($ean)) { throw new InvalidArgumentException("Ugyldig EAN kontrollsiffer"); } return $ean; } private static function validerKontrollsiffer($ean) { $siffer = str_split($ean); $kontroll = array_pop($siffer); $sum = 0; foreach ($siffer as $index => $tall) { $sum += $tall * (($index % 2 === 0) ? 1 : 3); } $beregnetKontroll = (10 - ($sum % 10)) % 10; return $beregnetKontroll == $kontroll; } public static function validerSøkeord($søkeord) { $søkeord = trim($søkeord); if (strlen($søkeord) < 2) { throw new InvalidArgumentException("Søkeord må være minst 2 tegn"); } if (strlen($søkeord) > 100) { throw new InvalidArgumentException("Søkeord kan ikke være lengre enn 100 tegn"); } return $søkeord; } } // Bruk validering try { $ean = InputValidator::validerEAN('7035620033148'); $produkt = $api->request("products/ean/{$ean}"); } catch (InvalidArgumentException $e) { echo "Ugyldig input: " . $e->getMessage(); } ``` ## Ytelse og beste praksis ### 1. Caching for bedre ytelse ```php class CachedKassalappAPI extends KassalappAPI { private $cache = []; private $cacheVarighet = 3600; // 1 time public function requestCached(string $endpoint, array $params = []) { $cacheNøkkel = $this->lagCacheNøkkel($endpoint, $params); // Sjekk cache if (isset($this->cache[$cacheNøkkel])) { $cacheData = $this->cache[$cacheNøkkel]; if (time() - $cacheData['tid'] < $this->cacheVarighet) { return $cacheData['data']; } } // Hent fra API $data = $this->request($endpoint, $params); // Lagre i cache $this->cache[$cacheNøkkel] = [ 'data' => $data, 'tid' => time() ]; return $data; } private function lagCacheNøkkel($endpoint, $params) { return md5($endpoint . serialize($params)); } public function tømCache() { $this->cache = []; } } ``` ### 2. Batch-operasjoner ```php class BatchProcessor { private $api; private $batch = []; private $batchStørrelse = 10; public function __construct(KassalappAPI $api) { $this->api = $api; } public function leggTilBatch($ean) { $this->batch[] = $ean; if (count($this->batch) >= $this->batchStørrelse) { return $this->prosesserBatch(); } return []; } public function prosesserBatch() { $resultater = []; foreach ($this->batch as $ean) { try { $produkt = $this->api->request("products/ean/{$ean}"); $resultater[$ean] = $produkt['data']; } catch (Exception $e) { $resultater[$ean] = null; } // Vent litt mellom forespørsler for å unngå rate limiting usleep(100000); // 100ms } $this->batch = []; return $resultater; } } ``` ### 3. Asynkrone forespørsler ```php use GuzzleHttp\Pool; use Psr\Http\Message\ResponseInterface; use GuzzleHttp\Exception\RequestException; class AsyncKassalappAPI extends KassalappAPI { public function hentFlereProdukterAsync(array $eanListe): array { $requests = function () use ($eanListe) { foreach ($eanListe as $ean) { yield $ean => $this->client->requestAsync('GET', "products/ean/{$ean}"); } }; $resultater = []; $pool = new Pool($this->client, $requests(), [ 'concurrency' => 5, // Maks 5 samtidige forespørsler 'fulfilled' => function (ResponseInterface $response, $ean) use (&$resultater) { $body = $response->getBody()->getContents(); $data = json_decode($body, true); if (json_last_error() === JSON_ERROR_NONE) { $resultater[$ean] = $data; } else { $resultater[$ean] = ['error' => 'Invalid JSON response']; } }, 'rejected' => function (RequestException $reason, $ean) use (&$resultater) { $resultater[$ean] = ['error' => $reason->getMessage()]; } ]); // Vent til alle forespørsler er fullført $pool->promise()->wait(); return $resultater; } } ``` ### 4. Tips for optimal bruk ```php // ✅ GJØR DETTE: // 1. Bruk kategorier for å redusere API-kall $kategoriProdukter = $api->request('products', [ 'category_id' => 123, 'sort' => 'price_asc' ]); // 2. Bruk 'unique' parameter for å få kun unike produkter $unikeProdukter = $api->request('products', [ 'search' => 'melk', 'unique' => true ]); // 3. Bruk EAN-oppslag når mulig (raskere enn søk) $produkt = $api->request("products/ean/7035620033148"); // 4. Cache statiske data som kategorier og butikker $kategorier = $cachedApi->requestCached('categories'); // ❌ UNNGÅ DETTE: // 1. Ikke gjør for mange samtidige forespørsler // FEIL: for ($i = 0; $i < 100; $i++) { $api->request('products', ['page' => $i]); } // 2. Ikke ignorer rate limiting // FEIL: while (true) { $api->request('products'); // Vil treffe rate limit } // 3. Ikke hent alle produkter hvis du kun trenger noen få // FEIL: $alleProdukter = $api->request('products'); // Henter 100 produkter $melk = array_filter($alleProdukter, fn($p) => strpos($p['name'], 'melk')); ``` ## Avslutning Med Kassalapp API har du nå tilgang til Norges mest omfattende database over dagligvarepriser. Denne guiden har vist deg hvordan du: - Setter opp og autentiserer API-tilgang - Søker og filtrerer produkter effektivt - Bygger prissammenlignings-tjenester - Håndterer feil og rate limiting profesjonelt - Optimaliserer ytelse med caching og batch-operasjoner --- _Lykke til med utviklingen! Vi gleder oss til å se hva du bygger med Kassalapp API._