Hopp til hovedinnhold

Modulstruktur

Hver API-modul følger en konsistent intern struktur med kontrollere, repositories, modeller og hjelpere. Å forstå denne oppbyggingen gjør det enkelt å navigere i kodebasen og legge til ny funksjonalitet i enhver modul.

Før du begynner

Katalogoppsett

Hver modul ligger under src/modules/{navn}/ og inneholder fire kataloger:

src/modules/{navn}/
├── controllers/ ← Rutehåndterere (Express-endepunkter)
├── repositories/ ← Datatilgangslag (direkte SQL)
├── models/ ← TypeScript-grensesnitt og typer
└── helpers/ ← Modulspesifikk forretningslogikk

For eksempel membership-modulen:

src/modules/membership/
├── controllers/
│ ├── PersonController.ts
│ ├── GroupController.ts
│ └── ...
├── repositories/
│ ├── PersonRepository.ts
│ ├── GroupRepository.ts
│ └── ...
├── models/
│ ├── Person.ts
│ ├── Group.ts
│ └── ...
└── helpers/
└── ...

Kontrollere

Kontrollere definerer API-rutene for en modul. De utvider CustomBaseController fra @churchapps/apihelper og bruker Inversify-dekoratører for ruteregistrering.

import { controller, httpGet, httpPost } from "inversify-express-utils";
import { CustomBaseController } from "@churchapps/apihelper";

@controller("/people")
export class PersonController extends CustomBaseController {

@httpGet("/")
public async loadAll() {
return this.actionWrapper(async (au) => {
// au = autentisert brukerkontekst
au.checkAccess("People", "View");
const repos = RepositoryManager.getRepositories<MembershipRepositories>("membership");
return repos.person.loadByChurchId(au.churchId);
});
}

@httpPost("/")
public async save() {
return this.actionWrapper(async (au) => {
au.checkAccess("People", "Edit");
const data = this.request.body;
// ... lagringslogikk
});
}
}

Rutedekoratører

DekoratørHTTP-metode
@httpGet("/sti")GET
@httpPost("/sti")POST
@httpPut("/sti")PUT
@httpPatch("/sti")PATCH
@httpDelete("/sti")DELETE

@controller("/base")-dekoratøren setter basestien for alle ruter i kontrolleren.

Repositories

Repositories håndterer alle databaseoperasjoner ved hjelp av direkte SQL via DB.query(). Det er ingen ORM -- du skriver SQL direkte.

export class PersonRepository {
public async loadByChurchId(churchId: string) {
return DB.query("SELECT * FROM people WHERE churchId=?", [churchId]);
}

public async save(person: Person) {
// INSERT- eller UPDATE-logikk
}
}

Få tilgang til repositories gjennom RepositoryManager:

const repos = RepositoryManager.getRepositories<MembershipRepositories>("membership");
const people = await repos.person.loadByChurchId(churchId);

Autentisering og autorisasjon

JWT-autentisering

Alle forespørsler autentiseres via JWT-tokens håndtert av CustomAuthProvider. Tokenet valideres automatisk, og den autentiserte brukerkonteksten (au) er tilgjengelig i hver kontrollerhandling.

Tillatelseskontroller

Bruk au.checkAccess() for å verifisere at gjeldende bruker har den nødvendige tillatelsen:

au.checkAccess("People", "View");    // Lesetilgang
au.checkAccess("People", "Edit"); // Skrivetilgang

Hvis brukeren mangler den nødvendige tillatelsen, returneres en feilrespons automatisk.

Advarsel

Kall alltid au.checkAccess() før du utfører dataoperasjoner. Hopp aldri over tillatelseskontroller, selv for tilsynelatende skrivebeskyttede endepunkter.

Miljøkonfigurasjon

Environment-klassen håndterer konfigurasjon på tvers av miljøer:

  • Lokal utvikling: Leser fra .env-filen i prosjektets rotkatalog
  • Distribuerte miljøer: Leser fra AWS SSM Parameter Store
// Tilgang til miljøvariabler
const dbConnection = Environment.membershipDb;
const jwtSecret = Environment.jwtSecret;

Denne abstraksjonen betyr at koden din ikke trenger å vite hvor konfigurasjonen kommer fra.

Lambda-funksjoner

Når API-et distribueres til AWS, kjører det som fire Lambda-funksjoner:

FunksjonFormål
webHåndterer alle HTTP REST API-forespørsler
socketAdministrerer WebSocket-tilkoblinger for sanntidsfunksjoner
timer15MinPlanlagt hvert 15. minutt for e-postvarsler
timerMidnightPlanlagt daglig for oppsummeringse-poster og vedlikehold
Info

Lokalt kjører web-funksjonen på port 8084 og socket-funksjonen på port 8087. Timerfunksjonene kan utløses manuelt under utvikling.

Relaterte artikler

  • Database -- Tilkoblingsstrenger, skjemaskript og datatilgangsmønstre
  • Lokalt API-oppsett -- Fullstendig trinnvis oppsettsguide
  • ApiHelper -- Det delte biblioteket som tilbyr CustomBaseController og autentiseringsmellomvare