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
- Kom i gang
- Autentisering
- Produktsøk
- Filtrering og sortering
- Strekkode-oppslag
- Butikklokasjoner
- Kategorier og merker
- Avanserte eksempler
- Feilhåndtering
- 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:
- Gå til https://kassal.app/api
- Opprett en gratis konto
- Kopier din API-nøkkel fra dashboardet
Steg 2: Installer Guzzle
Vi bruker Guzzle HTTP-klient for å gjøre API-kall enklere:
composer require guzzlehttp/guzzle
Steg 3: Grunnleggende oppsett
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
class KassalappAPI {
private $client;
private $apiKey;
private const BASE_URL = 'https://kassal.app/api/v1/';
public function __construct(string $apiKey) {
$this->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:
$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:
// 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:
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:
// 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:
// 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
// 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:
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:
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
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
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
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
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
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
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
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
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
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
// ✅ 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.