Clone
6
Generella krav för samtliga APIer
Erik Thuning edited this page 2025-09-18 13:34:10 +02:00

Generella krav

Allmänt

All API-kommunikation sker i json. Klienten skickar Accept: application/json i samtliga requests och förväntar sig Content-Type: application/json i framgångsrika svar.

Versionshantering

Alla API:er skall versioneras med hjälp av URI:n. Den första versionen skall vara v1. Inga bakåtbrytande ändringar får göras i en version, istället skall en ny version skapas.

När en ny version skapas skall den gamla versionen finnas kvar under någon tidsperiod för att tillåta migrering. Alla endpoints ska finnas i alla versioner även om dom inte har ändrats.

Exempel på ändringar som tillåts inom en version

  • Lägga till nya fält i ett svar
  • Lägga till nya API:er
  • Lägga till nya feltyper

Autentisering

API:t skall använda sig av OAuth 2.0 med JSON Web Tokens (JWT) i JSON Web Signature (JWS) format för autentisering och avgöra behörigheter på principalen (sub) som identifieras av token och eventuella entitlements.

För mer information se https://oauth2.dsv.su.se/

Identifiering av personer

Personer ska i både förfrågningar och svar identifieras via fullt kvalificerad principal, t.ex foobar@su.se. Om flera identiteter existerar för samma person så ska i möjligaste mån en identitet i samma domän som den autentiserade användarens returneras. Den autentiserade användarens domän är den domän som står i förfrågningens JWT-token i fältet sub.

Användardefinerade strängar

När en användare skickar data i form av en sträng till ett API, t.ex namnet på en bokning, så ska helt arbiträr UTF-8 accepteras. Mottagaren ansvarar för att hantera indata på ett säkert sätt som inte äventyrar applikationens integritet via t.ex injection-attacker. När samma sträng returneras via en request faller ansvaret för sanering på mottagaren.

API:er får sätta tillåtna max-längder på strängar skickade från klienten per applicerbart fält. Sådana begränsningar ska dokumenteras. Detaljerna i hur längden på en sträng räknas (codepoints, bytes, etc) är oviktiga - det måste inte gå att skicka 50 emojis om teckengränsen är 50 tecken. Gränsen ska vara satt så att förväntade rimliga indata stöds.

Datum och tid

Alla datum, klockslag och tidsintervall ska uppfylla ISO8601.

  • Datum: YYYY-MM-DD

  • Tid: hh:mm:ss

  • Datum+tid: YYYY-MM-DDThh:mm:ss
    T används som separator mellan datum- och tidsdelen.

  • Tidsintervall: PnYnMnDTnHnMnS
    Det generella formatet är P för "Period", följt av antal år/månader/dagar, följt av T för "Time", följt av antal timmar/minuter/sekunder. Enheter som inte används förväntas utelämnas.

    Exempel:

    • P1DT3H: 1 dag, 3 timmar
    • PT2H: 2 timmar
    • P4Y: 4 år

Internationalisering

Om ett fält kan populeras med data på flera språk skall värdet baseras på HTTP headern Accept-Language och språket ska anges i svaret med hjälp av Content-Language. Om inget av språken i Accept-Language finns skall det först falla tillbaka på engelska och om även det saknas falla tillbaka på svenska.

Denna internationalisering måste även appliceras på felmeddelanden, t.ex title, detail, och eventuella extra attribut.

Exempel med språk som stöds

> GET /lokal
> Accept-Language: sv
< 200 OK
< Content-Language: sv
{
  "name": "Mötesrum"
}

Exempel med språk som inte stöds

> GET /lokal
> Accept-Language: de
< 200 OK
< Content-Language: en
{
  "name": "Meeting room"
}

Prestandakrav

99% av alla giltiga förfrågningar måste svaras på inom 100ms. Detta måste gälla hela tiden genom att mäta i ett kort rullande fönster, inte bara genomsnittligt över en längre period.

Felhantering

Fel anges i formatet specifierat i RFC 7807 (Problem details).

Specifikation

Felmeddelanden returneras som JSON-data med Content-type: application/problem+json.

Följande fält är obligatoriska:

  • type: string
    Felmeddelandets typ. Typen ska vara en av en dokumenterad uppsättning strängar på formatet applikation:feltyp. Formatet på feltyp-delen är upp till applikationen, men måste vara dokumenterat.

  • title: string
    En beskrivning av feltypen avsedd att presenteras för användaren. Värdet på det här fältet förväntas vara samma för alla fel av samma type. Värdet ska vara internationaliserat och meningsfullt för en användare.

  • detail: string
    En beskrivning av det här felets specifika omständighter avsedd att presenteras för användaren. Meddelandets fokus ska vara att hjälpa användaren förstå och åtgärda vad som gått fel (om möjligt - en användare kan inte på egen hand ge sig själv nya rättigheter t.ex).

  • instance: string
    Den lokala URL i applikationen som anropades av klienten då felet uppstod.

Extra fält

Alla feltyper en applikation dokumenterar får inkludera extra fält avsedda att underlätta för den mottagande applikationen att presentera felet för användaren. Sådana extra fält ska dokumenteras tillsammans med övrig information om feltypen.

T.ex skulle ett formulärfel kunna inkludera en lista på fält som inte klarade validering. Se nedan för ett exempel.

Exempel på fel

De här exemplen är inte avsedda att ses som specifikation på förväntade feltyper, utan bara illustrera hur fel förväntas formateras.

Ej behörig

< 403 Forbidden
< Content-Type: application/problem+json
< Content-Language: en
{
  "type": "daisy:forbidden",
  "title": "You can not perform this action",
  "detail": "You may not book a group room because you are not a student at SU",
  "instance": "/v1/bookings/group-rooms"
}

Misslyckad validering av indata

< 400 Bad request
< Content-Type: application/problem+json
< Content-Language: en
{
  "type": "daisy:bad-request",
  "title": "Bad request",
  "detail": "Request contents did not pass validation",
  "instance": "/v1/bookings/group-rooms",
  "violations": {
    "start_time": "Must be in format YYYY-MM-DDThh:mm:ss",
    "name": "Too long, max 100 characters"
  }
}

För lång bokning

< 400 Bad request
< Content-Type: application/problem+json
< Content-Language: sv
{
  "type": "daisy:duration-too-long",
  "title": "Bokningen överskrider maxlängden",
  "detail": "Du försökte boka 5 timmar, men maxlängden är 4 timmar",
  "instance": "/v1/bookings/group-rooms"
}

För få deltagare

< 400 Bad request
< Content-Type: application/problem+json
< Content-Language: en
{
  "type": "daisy:too-few-participants",
  "title": "Booking needs more participants",
  "detail": "You may only book with at least two participants, not by yourself",
  "instance": "/v1/bookings/group-rooms"
}