Terug naar blog 6 april 2024
OntwikkelingBackend

Wat is backend ontwikkeling?

Backend staat letterlijk voor ‘achterkant’. Dit is hetgene de gebruiker niet ziet maar waar het wel om draait.

Servers

In het vorige deel (frontend ontwikkeling) heb ik uitgelegd wat een frontend is. In dit deel gaan we naar de backend kijken, iets wat je niet ziet maar wat wel heel veel invloed heeft op hoe de applicatie werkt.

De backend draait net zoals de frontend ook op een server en is via een domain beschikbaar. Hierdoor kan de frontend data opsturen of ontvangen. Dit wordt opgeslagen in een database.

Wat valt er onder backend?

Een backend heeft best een aantal dingen onder zijn hoede. Om goed te kunnen begrijpen wat een backend is en wat er komt bij kijken als er een backend gebouwd moet worden, gaan we apart kijken naar elk onderdeel.

Een server

Je kan een server bekijken als een computer zonder beeldscherm die verbonden zit met het internet. Elke computer heeft een IP-adres, vergelijkbaar met het adres van een huis. Een simpele website die gemaakt is met HTML kan op een server worden gehost (bijvoorbeeld met Apache), waarna je deze kunt bekijken door naar het IP-adres te gaan in je browser.

Bij APi’s (volgend kopje) werkt dit iets anders. Omdat je API code niet kan hosten (browser begrijpt dat niet), ontvang de API een verzoek vanaf de browser. Aan de hand van de URL en eventuele parameters in het verzoek, bepaalt de API-server welke logica moet worden uitgevoerd. Dit kan bijvoorbeeld betekenen dat de server data ophaalt uit een database, berekeningen uitvoert of andere acties onderneemt.

Een API

Een API (Application Programming Interface) is een soort van verbinding tussen je data (database) en de frontend (wat je ziet). Als jij naar je profiel navigeert om je naam te wijzigen, gebeuren er een aantal dingen in de achtergrond.

  1. De web app stuurt een verzoek naar de API om je profiel gegevens te tonen.

  2. De API ontvangt dit verzoek en bevestigd of je gemachtigd bent deze data in te zien.

  3. Nadat de API heeft bevestigd dat je toegang hebt tot deze data, stuurt de API een verzoek naar de database om de data op te halen.

  4. De database ontvang dit verzoek en “zoekt” de juiste data op en stuurt deze terug naar de API.

  5. De API ontvang deze data en stuurt deze data op als antwoord op het verzoek van de web app.

  6. De web app ontvangt deze data en laat dit netjes in de frontend zien.

API verzoek vanaf de frontend API verzoek vanaf de frontend

Dit is nog een simpel verzoek van de frontend. Als er data opgeslagen moet worden in de database zorgt de API ervoor dat deze data valide is voor hetgene de gebruiker probeert te doen. Ook kan de API bijvoorbeeld een email of notificatie sturen als er data toegevoegd/gewijzigd wordt.

Er zijn verschillende soorten API’s die ik een eindje verder ga behandelen. Het enige wat verschilt is de manier hoe je interactie hebt met deze API’s en hoe je de data terug krijgt. Ook zijn er verschillende frameworks net zoals bij de frontend die zorgen voor structuur bij het maken van een API.

Een database

Je hebt het net al voorbij zien komen, maar een database is een georganiseerd systeem voor het opslaan en beheren van gegevens die de applicatie maakt zoals het is. Het biedt een gestructureerde manier om informatie op te slaan, te ordenen en op te vragen. Bijna alles wat digitaal interactie heeft, heeft een database.

De gegevens in een database zijn onderverdeeld in tabellen, die rijen en kolommen bevatten. Elke rij representeert een afzonderlijk record, zoals een klantgegevens of een productinformatie. De kolommen bevatten de verschillende velden of attributen van die records, zoals naam, adres, prijs, etc.

