Fra FSWS-CDM (REST) til FS GraphQL API
⚠ Denne tjenesten avvikles etter 31. mars 2027. Nye integrasjoner bør bygges direkte på FS GraphQL API. Se Sikts avviklingspraksis og avviklingsloggen. Kilde: fellesstudentsystem.no/.../rest/cdm.html
Denne guiden gjelder REST-varianten. SOAP-varianten av FSWS-CDM er allerede avviklet (24.04.2025) og svarer ikke lenger.
Denne guiden hjelper deg migrere fra FSWS-CDM (REST) til FS GraphQL API. Listen med eksempler under er ikke komplett. Ta kontakt med fs-support@sikt.no dersom du trenger hjelp til å finne en spørring som passer ditt behov.
Forskjeller og likheter
FSWS-CDM er ett enkelt GET-endepunkt (/fsrest/rest/cdm/studiedata) som leverer studieprogrammer og etter-/videreutdanningskurs i et standardformat for læringsdata, primært brukt av Utdanning.no. FS GraphQL API dekker studieprogram-delen med rot-spørringen publiseringsklareStudieprogram. Denne spørringen lar deg sette samme type publiseringsavgrensning som CDM brukte, men du må selv be om den eksplisitt i filteret — den er ikke satt som standard.
Emnedata er ikke dekket her. Den tekniske REST-siden for CDM lister emner som del av tjenesten, men Sikts brukerdokumentasjon om overføringen til Utdanning.no merker «Emner» som ikke implementert, og i praksis er det studieprogramdelen som overføres.
Publisering til Utdanning.no er ikke det samme som «publisering» ellers i API-et. CDM eksporterer kun studieprogrammer som er markert for ekstern publisering i FS (feltet for ekstern publisering på Infotermin-fanen), ikke «Publisér Internt». I GraphQL heter dette filteret kanPubliseresTilEksterneRegistre — ikke kanPubliseres, som gjelder intern publisering. De to er søsterfelt på samme Infotermin-rad, men settes uavhengig av hverandre. Se seksjonene under for kontraktsnivå per entitet.
Språk velges ikke lenger i forespørselen. CDM tok sprak=BOKMÅL|NYNORSK|ENGELSK og returnerte ett språk per kall (bokmål som standard hvis parameteren ble utelatt). FS GraphQL API returnerer i stedet alle registrerte språk samtidig — du velger selv hvilke du vil ha med i spørringen.
Semester/termin må angis eksplisitt. CDM beregnet selv hvilket semester som var «gjeldende» ut fra datoene i FS på spørretidspunktet. I FS GraphQL API må du selv angi hvilke terminer du spør for — det finnes ingen tilsvarende automatikk. Får du tomme eller uventede resultater sammenlignet med CDM, sjekk terminfilteret først.
Terminfilteret på publiseringsklareStudieprogram er på vei ut
På publiseringsklareStudieprogram er terminer deprekert og fjernes etter 31. mars 2027 — samme dato som FSWS-CDM selv avvikles. Erstatningen terminkoder tar de samme verdiene (arstall + terminbetegnelse), men er foreløpig experimental og krever Feature-Flags: experimental. Det finnes også terminerV2, som tar termin-ID-er i stedet (også experimental). Bygg produksjonsintegrasjoner på terminer inntil terminkoder er hevet til stable — den virker som normalt fram til fjerningsdatoen. Følg med på kontraktsnivået til terminkoder når du planlegger byttet.
Merk: Studieprogrammer og etter-/videreutdanningskurs kommer fra samme XML-dokument i CDM, men fra separate GraphQL-spørringer. Skal du bygge noe tilsvarende det samlede CDM-dokumentet, må du kalle dem hver for seg og sette dem sammen selv.
Et konkret utsnitt: fra CDM-XML til GraphQL
CDM sitt element for et studieprograms korte presentasjon, programIntroduction, ser omtrent slik ut i XML-svaret (utsnitt, ikke et fullt dokument):
<program>
<code>ALLINN</code>
<programIntroduction xml:lang="nb">
Er du interessert i ...? Utdanningen gir deg mulighet til ...
</programIntroduction>
</program>
Det samme innholdet henter du i FS GraphQL API via beskrivelsesavsnitt med cdmTag lik institusjonens eget valg av CDM-element (se Infotekster for en fullstendig spørring — cdmTag-verdien der er institusjonsspesifikk, ikke nødvendigvis prg-programIntroduction). Resten av denne guiden viser tilsvarende GraphQL-spørring og -svar for hvert datasett, uten å gjenta selve CDM-XML-en hver gang.
Sikt publiserer ingen elementliste eller XSD for CDM-dokumentet, så denne guiden kan ikke gi en fullstendig element-for-element-tabell. Finner du ikke igjen et CDM-element du er avhengig av, beskriv det for fs-support@sikt.no — se Finner du ikke det du trenger?.
Før du starter
Sett deg inn i disse tingene før du går videre:
- Tilgang, endepunkt og kontraktsnivå (
Feature-Flags-header): Kom i gang - Paginering: Spørringer — eksemplene under bruker
first: 5/first: 10for å holde dem korte. Et fullt uttrekk krever at du følgerpageInfo/endCursorog gjentar kallet medafter. - Feilhåndtering: Mutasjoner
- Autorisasjon (RAS): Tilgangsstyring med RAS
- Bruker du en integrasjonsplattform (Gravitee/IntArk): FS GraphQL API og IntArk
- Utforsk skjemaet selv: Introspeksjon
Tilgang (RAS): hvilke roller trenger du?
FS GraphQL API styrer tilgang med Oracle RAS (se Tilgangsstyring med RAS). CDM krevde eget brukernavn og passord, men hadde ingen tilsvarende rolleoppdeling.
publiseringsklareStudieprogram, evuKurs og infotekstene under beskrivelsesavsnitt på studieprogram krever ingen egen rolle. Dataene ligger bak STUDIEELEMENTER_LES1, som alle brukere får automatisk.
Unntak: kurstekster. EvuKurs.beskrivelsesavsnitt er ikke dekket av grunntilgangen — det krever FAGPERSON_ROLLE eller STUDENT_ROLLE. Disse er ikke egne, bestillbare roller på RAS-siden slik STUDIEELEMENTER_LES1 er — har du bare standardtilgangen, får du en tom liste uten feilmelding når du spør etter kurstekster. Trenger du disse, kontakt fs-support@sikt.no.
Merk likevel: i FS GraphQL API gir manglende tilgang som regel et tomt svar, ikke en feilmelding — HTTP 200 og ingen
errors. Får du uventet tomme resultater, er det verdt å utelukke tilgang før du feilsøker selve spørringen.
Kontraktsnivå i eksemplene
Hver seksjon under er merket med kontraktsnivå. stable virker uten videre. beta- og experimental-felt krever headeren Feature-Flags, med nøyaktig de nivåene eksempelet faktisk bruker — se Kom i gang. Hvert eksempel under oppgir sin egen kombinasjon. beta-endringer varsles minst to uker før produksjonssetting; experimental kan endres eller forsvinne helt uten varsel og er ikke ment å bygges mot i produksjon. Trenger du et experimental-felt i en integrasjon som skal driftes, be fs-support@sikt.no om å heve kontraktsnivået.
Institusjonsnummer i eksemplene
Eksemplene under bruker eierInstitusjonsnummer: "1234". Bytt ut «1234» med institusjonsnummeret til ditt lærested.
Merk argumentnavnet. Guiden bruker to ulike navn på samme verdi.
publiseringsklareStudieprogrambrukereierInstitusjonsnummer, mensevuKursogstudieprogramGittStudieprogramkoderV2brukereierOrganisasjonskode.
IDer: er de samme som i FSWS-CDM?
Nei, men det spiller sjelden noen rolle. CDM er et rent eksportformat — det identifiserer rader med institusjonsnr + kode + versjonskode/termin, ikke med en ID du følger opp senere. Har du kun kjørt CDM-uttrekk, trenger du normalt ikke slå opp gamle nøkler i det hele tatt: publiseringsklareStudieprogram gir deg både kode og innhold i samme svar.
Trenger du likevel å hente ett bestemt element du kjenner koden til, finnes egne oppslagsspørringer:
ID-ene du får tilbake (id-feltet) er ugjennomsiktige. Du kan base64-dekode dem, men innholdet er en intern implementasjonsdetalj som kan endres uten varsel — ikke konstruer dem selv, og ikke parse dem for å hente ut de gamle nøklene.
Studieprogrammer
Kontraktsnivå: stable for spørringen, terminfilteret (terminer) og publiseringsfilteret. Feltet url er experimental og krever Feature-Flags: experimental — se Kontraktsnivå i eksemplene.
query PubliseringsklareStudieprogram {
publiseringsklareStudieprogram(
filter: {
eierInstitusjonsnummer: "1234"
kanPubliseresTilEksterneRegistre: true
terminer: [{ arstall: 2023, terminbetegnelse: "HØST" }]
}
first: 10
) {
nodes {
url
termin {
arstall
betegnelse {
kode
}
}
studieprogram {
kode
navnAlleSprak {
nb
}
urlAlleSprak {
und
}
}
}
}
}
Eksempel på svar:
{
"data": {
"publiseringsklareStudieprogram": {
"nodes": [
{
"url": null,
"termin": { "arstall": 2023, "betegnelse": { "kode": "HØST" } },
"studieprogram": {
"kode": "MSPROG1",
"navnAlleSprak": { "nb": "Bachelor i testing" },
"urlAlleSprak": null
}
},
{
"url": null,
"termin": { "arstall": 2023, "betegnelse": { "kode": "HØST" } },
"studieprogram": {
"kode": "MSPROG58",
"navnAlleSprak": { "nb": "Bachelor i testing ny utgaveX" },
"urlAlleSprak": null
}
}
]
}
}
}
Filtrering: kanPubliseresTilEksterneRegistre (STATUS_EKSPORT_EKSTERN) tilsvarer CDM sin avgrensning — uten dette filteret får du alle studieprogrammer som har en InfoTermin-rad, uansett publiseringsstatus.
Study in Norway er en tredje, egen kanal. CDM sitt eksportfelt dekker kun Utdanning.no. Skal du i tillegg gjenskape overføringen til Studyinnorway.no, finnes et eget filter:
kanPubliseresTilRegistreForEngelsksprakligeStudier(STATUS_EKSPORT_STUDYINNORWAY, stable). De to filtrene er uavhengige av hverandre — et program kan være klarert for det ene og ikke det andre.Hjemmeside til studietilbudet kan komme fra tre steder. Nærmest CDM sin egen kilde er
urldirekte på treff-noden (nodes { url }, experimental) — det er URL-en satt på selve Infotermin-raden CDM leser fra. Derneststudieprogram.urlAlleSprak.und(stable). Noen institusjoner setter i stedet en infotekst medcdmTag: "prg-url"(se Infotekster) — dette er en institusjonskonvensjon, ikke en offisiell Sikt-kode. Sjekk flere av dem om den første er tom.Bruk kun
kanPubliseresTilEksterneRegistrei filteret — ikke kombiner medkanPubliseres.kanPubliseresstyrer intern publisering og er urelatert til CDM sin avgrensning (se Forskjeller og likheter). Kombinerer du de to filtrene, mister du programmer som er klarert for ekstern eksport men ikke for intern publisering.Får du et annet resultat enn CDM for samme institusjon/termin, sjekk terminvalget først. CDM beregner «gjeldende termin» implisitt ut fra spørretidspunktet og institusjonens egne, til tider overlappende datointervaller for eksport — ikke ut fra et eksplisitt terminvalg. Det kan gjøre at CDM viser data for en annen termin enn den du tror du sammenligner mot. GraphQL sitt terminfilter er derimot eksplisitt og leverer nøyaktig det som er registrert for akkurat den terminen du spør om. Merk at
publiseringsklareStudieprogramverken filtrerer påerAktiveller på et eget «tilbys i periode»-vindu på studieprogrammet — du kan få treff på program som er deaktivert eller utenfor sitt tilbudsvindu, så lenge det finnes en Infotermin-rad. Vil du gjenskape en slik avgrensning, ta medstudieprogram { erAktiv }og filtrer selv.
EVU-kurs
Kontraktsnivå: stable for selve spørringen. Alle filtre utover eierOrganisasjonskode er beta eller experimental.
⚠ Sjekk om EVU-kurs faktisk er med i ditt uttrekk. Den tekniske REST-siden for CDM sier tjenesten dekker etter- og videreutdanningskurs, mens en annen brukerdok-side om CDM-eksport sier at overføring av slike kurs «er planlagt, men foreløpig ikke satt i drift». Kjør ditt eget CDM-kall og se etter kurselementer i svaret — det avgjør saken for din institusjon. Trenger du en avklaring: fs-support@sikt.no.
evuKurs (samme spørring som i FSWS-Studinfo2-guiden) er det nærmeste tilgjengelige alternativet, men med tre konkrete forbehold:
- Ingen publiseringsavgrensning. Det finnes ikke noe
kanPubliseresTilEksterneRegistrepå EVU-kurs — du får alle kurs og må filtrere selv, f.eks. med filterfelteneerAktivellertilbysInnenforPeriode(begge beta — sendFeature-Flags: beta). Det utfelteerAktivi eksempelet under er derimot stable og krever ingen header. To ting å være obs på medtilbysInnenforPeriode: kurs uten noen dato registrert i det hele tatt (verken fra- eller til-dato) faller alltid utenfor, uansett hvilken periode du spør om; og et kurs med bare én av datoene satt vurderes mot dagens dato på den andre — ikke som åpent i den retningen. Samme spørring kan derfor gi ulikt svar avhengig av når den kjøres. - Kurskoden alene identifiserer ikke et kurs. Samme
kodekan gå igjen for flere kurstidsangivelser. Skal du bygge noe CDM-likt, ta medtidsangivelseskode(beta) i tillegg. - CDM-elementkoblingen ligger ett nivå dypere enn på studieprogram.
EvuKurs.beskrivelsesavsnitt(experimental) har ikkecdmTagdirekte. Verdien finnes likevel — hent den viabeskrivelsesavsnitt { tekstkategori { cdmTag } }(se eksempel under).Tekstkategori.cdmTager også experimental, og kurstekster krever i tillegg egen tilgang — se Tilgang (RAS). Merk også at kurstekster ikke har noenperiode— termin-eksaktmatchen beskrevet under Infotekster gjelder ikke EVU-kurs.
query EvuKurs {
evuKurs(filter: { eierOrganisasjonskode: "1234" }, first: 10) {
nodes {
kode
navnAlleSprak {
nb
}
erAktiv
}
}
}
Eksempel på svar:
{
"data": {
"evuKurs": {
"nodes": [
{
"kode": "00000",
"navnAlleSprak": { "nb": "Språkutvikling og lek" },
"erAktiv": true
},
{
"kode": "06231",
"navnAlleSprak": { "nb": "Lyssetting av utemiljø" },
"erAktiv": true
}
]
}
}
}
Slik henter du CDM-elementet for en kurstekst (krever Feature-Flags: experimental og en av rollene i Tilgang (RAS)):
query EvuKursInfotekster {
evuKurs(filter: { eierOrganisasjonskode: "1234" }, first: 5) {
nodes {
kode
beskrivelsesavsnitt {
innhold
tekstkategori {
kode
cdmTag
}
}
}
}
}
Eksempel på svar:
{
"data": {
"evuKurs": {
"nodes": [
{
"kode": "000\\00",
"beskrivelsesavsnitt": [
{
"innhold": "Og sånn",
"tekstkategori": { "kode": "E-EKSBESKR", "cdmTag": "crs-examKind" }
}
]
}
]
}
}
}
Infotekster
Kontraktsnivå: eksempelet under er helt stable.
CDM sine beskrivende tekster (studieprogrammets presentasjon, opptakskrav, læringsutbytte osv.) kommer fra FS sine Infotype-tekster, kodet om til CDM-elementer ved eksport. I FS GraphQL API er dette nøstet under beskrivelsesavsnitt på hver node, med feltene cdmTag (CDM-elementnavnet) og innhold:
query StudieprogramInfotekster {
publiseringsklareStudieprogram(
filter: {
eierInstitusjonsnummer: "1234"
kanPubliseresTilEksterneRegistre: true
terminer: [{ arstall: 2023, terminbetegnelse: "HØST" }]
}
first: 5
) {
nodes {
studieprogram {
kode
}
beskrivelsesavsnitt {
innhold
cdmTag
tekstkategori {
kode
}
}
}
}
}
Eksempel på svar:
{
"data": {
"publiseringsklareStudieprogram": {
"nodes": [
{
"studieprogram": { "kode": "ALLINN" },
"beskrivelsesavsnitt": [
{
"innhold": "<p> Kort om programmet</p><p>Dette er det eneste studiet i Norge som gir et helhetlig bilde av naturens grunnleggende lover og prosesser. […]</p>",
"cdmTag": "prg-programDescription",
"tekstkategori": { "kode": "P-INNHOLD" }
},
{
"innhold": "<p>Briefly about the program</p><p>This is the only study in Norway that provides a comprehensive picture of nature's basic laws and processes. […]</p>",
"cdmTag": "prg-programDescription",
"tekstkategori": { "kode": "P-INNHOLD" }
}
]
},
{
"studieprogram": { "kode": "MSPROG2" },
"beskrivelsesavsnitt": []
}
]
}
}
}
Kort om feltene i eksempelet:
P-INNHOLDi eksempelet er en lokalt definert Infotype-kode, ikke Sikts standardkode. Institusjonen i eksempelet har selv kobletP-INNHOLDtilprg-programDescription— Sikts anbefalte standardkode for samme CDM-element erP-BESKR(se tabellen lenger ned). Nettopp dette illustrerer poenget: det finnes ingen global, fast kodeliste — les alltidcdmTagfra spørringen.- Tomt
beskrivelsesavsnitt-array er normalt, ikke en feil.MSPROG2har ingen avsnitt for denne terminen i det hele tatt — se terminkoblingen under for hvorfor. cdmTagkan værenullnår institusjonen ikke har konfigurert akkurat den infotypen for CDM-eksport. Les alltidcdmTagfra spørringen, ikke fra en fast liste — verdien er institusjonens eget valg.cdmTagfinnes to steder og gir samme verdi.beskrivelsesavsnitt.cdmTager en snarvei tilbeskrivelsesavsnitt.tekstkategori.cdmTag— begge leser CDM-elementkoden som er satt på avsnittets egen tekstkategori (Infotype), ikke på det enkelte avsnittet selv. Bruk snarveien på avsnittet der den finnes; den er kortere.publiseringstager derimot et annet felt med et annet formål — brukt ved overføring til andre publiseringsløsninger, ikke CDM.innholdvs.originalinnhold.originalinnholder teksten slik den ble redigert — ren tekst eller HTML.innholdgenereres fraoriginalinnholdi et eget steg i FS, og FS sporer selv når denne genereringen gjenstår — de to kan derfor være midlertidig ute av synk rett etter en redigering.innholdligner mest på det CDM leverte og er det naturlige valget for de fleste. Erinnholdtomt mensoriginalinnholdhar data, ta kontakt med fs-support@sikt.no.- Vi anbefaler at
cdmTagkun brukes på én aktiv tekstkategori om gangen på samme studieprogram. Er sammecdmTagsatt på to ulike tekstkategorier samtidig, kan innholdet blandes eller vises inkonsekvent — dette er et institusjonelt Infotype-oppsett, ikke noe GraphQL-spørringen kan rette opp i.
Terminkoblingen er en eksakt match, ikke et gyldighetsvindu
Hvert avsnitt er registrert med en periode (fraTermin/tilTermin) det gjelder for. Men når du henter beskrivelsesavsnitt nøstet under publiseringsklareStudieprogram slik som over, får du kun avsnitt der periode.fraTermin er nøyaktig lik terminen du spør om — ikke avsnitt som ble skrevet for en tidligere termin og fortsatt er gyldige. En tekst med fraTermin: HØST 2020 og tilTermin åpen dukker altså ikke opp når du spør for HØST 2023, selv om den fortsatt gjelder.
Ser en tekst ut til å mangle sammenlignet med CDM? Sjekk dette først.
Trenger du «teksten som gjelder nå», slik CDM leverte den:
- Hent i stedet uten terminfilter via
Studieprogram.beskrivelsesavsnitt. Det er en paginert Connection (feltene ligger undernodes) som henter 100 avsnitt som standard — settfirsteksplisitt om du trenger flere. - Be om
periode { fraTermin { arstall betegnelse { kode } } tilTermin { arstall betegnelse { kode } } }. Begge feltene er stable på studieprogram. - Velg selv raden der perioden dekker terminen din — en åpen
tilTerminbetyr fortsatt gyldig. Tre feller her:- Årstall+terminbetegnelse sorterer ikke kronologisk som tekst.
betegnelse.kodeerVÅR/SOM/HØST— alfabetisk blir detHØST < SOM < VÅR, mens den faktiske rekkefølgen i et år erVÅR < SOM < HØST. Sammenlign påarstallførst. - Det finnes én rad per kombinasjon av tekstkategori, språk og fra-termin, ikke én rad per tekstkategori — grupper på
tekstkategori.kodeog språk (se under) før du velger blant fra-terminene i hver gruppe. gjelderForTerminer/gjelderFraTerminer-filteret på selvebeskrivelsesavsnitt-kallet snevrer bare inn på samme fra-termin-felt — det gir ingen containment/gyldighetsvindu, og er derfor ingen snarvei rundt punktene over.
- Årstall+terminbetegnelse sorterer ikke kronologisk som tekst.
Språk
Infotekster returneres én rad per språk, ikke samlet slik navnAlleSprak gjør — SPRAKKODE er del av primærnøkkelen på STUDIEPROGRAM_INFORMASJON. Samme cdmTag kan derfor dukke opp flere ganger i lista, én gang per språk. Vil du hente ett bestemt språk, filtrer eksplisitt (filterverdien slås opp mot en egen SPRAK-tabell, så en språkkode uten treff der gir stille tomt resultat for det avsnittet):
Verdien i filteret er ISO 639-2 (nob/nno/eng, ikke CDM sine egne BOKMÅL/NYNORSK/ENGELSK), mens returfeltet sprak { sprakkode } på selve avsnittet gir FS sin egen kode — ikke bruk den returnerte verdien direkte som filterverdi neste gang. Et iso6392Kode-felt finnes på den underliggende Sprak-typen (eid av en annen subgraf), som trolig kan gi deg verdien du kan filtrere på senere — ikke live-verifisert i denne guiden, siden det krever en full supergraph å teste. Filteret tar dessuten kun ett språk om gangen, ikke en liste — CDM sitt sprak=-parameter var det samme.
EVU-kurstekster har samme én-rad-per-språk-oppførsel, men ingen filtermulighet. EvuKurs.beskrivelsesavsnitt tar ikke noe filter-argument i det hele tatt — du må gruppere og velge språk selv i klienten, se EVU-kurs.
Sikts anbefalte standard-mapping mellom Infotype-koder og CDM-elementer for studieprogram (et utgangspunkt — institusjonen kan konfigurere dette annerledes, se advarselen over):
Full liste finnes i Sikts egen oversikt over infotypekoder. Institusjoner kan i tillegg definere egne Infotype-koder og selv velge hvilket CDM-element de skal kodes om til (cdmTag) — det finnes altså ikke én global, fast kodeliste.
Finner du ikke det du trenger?
Kontakt fs-support@sikt.no. Beskriv gjerne hvilket CDM-element eller hvilken institusjons- eller opptaksmetadata (f.eks. institusjonsnavn, adresse, semesteravgift eller SO-kode fra Samordna opptak, som CDM også eksporterer men som ikke er kartlagt i denne guiden ennå) du er avhengig av — da finner vi raskere ut om funksjonaliteten finnes under et annet navn, om den ligger på et lavere kontraktsnivå, eller om vi må bygge den.