Hente data fra et eksternt API
Slik henter appen data fra et annet system og viser dem i skjemaet
Appen kan hente data fra et annet system og vise dem til brukeren, for eksempel en liste med dokumenter som hører til saken. Utvikleren skriver en klasse som henter dataene. I skjemaet viser du dem med uttrykket externalApi eller i en SimpleTable.
externalApi bare til å vise tekst. Backend i appen kjenner ikke funksjonen ennå og gir en feil når den møter den. Bruk den derfor ikke i hidden, required, validering, beregninger eller i prosessen. Vi har meldt feilen i Altinn/altinn-studio#21350.Slik virker det
- Utvikleren lager en klasse som henter dataene, og registrerer den i appen.
- Appen gjør dataene tilgjengelige for hver instans gjennom et eget endepunkt.
- Første gang et uttrykk med
externalApitrenger dataene, henter nettleseren dem fra endepunktet. Den henter da dataene fra alle de eksterne API-ene appen har, ikke bare det ene uttrykket bruker. EnSimpleTablehenter bare dataene den selv viser. - Nettleseren husker dataene en stund og bruker dem om igjen. Hvor lenge, kommer an på hvor dataene vises. Når nettleseren har glemt dem, eller brukeren laster inn siden på nytt, henter den dataene igjen.
Nettleseren henter ikke dataene på nytt når brukeren endrer noe i skjemaet. Dataene kan derfor ikke avhenge av det brukeren fyller ut.
Fordi uttrykket henter fra alle de eksterne API-ene, kaller appen alle API-ene hver gang nettleseren henter dataene til uttrykket, også de dataene skjemaet ikke viser. Det tar tid, og det kan koste penger for den som leverer API-et.
Lage en klient
Klienten er en klasse som implementerer grensesnittet IExternalApiClient. Den har to deler:
Ider navnet du bruker for å vise til klienten i skjemaet. Skriv navnet nøyaktig likt i skjemaet. UttrykketexternalApiskiller mellom store og små bokstaver, og et feil navn gir tom tekst uten feilmelding.GetExternalApiDatahenter dataene og returnerer dem som et objekt.
Eksempelet returnerer faste data, slik at du ser formen. I en ekte klient henter du dataene fra API-et, se Kalle et API med Maskinporten.
Appen lager alle klientene for å lese Id, også når ingen henter data. Hold derfor konstruktøren enkel, og la Id være en fast verdi.
App/logic/DokumentApiClient.csusing Altinn.App.Core.Features.ExternalApi;
using Altinn.App.Core.Models;
public class DokumentApiClient : IExternalApiClient
{
public string Id => "dokumenter";
public Task<object?> GetExternalApiData(
InstanceIdentifier instanceIdentifier,
Dictionary<string, string> queryParams
)
{
var data = new DokumentListe
{
Tittel = "Dokumenter i saken",
Dokumenter =
[
new Dokument { Navn = "Panteattest", Dato = "2026-10-01" },
new Dokument { Navn = "Registerutskrift", Dato = "2026-10-15" },
],
};
return Task.FromResult<object?>(data);
}
}
public class DokumentListe
{
public required string Tittel { get; set; }
public required List<Dokument> Dokumenter { get; set; }
}
public class Dokument
{
public required string Navn { get; set; }
public required string Dato { get; set; }
}
Appen sender dataene som JSON med små forbokstaver i navnene. Egenskapen Dokumenter heter derfor dokumenter i skjemaet. Det gjelder egenskaper i C#-klasser. Returnerer klienten JSON den har fått fra API-et, for eksempel som JsonElement, beholder navnene formen de har i API-et.
Registrere klienten
Registrer klienten i Program.cs:
App/Program.csusing Altinn.App.Core.Features.ExternalApi;
void RegisterCustomAppServices(
IServiceCollection services,
IConfiguration config,
IWebHostEnvironment env
)
{
services.AddTransient<IExternalApiClient, DokumentApiClient>();
}Har appen flere klienter, registrerer du hver av dem på samme måte. Gi dem ulike navn. Har to klienter samme navn, bruker appen den som er registrert først, uten å si fra.
Vise dataene i skjemaet
Med uttrykket externalApi
externalApi tar navnet på klienten og stien til verdien du vil vise. Stien bruker punktum mellom nivåene og hakeparenteser for plassen i en liste. Den første plassen er 0.
App/ui/{taskId}/layouts/{page}.json{
"id": "forsteDokument",
"type": "Text",
"textResourceBindings": {
"title": "forsteDokument.title"
},
"value": [
"externalApi",
"dokumenter",
"dokumenter[0].navn"
]
}
Med dataene fra eksempelet viser komponenten «Panteattest».
Funksjonen returnerer alltid tekst eller null:
- Tall og
trueblir tekst, for eksempel"42". - Lister og objekter gir
null. Du kan altså ikke telle elementene i en liste eller sjekke om listen er tom. 0,false, en tom tekst og en sti som ikke finnes, gir ogsånull.
I en tabell
SimpleTable kan vise en liste fra et eksternt API som en tabell. I externalApi på komponenten oppgir du navnet på klienten i id og stien til listen i path. Hver kolonne viser til et felt i hver rad med accessors.
SimpleTable er en betakomponent. Du må slå den på i appsettings.json før du kan bruke den:
App/appsettings.json{
"FeatureManagement": {
"SimpleTableEnabled": true
}
}
App/ui/{taskId}/layouts/{page}.json{
"id": "dokumenttabell",
"type": "SimpleTable",
"externalApi": {
"id": "dokumenter",
"path": "dokumenter"
},
"columns": [
{ "header": "dokumenttabell.navn", "accessors": ["navn"] },
{ "header": "dokumenttabell.dato", "accessors": ["dato"] }
]
}
Stien må peke på et objekt eller en liste med objekter. Peker den på noe annet, viser tabellen ingenting. En komponent kan ikke ha både externalApi og dataModelBindings. Se SimpleTable for alle egenskapene.
Kalle et API med Maskinporten
Krever API-et Maskinporten, gir du klienten en HTTP-klient som legger på et token. Appen bruker Maskinporten-klienten Altinn Studio har satt opp for den. Se Bruke Maskinporten i appkoden for hvordan HTTP-klienten får token, og Legge til Maskinporten-scopes for hvordan du gir appen scopene API-et krever.
App/Program.csusing Altinn.App.Core.Features.ExternalApi;
void RegisterCustomAppServices(
IServiceCollection services,
IConfiguration config,
IWebHostEnvironment env
)
{
services
.AddHttpClient<DokumentApiClient>(client => client.BaseAddress = new Uri("https://api.example.no/"))
.UseMaskinportenAuthorization("example:dokumenter.read");
services.AddTransient<IExternalApiClient>(sp => sp.GetRequiredService<DokumentApiClient>());
}Den siste linjen gjør at appen bruker den samme klienten, med HTTP-klienten og Maskinporten-tokenet, når den henter data fra det eksterne API-et.
App/logic/DokumentApiClient.csusing System.Net.Http.Json;
using Altinn.App.Core.Features.ExternalApi;
using Altinn.App.Core.Models;
public class DokumentApiClient(HttpClient httpClient) : IExternalApiClient
{
public string Id => "dokumenter";
public async Task<object?> GetExternalApiData(
InstanceIdentifier instanceIdentifier,
Dictionary<string, string> queryParams
)
{
return await httpClient.GetFromJsonAsync<DokumentListe>("dokumenter");
}
}
Når noe går galt
Brukeren ser ingen feilmelding når et eksternt API feiler:
- Uttrykket
externalApigir tom tekst. SimpleTableviser ingenting.- For
SimpleTableskriver nettleseren feilen i konsollen. For uttrykketexternalApiser du feilen bare som en mislykket forespørsel i nettverksfanen i utviklerverktøyene til nettleseren.
Gir klienten en HttpRequestException med statuskode, svarer endepunktet med den samme statuskoden. Avviser API-et tokenet, får nettleseren derfor statuskode 401 eller 403. Andre feil gir statuskode 500.
Endepunktet sender feilmeldingen fra unntaket videre til nettleseren. Ikke ta med personopplysninger eller andre sensitive opplysninger i feilmeldingene fra klienten.
Hente dataene fra endepunktet
Du kan også hente dataene direkte, for eksempel fra et annet system:
GET {org}/{app}/instances/{instanceOwnerPartyId}/{instanceGuid}/api/external/{externalApiId}
{externalApiId}er navnet på klienten, altså verdien iId.- Den som kaller endepunktet, må ha lesetilgang til instansen.
- Finnes det ingen klient med navnet, svarer endepunktet med statuskode 400.
- Spørreparametere i adressen sender appen videre til
GetExternalApiDataiqueryParams. Skjemaet sender aldri spørreparametere, så der erqueryParamsalltid tom.
Kommer du fra v8?
- Metoden heter nå
GetExternalApiData, utenAsync.studioctl app upgrade v9gir metoden det nye navnet. ConfigureMaskinportenClientfinnes ikke lenger. Se Kommer du fra v8? på siden om Maskinporten.- I
Textstår uttrykket ivaluepå komponenten. - Uttrykket
["equals", ["externalApi", id, "length"], 0]ihiddenfra v8-dokumentasjonen virker ikke. Funksjonen girnullfor lister og for0, og backend gir en feil fordi uttrykket står ihidden.
Spørsmål du kan stille utviklerne
- Hvilke systemer henter appen data fra, og hva skjer i skjemaet hvis et av dem er nede?
- Bruker vi
externalApinoe annet sted enn i tekst, for eksempel ihiddenellerrequired? - Kan dataene endre seg mens brukeren fyller ut skjemaet, og er det et problem at nettleseren ikke henter dem på nytt?
- Hvor mange eksterne API-er kaller appen, og koster hvert kall noe?
- Inneholder dataene personopplysninger, og hvem har tilgang til dem?