Een database wordt aangestuurd door software. Dit wordt meestal een database management systeem (DBMS) genoemd. Deze software zorgt ervoor dat je gegevens kan opslaan, wijzigen, verwijderen, en efficient kan opvragen. Bekende DBMS-systemen zijn MySQL (gebruikt door WordPress), PostgreSQL, SQLite (kleiner), Oracle Database, en Microsoft SQL Server.

Authenticatie en authorizatie

Je wilt niet dat iedereen zo je database kan uitlezen of kan wijzigen. Als jij vanaf de frontend een verzoek naar de API maakt, moet je bewijzen dat jij toegang hebt tot die gegevens.

Authenticatie is het proces waarbij een gebruiker zijn identiteit bewijst aan het systeem. Dit kan op verschillende manieren gebeuren, zoals het invoeren van een gebruikersnaam en wachtwoord, het gebruik van een token of zelfs biometrische gegevens zoals vingerafdrukken of gezichtsherkenning.

Zodra de gebruiker is geverifieerd, wordt er meestal een uniek token aangemaakt die opgeslagen wordt in een database en naar de frontend wordt gestuurd. Dit token heeft een geldigheidsduur van bijvoorbeeld 15 minuten. Na deze 15 minuten moet dit token worden ververst met een nieuw token. Als jij als gebruiker een verzoek naar de API maakt stuur je dit token mee. Dit gebeurt meestal doormiddel van een cookie. De API ziet dit en verifieert dit doormiddel van een verzoek naar de cache/database (meestal een Redis database). Als dit token niet bekend is, betekent dit dat je geen toegang hebt.

Autorisatie gaat een stap verder en bepaalt welke acties een gebruiker mag uitvoeren en welke gegevens hij mag opvragen of wijzigen. Dit wordt vaak geregeld aan de hand van rollen en rechten die aan gebruikers worden toegekend. Sommige gebruikers hebben bijvoorbeeld alleen leesrechten, terwijl anderen ook schrijfrechten hebben.

Zo een rol kan bijvoorbeeld beheerder of werknemer zijn. Deze hebben beide andere rechten. Als beheerder kan je alles doen, maar als werknemer kan je bijvoorbeeld niet iedere gebruiker wijzigen. Nadat de API het token heeft geverifieerd, gaat die nu na in zijn logica of de gebruiker met X rol, deze logica kan uitvoeren (bijvoorbeeld gegevens wijzigen van een andere gebruiker). Als deze rol niet deze bevoegdheid heeft, stuurt de API een foutmelding terug. Als de gebruiker dit wel mag doen, zal de logica verder uitgevoerd worden.

Externe koppelingen

Soms wil je een koppeling met een ander systeem. Dit kan bijvoorbeeld nodig zijn om gegevens uit te wisselen of om functionaliteit van een ander systeem te gebruiken in jouw web applicatie. De backend is dan een soort schakel tussen jouw applicatie/database en de externe systemen. Er kunnen koppelingen worden gemaakt met elk systeem dat een API heeft en dat toestaat.

Om jezelf the authorizeren en authenticeren heb je een API-token nodig. Met dit token kan de backend met andere APIs praten. Stel, je wilt facturen direct vanuit je eigen web applicatie versturen, maar je wilt wel je eigen boekhoudsysteem blijven gebruiken. Zodra jij op een knop klikt met versturen, maakt de API een verzoek naar het externe systeem met de juiste parameters. Als dit verzoek faalt, zal dit worden weergeven in de frontend. Als het lukt, zul je dit ook zien en zal er een aantal externe gegevens in de database van je web applicatie worden opgeslagen zodat we de juiste verbindingen kunnen maken.

Soms wil je alleen maar data “kopieren” vanuit een andere applicatie die jij dan weer makkelijk kan bewerken in je eigen applicatie zonder dat de data in de andere applicatie veranderd. Dit wordt synchroniseren genoemt. Om een bepaalt tijdstip vraagt de backend bepaalde gegevens van de andere applicatie en slaat deze op (of wijzigt dit) in onze eigen database. Andersom kan het ook, onze backend stuurt gegevens op naar een andere applicatie die die dan opslaat/wijzigt.

