Lokal utveckling: http://localhost:8000/api
Produktion: https://brottsplatskartan.se/api
Alla API-endpoints returnerar JSON-data.
Hämta händelser med filtrering och paginering.
Optimerad med: N+1 fix (eager loading av locations)
Query-parametrar:
limit(integer, default: 10) - Antal händelser per sidaarea(string, optional) - Län, t.ex. "Stockholms län"location(string, optional) - Plats/gata, t.ex. "Folkungagatan"type(string, optional) - Händelsetyp, t.ex. "Inbrott", "Rån"page(integer, default: 1) - Sidnummer för paginering
Exempel:
# Alla händelser (10 st)
curl "http://localhost:8000/api/events"
# Händelser i Stockholms län
curl "http://localhost:8000/api/events?area=Stockholms+län&limit=20"
# Inbrott i Stockholm
curl "http://localhost:8000/api/events?type=Inbrott&area=Stockholms+län"
# Med paginering
curl "http://localhost:8000/api/events?page=2&limit=50"Svar-struktur:
{
"links": {
"current_page": 1,
"first_page_url": "...",
"last_page": 29617,
"next_page_url": "...",
"prev_page_url": null,
"per_page": 10,
"total": 296161
},
"data": [
{
"id": 296231,
"title_type": "Mord/dråp",
"title_location": "Stockholm",
"headline": "Flera personer ringer polisen...",
"description": "...",
"content": "...",
"location_string": "Riksby, Bromma, Stockholm, Stockholms län",
"lat": 59.3444841,
"lng": 17.94539,
"date_human": "4 dagar sedan",
"permalink": "http://localhost:8000/...",
"image": "https://kartbilder.brottsplatskartan.se/...",
"external_source_link": "https://polisen.se/..."
}
]
}Hämta händelser optimerade för kartvisning (senaste 3 dagarna, max 500 st).
Optimerad med: N+1 fix (eager loading av locations) Cache: 5 minuter
Query-parametrar: Inga
Exempel:
curl "http://localhost:8000/api/eventsMap"Svar-struktur:
{
"data": [
{
"id": 296231,
"time": "17:37",
"time_human": "4 dagar sedan",
"headline": "Flera personer ringer polisen...",
"type": "Mord/dråp",
"locations": "Riksby, Bromma, Stockholm",
"lat": 59.3444841,
"lng": 17.94539,
"image": "https://kartbilder.brottsplatskartan.se/...",
"permalink": "http://localhost:8000/..."
}
]
}Hämta en enskild händelse baserat på ID.
Query-parametrar: Inga (ID i URL:en)
Exempel:
curl "http://localhost:8000/api/event/296231"Svar: Samma struktur som ett element i /api/events data-arrayen.
Hämta händelser nära en specifik koordinat.
Query-parametrar:
lat(float, required) - Latitudlng(float, required) - Longituddistance(integer, optional, default: 25) - Avstånd i kilometerlimit(integer, optional, default: 10) - Max antal händelser
Exempel:
# Händelser nära Stockholms centralstation
curl "http://localhost:8000/api/eventsNearby?lat=59.3293&lng=18.0686&distance=5&limit=20"Hämta lista över alla län (administrative_area_level_1).
Query-parametrar: Inga
Exempel:
curl "http://localhost:8000/api/areas"Svar:
{
"data": [
"Stockholms län",
"Västra Götalands län",
"Skåne län",
...
]
}Hämta händelser som har associerade nyhetsartiklar från TextTV.
Query-parametrar:
limit(integer, optional, default: 10)
Exempel:
curl "http://localhost:8000/api/eventsInMedia?limit=20"Hämta mest visade händelser nyligen.
Query-parametrar:
limit(integer, optional, default: 10)minutes(integer, optional, default: 60) - Tidsperiod i minuter
Exempel:
curl "http://localhost:8000/api/mostViewedRecently?limit=20&minutes=120"Huvudfält:
id(integer) - Unikt IDtitle_type(string) - Händelsetyp (t.ex. "Inbrott", "Rån", "Trafikolycka")title_location(string) - Primär platsheadline(string) - AI-genererad rubrik eller fallbackdescription(string) - Kort beskrivning/teasercontent(string) - Fullständig text (HTML-formaterad)content_teaser(string) - Kortversion för listor
Datum/tid:
pubdate_iso8601(string) - ISO 8601 formatpubdate_unix(integer) - Unix timestampdate_human(string) - Relativ tid (t.ex. "4 dagar sedan")
Geografisk data:
lat(float) - Latitudlng(float) - Longitudlocation_string(string) - Fullständig platsträng med länlocation_string_2(string) - Kortare platsträng utan länadministrative_area_level_1(string) - Länadministrative_area_level_2(string|null) - Kommun
Viewport (för kartbilder):
viewport_northeast_lat(float)viewport_northeast_lng(float)viewport_southwest_lat(float)viewport_southwest_lng(float)
Bilder:
image(string) - Statisk kartbild (640x320px)image_far(string) - Kartbild med större zoom-out
Länkar:
permalink(string) - Länk till händelsen på brottsplatskartan.seexternal_source_link(string) - Länk till original på polisen.se
Följande endpoints har optimerats för att undvika N+1 query-problem:
- ✅
/api/events- Använder->with('locations') - ✅
/api/eventsMap- Använder->with('locations')
Före optimering:
/api/eventsmed 20 händelser: ~22 queries/api/eventsMapmed 500 händelser: ~501 queries
Efter optimering:
/api/eventsmed 20 händelser: ~3 queries (85% minskning)/api/eventsMapmed 500 händelser: ~2 queries (99% minskning)
API endpoints använder två cache-lager:
-
Response Cache (Spatie Laravel Response Cache)
- Cachar hela HTTP-responsen (snabbast vid cache hit)
/api/events- 10 minuter/api/eventsMap- Hanteras av web-routes standard (30 min)- Response header:
laravel-responsecache: cached on <timestamp>
-
Query Cache (Laravel Cache facade)
- Cachar databas-resultat som fallback
/api/events- 2 minuter (förhindrar COUNT queries från paginate)/api/eventsInMedia- 5 minuter/api/eventsMap- 5 minuter- Geografiska queries - 9-15 minuter
- Datum-navigering - 14-23 minuter
Cache-implementation:
- Redis som backend för båda lagren
- Automatisk cache-invalidering efter TTL
- Unik cache-nyckel per parameter-kombination
- Query-parametrar som
?t=,?_=filtreras bort (skapar inte separata cache-entries)
Nuvarande status: Ingen rate limiting implementerad (TODO)
Rekommendation för produktion:
- Implementera rate limiting för att undvika överbelastning
- Överväg API-nycklar för högre volymanvändning
API:et tillåter cross-origin requests (CORS är aktiverat).
Standard HTTP-statuskoder:
200- Lyckad förfrågan404- Händelse/resurs inte hittad422- Valideringsfel (felaktiga parametrar)500- Serverfel
Fel-svar:
{
"error": "Resource not found",
"message": "Event with ID 999999 does not exist"
}curl "http://localhost:8000/api/events?type=Inbrott&area=Stockholms+län&limit=20" | jq '.data[] | {headline, location_string, date_human}'fetch('http://localhost:8000/api/eventsMap')
.then(res => res.json())
.then(data => {
data.data.forEach(event => {
// Lägg till marker på kartan
addMarker(event.lat, event.lng, event.headline);
});
});curl "http://localhost:8000/api/events?area=Västra+Götalands+län&type=Trafikolycka&limit=10&page=1"import requests
# Hämta händelser
response = requests.get('http://localhost:8000/api/events', params={
'area': 'Stockholms län',
'limit': 20
})
events = response.json()['data']
for event in events:
print(f"{event['headline']} - {event['location_string']}")const axios = require('axios');
async function getEvents(area, limit = 10) {
const response = await axios.get('http://localhost:8000/api/events', {
params: { area, limit }
});
return response.data.data;
}
getEvents('Stockholms län', 20).then(events => {
events.forEach(e => console.log(e.headline));
});$area = 'Stockholms län';
$limit = 20;
$url = "http://localhost:8000/api/events?area=" . urlencode($area) . "&limit=$limit";
$response = file_get_contents($url);
$data = json_decode($response, true);
foreach ($data['data'] as $event) {
echo $event['headline'] . "\n";
}För att testa API:et lokalt, kör:
# Starta lokal server
php artisan serve
# Testa endpoints
curl http://localhost:8000/api/events
curl http://localhost:8000/api/eventsMap
curl http://localhost:8000/api/areas- ✅ Implementerat Spatie Response Cache för API endpoints (10-30 min TTL)
- ✅ CustomRequestHasher filtrerar query-parametrar (
?t=,?_=) - ✅ Multi-tier caching: Response Cache (yttre) + Query Cache (inre)
- ✅ Implementerat query cache för
/api/events(2 min TTL) - eliminerar upprepade COUNT queries - ✅ Implementerat query cache för
/api/eventsInMedia(5 min TTL) - ✅ 100% query-reduktion vid cache-träff (3 queries → 0 queries)
- ✅ Fixat N+1 query problem i
/api/eventsoch/api/eventsMap - ✅ Reducerat antal queries med 85-99%
- ✅ Förbättrad prestanda och minskad databas-belastning
- ✅ Skapad virtuell kolumn
date_created_atför optimerade datum-queries - ✅ Lagt till index på datum-kolumner
För frågor eller buggrapporter, skapa ett issue på GitHub: https://github.com/bonny/brottsplatskartan-web/issues