API
Det åpne GraphQL-API-et til Hva skjer i Midtre Gauldal?. Les oversikten først hvis du ikke har gjort det; den fullstendige typelisten finner du på referansesiden og i schema.graphql.
Endepunkt
POST https://hvaskjerimidtregauldal.no/graphQL
Content-Type: application/json
{"query": "...", "variables": {...}, "operationName": "..."}
variablesogoperationNameer valgfrie. Svar er JSON:{"data": ..., "errors": [...], "extensions": {...}}.- GET godtas for spørringer (
?query=...&variables=..., URL-kodet), men bare med headerenApollo-Require-Preflight: true. Uten den svarer tjeneren 400 med en CSRF-melding. Bruk helst POST. - CORS er åpent: en nettside på hvilket som helst opphav kan kalle endepunktet direkte. Egne headere utløser en preflight, som besvares.
- Sandboxen er det samme endepunktet åpnet i en nettleser (en forespørsel som godtar HTML): skjemaet, autofullføring og en kjørbar spørring. Introspeksjon er på.
- Det er ingen versjonering i URL-en. Endringer kunngjøres i endringsloggen og, for kallere med nøkkel, på e-post før de lander.
Headere
| Header / parameter | Hvem sender den | Betydning |
|---|---|---|
X-Api-Key: hsk_… |
du | Applikasjonens nøkkel. Identitet, ikke sikkerhet: se Nøkler. |
?key=hsk_… |
du, når headere er utenfor rekkevidde | Samme nøkkel som parameter i spørrestrengen, for plattformer som ikke kan sette headere. |
X-Page-Url: https://… |
innbygginger i nettleser | Full URL til siden innbyggingen står på. Nettlesere sender bare opphavet som Referer på tvers av opphav, så uten denne er en widget på example.no/kultur/program umulig å skille fra enhver annen side på example.no. |
X-Client-Id: name/version |
våre egne klienter | Reservert for kalenderens egen front-end, tjenerrenderingen, widgeten og skjermappene. Ikke send den: trafikken din ville blitt ført under vår. |
En nøkkel som er ukjent eller trukket tilbake får ikke forespørselen til å feile: den behandles som anonym, og
svaret bærer en extensions.notice som sier det.
events-spørringen
query Upcoming($page: Int, $pageSize: Int, $filter: Filter) {
events(page: $page, pageSize: $pageSize, filter: $filter) {
totalCount
hasMore
pageInfo { currentPage pageSize totalPages }
data {
id
event_slug
eventLink
title_nb
title_en
startDate
endDate
startTime
duration
categories
mode
venue { id name slug address location { latitude longitude } }
organizers { id name slug website }
images { urlSmall urlLarge alt }
repetitions { startDate endDate startTime venue { name } }
}
}
}
Paginering
events(filter, page, pageSize). page starter på 0; pageSize er 10 som standard. Les
totalene fra EventConnection, ikke fra lengden på data:
totalCount— arrangementer som matcher filteret, på tvers av alle sider;hasMore— ompage + 1har noe;pageInfo—currentPage,pageSize,totalPages.
page < 0 eller pageSize <= 0 gir feilen BAD_USER_INPUT. Forbindelsen bærer også fasetter over
hele det filtrerte settet (ikke bare siden): venues, organizers og categories, hver en liste
av { …, hits }.
Filter
Alle felt er valgfrie. Kombiner fritt; hver betingelse må holde.
| Felt | Betydning |
|---|---|
fromDate |
Arrangementer som fortsatt pågår på dette tidspunktet eller senere: ikke avsluttet ennå, eller (for arrangementer publisert uten sluttid, der endDate == startDate) startet for mindre enn tre timer siden. Standard er nå. |
untilDate |
Arrangementer som starter før dette tidspunktet. |
fromStartDate |
Arrangementer som starter på dette tidspunktet eller senere. Bruk denne heller enn fromDate når pågående arrangementer ikke skal vises. |
categories |
Kategori-id-er (se Identifikatorer); hvilken som helst av dem. Tom betyr alle. |
notCategories |
Utelukk disse kategori-id-ene. |
venues, venueSlug |
Sted-slugs (Venue.slug), hvilken som helst av dem / én av dem. |
organizers, organizerSlug |
Arrangør-slugs (Organizer.slug). |
searchTerm |
Fritekst, matchet uavhengig av store/små bokstaver og aksenter mot titler, beskrivelser, stikkord, stedsnavn, arrangørnavn og kategorietiketter; når ingenting matcher bokstavelig, matches titler og beskrivelser omtrentlig (én eller to skrivefeil). |
tag |
Ett stikkord fra Event.tags. |
mode |
online eller offline. |
superEvent |
Id-en til et beholderarrangement (en festival, et marked): programmet dets. |
onlyFeatured |
Bare arrangementer arrangøren har fremhevet. |
onlyFeaturedSpecialEvent |
Bare arrangementer fremhevet i lisensens spesialarrangement, der det er satt opp. |
cancelledNotIncluded, soldOutNotIncluded |
Fjern avlyste / utsolgte arrangementer. |
hoursRange |
HH:mm-HH:mm, f.eks. 16:00-22:00: arrangementer som starter innenfor det vinduet. |
groupRepetitionsByDay |
Utvid hver fremtidig dag i et arrangement med flere datoer til sin egen node (med den dagens startDate), så en liste kan vise én rad per dag. Datoer samme dag blir i den nodens repetitions. |
municipality, postalCodes |
Filtrer på stedets adresse. |
sortBy |
Utgått: resultatene er alltid kronologiske. |
Datoargumenter tar YYYY-MM-DD HH:mm:ss etterfulgt av en forskyvning (+02:00, +0200, +02 eller Z),
for eksempel "2026-09-01 00:00:00+02:00". En dato som ikke kan tolkes gir feilen Query Arguments invalid
med extensions.invalidArgs som navngir argumentet.
{
events(
filter: {
searchTerm: "konsert"
fromDate: "2026-09-01 00:00:00+02:00"
untilDate: "2026-12-31 23:59:59+01:00"
}
page: 0
pageSize: 20
) {
totalCount
data { id title_nb startDate venue { name } }
}
}
Andre spørringer
| Spørring | Returnerer |
|---|---|
eventByID(eventID: String!) |
Ett arrangement etter id. |
eventBySlug(eventSlug: String!) |
Ett arrangement etter event_slug (siste segment i eventLink). |
eventsBySlugs(eventsSlugs: [String]!) |
Flere arrangementer etter slug. |
eventByTitle(title: String!, lan: String!) |
Ett arrangement etter eksakt tittel; lan er nb eller en. |
allUpcomingSuperEvents |
Beholderarrangementer (festivaler, markeder) som ikke er avsluttet. |
allUpcomingEventsInArea(minLatitude, maxLatitude, minLongitude, maxLongitude) |
Kommende arrangementer med sted innenfor boksen. |
categories |
Denne lisensens kategorier med id-er, etiketter, slugs og underkategorier. |
venues, organizers |
Katalogen over steder og arrangører, med id-er og slugs. |
Det finnes ingen mutasjoner. Arrangementer publiseres av mennesker gjennom kalenderens egne skjemaer og av kalenderens egne importører.
Datoer
To fakta. Hvert av dem har gitt feil program på noens nettsted.
1. startDate og endDate bærer UTC-forskyvningen som gjelder på arrangementets dato. Norge er
+01:00 om vinteren og +02:00 om sommeren, og verdien sier hvilken:
2026-02-14 19:00:00+01:00 en februarkonsert kl. 19:00 Oslo-tid
2026-07-14 19:00:00+02:00 en julikonsert kl. 19:00 Oslo-tid
Begge er kl. 19:00 på veggklokka. Begge er gyldige tidspunkt. Det de ikke er, er «ISO med +00»: en parser satt opp med fast forskyvning, eller en formatering som skriver i tjenerens egen sone, viser 18:00 eller 20:00 for én av dem, og feilen snur ved hver overgang til og fra sommertid. Et reiselivsnettsted viste hvert klokkeslett feil i ukevis på denne måten.
- Formatet er
YYYY-MM-DD HH:mm:ss±HH:mmmed et mellomrom mellom dato og tid. En streng RFC 3339-parser vil ha enT: bytt ut mellomrommet, så tolkes den overalt. - For visning: konverter tidspunktet til
Europe/Oslo(aldri til leserens eller tjenerens sone). - Eller dropp regnestykket:
startTime(HH:mm) er den norske starten på veggklokka nøyaktig slik arrangøren skrev den, ogdurationer i minutter. Det finnes ikke noeendTime-felt; utled det fraendDateiEurope/Osloeller frastartTime + duration. publishingDateogticketsFromDatefølger samme regel.created_atogupdated_ater bokføring og gjør ikke nødvendigvis det.
2. startDate er neste kommende forekomst; repetitions lister bare fremtidige. Et
arrangement med flere datoer er ett arrangement med én id. Når den første datoen har passert, løfter
API-et den neste datoen som fortsatt gjelder inn i startDate, endDate, startTime, duration,
venue, ticketsURL, eventCancelled og eventSoldOut, og repetitions holder datoene etter
den. Passerte datoer returneres ikke, så samme id svarer med en annen startDate neste uke.
Ikke nøkle dine egne poster på id + startDate med mindre du vil ha én post per forekomst;
i så fall gir groupRepetitionsByDay deg dagsnodene direkte.
Identifikatorer
3. Filtrer og vis etter id. Navn og slugs er presentasjon.
Event.ider identiteten til et arrangement hele dets levetid.event_sluger URL-segmentet (eventLinker hele URL-en);title_nb/title_enredigeres av mennesker.Event.categorieser en liste over kategori-id-er. Hent etikettene fracategoriesved hver kjøring — ikke én gang ved installasjon, og aldri skrevet for hånd. Id-er er forskjellige mellom lisenser (samme etikett erCONCERTpå én kalender og noe annet på en annen), og en lisens kan bytte ut hele taksonomien sin: en pensjonert id forsvinner fracategories, arrangementene som bar den migreres, og id-en gjenbrukes aldri til noe annet. Å filtrere på en id som ikke lenger finnes icategoriesreturnerer ingenting, uten feilmelding. Endringsloggen registrerer hver slik endring.VenueogOrganizerhar enidog enslug.events-filteret tar sluggen (venues,organizers); les den fravenues/organizersheller enn å utlede den fra et navn.categoriesreturnerervisibleper kategori; skjulte er fortsatt gyldige id-er på arrangementer.
Kategoriene til Hva skjer i Midtre Gauldal?
Slik de fulgte med dette bygget. categories-spørringen er sannheten ved kjøring.
| id | name_nb | name_en | slug_nb | slug_en |
|---|---|---|---|---|
CHURCH |
Kirke | Church | kirke | church |
CULTURE |
Kultur & historie | Culture & history | kultur-historie | culture-history |
FAMILY |
Barn & familie | Children & family | barn-familie | children-family |
FOOD |
Mat & marked | Food & market | mat-marked | food-market |
LECTURE |
Kurs & foredrag | Courses & talks | kurs-foredrag | courses-talks |
MOVIES |
Kino | Cinema | kino | cinema |
MUSIC |
Konsert & musikk | Concerts & music | konsert-musikk | concerts-music |
OTHER |
Annet | Other | annet | other |
SENIOR |
Senior | Senior | senior | senior |
SOCIAL |
Sosialt & samfunn | Social & community | sosialt-samfunn | social-community |
SPORT |
Idrett & friluft | Sports & outdoors | idrett-friluft | sports-outdoors |
THEATER |
Teater & scene | Theatre & stage | teater-scene | theatre-stage |
Billettyper
Price.type er en billettype-id. De innebygde på denne kalenderen:
| id | name_nb | name_en |
|---|---|---|
ASSISTANT |
Ledsager | Assistant |
CHILD |
Barn | Child |
FAMILY |
Familie | Family |
MEMBERS |
Medlemmer | Members |
REGULAR |
Vanlig | Regular |
REDUCED |
Redusert | Reduced |
SENIOR |
Honnør | Senior |
STUDENT |
Student | Student |
En arrangør kan også definere egne billettyper for sine arrangementer; de id-ene står ikke
her, og Price.name_nb / Price.name_en bærer etiketten når arrangøren ga en.
Pris og kapasitet
4. Ingenting som kommer fra et skjema er garantert numerisk.
Price.priceer typetInt, og tjeneren avrunder det arrangøren lagret — men den lagrede verdien kan være1.595(skrevet med norsk tusenskilletegn),150,-eller tom. Når den ikke kan leses som tall er feltetnull. Del aldri på det, anta aldri øre.ticketsInformationsier hvilken avfree,noTicketsInfoellerticketsInfosom gjelder;priceser bare meningsfull forticketsInfo.ticketsURLer der billetter selges når de selges et annet sted.duration,minimumAge,maximumAge,cancellationPeriod,viewskan værenull.- Kapasitetsfeltene (
registrationEnabled,availableTickets,activeTickets,maxBookingDate,maxBookingTime,paymentMethod) finnes for kalendere der besøkende melder seg på gjennom kalenderen selv. På en kalender uten påmelding er denullellerfalse; ikke lesavailableTickets: nullsom «utsolgt».eventSoldOuter arrangørens eksplisitte flagg. - En
Repetitionkan bære sine egneprices; når den ernull, gjelder arrangementetsprices.
Bilder
Event.images er en liste; det første bildet er forsidebildet. urlSmall og urlLarge er samme
bilde i to størrelser.
Et kort beskjærer som regel bildet til en boks med sin egen form, og en beskjæring rundt midten
kutter hodene av et gruppebilde. focusX og focusY sier hvor menneskene er, som andeler av
bildet: 0, 0 er øverste venstre hjørne, 1, 1 nederste høyre. Legg det punktet i bildet på samme
punkt i boksen din, så blir det i bildet uansett hvilken form boksen har. I CSS er det én deklarasjon:
img { object-fit: cover; object-position: 51% 31%; } /* focusX: 0.51, focusY: 0.31 */
{
events(pageSize: 3) {
data { title_nb images { urlLarge alt focusX focusY width height } }
}
}
- Begge er
nullnår det ikke ble funnet noe ansikt i bildet, og den første halvtimen eller så av et nytt bildes liv, før det er analysert. Behold din egen standardbeskjæring da. widthogheighter pikselstørrelsen til bildet påurlLarge, ognulltil det er analysert.
Feil
Svarkroppen er alltid JSON.
| Situasjon | HTTP | Kropp |
|---|---|---|
| Kroppen er ikke gyldig JSON | 400 | {"errors":[{"message":"Malformed JSON body"}]} |
GET uten Apollo-Require-Preflight |
400 | errors[0].extensions.code = "BAD_REQUEST", meldingen nevner CSRF |
| Spørringen validerer ikke (ukjent felt eller argument, feil type) | 400 | errors[0].extensions.code = "GRAPHQL_VALIDATION_FAILED"; meldingen navngir feltet |
| Ugyldig argumentverdi (negativ side, dato som ikke kan tolkes) | 200 | data: null, errors[0].extensions.code = "BAD_USER_INPUT" eller extensions.invalidArgs |
| Feil i en resolver | 200 | data med null for feltet som feilet og en oppføring i errors |
En errors-liste kan følge med delvise data; sjekk etter den i hvert svar, ikke bare ved
statuser som ikke er 200.
extensions.notice er ikke en feil. Det er en streng på vellykkede svar til forespørsler
uten gyldig nøkkel, som peker til denne portalen. En klient som ignorerer extensions påvirkes ikke;
en som leser den kan logge den én gang og gå videre.
Rate limits og kvote
Ingen i dag, med eller uten nøkkel. Når en kvote kommer, beholder applikasjoner med nøkkel sitt eget budsjett, og anonym trafikk som først ses etter den datoen kan få en lavere. Ikke ennå — dette avsnittet endres først, og endringsloggen sier fra.
Cache det du kan: en liste som endrer seg noen ganger om dagen trenger ikke hentes hvert sekund.
Kontakt
Spørsmål, et felt du trenger, et endringsvarsel du ikke fikk: post@hvaskjerimidtregauldal.no. Si hvilken kalender og, hvis du har en, hvilken nøkkel.