Verschillende soorten API’s

Een API is niet perse het belangrijkste maar is wel een soort van het “aanspreekpunt” van de backend. Dit is ook waar alle logica gebeurt die je applicatie nodig heeft en kan eigenlijk wel gezien worden als de hersenen terwijl de frontend het lichaam voorstelt.

Er is niet 1 manier om een API te bouwen. Er zijn verschillende frameworks die het makkelijker maken (net zoals bij de frontend) om een API te bouwen maar waar wij nu naar gaan kijken zijn de verschillende API’s types.

Voordat we verder gaan, moeten we eerst bekend worden met functies. Functies zijn eigenlijk kleine stukjes code die een specifieke taak uitvoeren. Dit is waar de logica wordt uitgevoerd. Elke API bestaat uit talloze functies die allemaal een taak hebben. Deze functies worden dan aangeroepen vanuit de frontend, Bij elke API type worden deze anders aangeroepen.

REST API

REST API’s zijn een van de meest voorkomende en populaire API-type. REST staat voor Representational State Transfer en is een stijl voor het ontwerpen van API’s. REST API’s maken gebruik van HTTP-protocollen zoals GET, POST, PATCH, PUT en DELETE om data te verzenden en op te halen.

REST API’s is de meest gebruikte architectuurstijl, omdat het op dezelfde manier werkt als een website. In de browser kan je naar een url gaan, bijvoorbeeld domain.com/profiel. Met REST API’s werkt dit hetzelfde. Als jij naar een url gaat zoals api.domain.com/v1/user/medan krijg jij data terug (moet je wel de juiste authenticatie opgeven). Een voorbeeld van dit data is bijvoorbeeld:


{
	"id": "c5735f09-4faa-404c-8732-6d623bba9f54",
	"email": "[email protected]"
	"name": "John Doe",
	"age": 34,
	"is_verified": true
}
 

Achter elke URL zit een functie die een specifieke taak uitvoert, zoals het ophalen van data uit de database. Straks ga je zien dat dat bij andere API-types deze op andere manieren worden aangeroepen. Dat deze functies gewoon via een URL kunnen worden aangeroepen, versimpelt heel veel.. De frontend kan hier ook heel makkelijk mee omgaan en heeft geen andere “tools” nodig om een verzoek aan de API te doen.

In API’s wordt er vaak gebruik gemaakt van filters. Soms wil je filteren op leeftijd (ouder dan x) of op prijs. Bij REST API’s gebeurt dit via zogeheten query parameters. Deze worden toegevoegd aan de url na een vraagteken, bijvoorbeeld: api.domain/v1/users?age=30. Hier wordt dus gefiltered op alle gebruikers die 30 jaar zijn. Ook dit is weer eenvoudig en heeft geen andere “tools” nodig.

GraphQL

GraphQL is een andere populaire API-architectuur die veel anders is dan van REST API’s. GraphQL is meer een soort van query-taal voor API’s. In plaats van meerdere endpoints heeft GraphQL er slechts één. Daarnaast kan je precies aangeven welke velden je nodig hebt.

Om hetzelfde voorbeeld te pakken van de REST API, in plaats van een verzoek aan api.domain.com/v1/user/me, is het een POST (versturen) verzoek aan api.domain.com/v1/graphql met de volgende data:

query {
  user {
    id
    email
    name
    age
    isVerified
  } 

Hiermee krijg je precies dezelfde data terug als bij de REST API. Het verschil zit hem in hoe het verwerkt wordt. Bij REST API’s kan je vooraf niet bepalen welke velden je wilt (tenzij met query parameters), terwijl bij GraphQL API’s je hier wel controle over hebt.

Al deze queries moeten vooraf in een schema worden aangegeven. Hierdoor snapt GraphQL wat voor methodes er beschikbaar zijn in je frontend. Type safety noemen we dit. Dat betekent dat je altijd zeker bent dat een veld bestaat anders krijg je een error tijdens het programmeren dat dat veld niet bestaat.

Filteren wordt ook gelijk in deze schema’s aangegeven met types. Als je niet technisch bent is dit misschien een stapje te ver, maar hieronder een voorbeeld van hoe zo een schema er uit ziet:

type UsersFilter = {
  age: Int!
}

type Query {
  user(id: ID!): User
  users(filter: UsersFilter): [User]! 
} 

Omdat je altijd dezelfde URL aanroept, moet de API-server weten welke functie er moet worden uitgevoerd. Dit wordt gedaan met speciale frameworks die de schema’s snappen en dan de juiste functie aanroepen en de juiste data terugsturen. Een ander groot voordeel van GraphQL is dat je niet gelimiteerd bent tot het aanroepen van 1 functie zoals je wel bent bij REST API’s. Je kan namelijk zoveel queries opsturen die je wilt en die worden dan allemaal uitgevoerd.

tRPC

Typescript Remote Procedure Call is een ander type of API. Dit is een methode om API’s te maken in typescript waardoor de frontend en backend volledig type-safe zijn. Waar HTTP een algemeen protocol is voor het uitwisselen van informatie op het web, is RPC gericht op het uitvoeren van code op afstand.

tRPC lijkt op GraphQL. In plaats van expliciet endpoints (URLs) te definiëren, kan je gewoon je functies maken. In GraphQL moet je nog schema’s definiëren waarin je alles “beschrijft”, maar met tRPC hoeft dit niet. Je kan de functies gelijk aanroepen vanuit de frontend.

Bijvoorbeeld, met tRPC kan je een functie maken zoals:

const appRouter = trpc.router().query('getUser', {
  input: z.object({
    id: z.string(),
  }),
  resolve: ({ input }) => {
    return {
      id: input.id,
      name: 'John Doe',
      email: '[email protected]',
    };
  },
}); 

En deze functie kan je dan vanuit de frontend gelijk aanroepen:

const { data } = await trpc.useQuery(['getUser', { id: '123' }]);
console.log(data); // { id: '123', name: 'John Doe', email: '[email protected]' } 

Als je later iets aan de getUser functie verandert, dan weet de frontend meteen dat de data niet meer overeenkomt. Dan krijg je gelijk een foutmelding. Dat is handig, want dan weet je meteen wat er mis is.

WebSockets

WebSockets is een ander type API dat wordt gebruikt voor real-time communicatie tussen de frontend en backend. In plaats van dat de frontend steeds nieuwe verzoeken moet sturen naar de backend, zoals bij REST API’s, kan de backend zelf berichten sturen naar de frontend wanneer er iets verandert.

Een goed voorbeeld hiervan is een chat applicatie. Wanneer iemand een bericht stuurt, wil je dat dit direct zichtbaar is voor alle andere gebruikers in de chat. Met WebSockets kan de backend direct data sturen naar alle aangesloten gebruikers zodra er een nieuw bericht is. Dit is veel efficiënter dan dat elke gebruiker steeds opnieuw moet vragen of er nieuwe berichten zijn.

WebSockets werken door een permanente verbinding op te zetten tussen de frontend en backend. Zolang deze verbinding actief is, kunnen er berichten heen en weer worden gestuurd. Dit maakt WebSockets erg geschikt voor toepassingen waar real-time interactie belangrijk is, zoals chat apps, online games of realtime dashboards.

Overige API-types

Naast REST, GraphQL en WebSockets zijn er nog andere API-architecturen, zoals SOAP en JSON-RPC. Deze worden echter minder vaak gebruikt dan de eerder genoemde types. Elk type heeft zijn eigen voor- en nadelen, afhankelijk van de specifieke eisen van de applicatie.

Nawoord

Hiermee is nog niet alles gezegd maar ik wil het niet te lang maken. Als je niet technisch bent is dit waarschijnlijk al ingewikkeld. Als er vragen zijn over iets of als je verduidelijking, ik sta altijd klaar om je te helpen.

Volgende keer gaan we het eindelijk hebben over AI (kunstmatige intelligentie) en wat je er allemaal mee kan doen. Tot de volgende!

Klaar om te beginnen?