Spring til hovedindhold

Modulstruktur

Hvert API-modul følger en konsistent intern struktur med controllere, repositories, modeller og hjælpere. Forståelse af dette layout gør det enkelt at navigere i kodebasen og tilføje ny funktionalitet til ethvert modul.

Før du begynder

Mappestruktur

Hvert modul bor under src/modules/{name}/ og indeholder fire mappetyper:

src/modules/{name}/
├── controllers/ ← Route handlers (Express endpoints)
├── repositories/ ← Data access layer (direct SQL)
├── models/ ← TypeScript interfaces and types
└── helpers/ ← Module-specific business logic

For eksempel medlemskabsmodulet:

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

Controllere

Controllere definerer API-ruterne for et modul. De udvider CustomBaseController fra @churchapps/apihelper og bruger Inversify-dekoratører til rutregister.

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 = authenticated user context
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;
// ... save logic
});
}
}

Route Dekoratører

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

Dekoratøren @controller("/base") indstiller basestien for alle ruter i controlleren.

Repositories

Repositories håndterer alle databaseoperationer ved hjælp af direkte SQL via DB.query(). Der 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 or UPDATE logic
}
}

Få adgang til repositories gennem RepositoryManager:

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

Godkendelse og godkendelse

JWT-godkendelse

Alle anmodninger godkendes via JWT-tokens håndteret af CustomAuthProvider. Tokenet valideres automatisk, og den godkendte brugersammenhæng (au) er tilgængelig i hver controlleraction.

Tilladelseskontroller

Brug au.checkAccess() til at verificere, at den nuværende bruger har den påkrævede tilladelse:

au.checkAccess("People", "View");    // Read access
au.checkAccess("People", "Edit"); // Write access

Hvis brugeren mangler den påkrævede tilladelse, returneres en fejlsvar automatisk.

advarsel

Kald altid au.checkAccess() før du udfører dataoperationer. Spring aldrig tilladelseskontroller over, selv for tilsyneladende skrivebeskyttede endpoints.

Miljøkonfiguration

Klassen Environment håndterer konfiguration på tværs af miljøer:

  • Lokal udvikling: Læser fra .env-filen i projektrodet
  • Implementerede miljøer: Læser fra AWS SSM Parameter Store
// Access environment variables
const dbConnection = Environment.membershipDb;
const jwtSecret = Environment.jwtSecret;

Denne abstraktion betyder, at din kode ikke behøver at vide, hvor konfigurationen kommer fra.

Lambda-funktioner

Når der implementeres på AWS, køres API'en som fire Lambda-funktioner:

FunctionFormål
webHåndterer alle HTTP REST API-anmodninger
socketAdministrerer WebSocket-forbindelser til realtidsfunktioner
timer15MinPlanlagt hver 15. minut til e-mail-meddelelser
timerMidnightPlanlagt dagligt til e-mail-sammendrag og vedligeholdelse
info

Lokalt kører web-funktionen på port 8084 og socket-funktionen på port 8087. Timer-funktionerne kan udløses manuelt under udvikling.

Relaterede artikler

  • Database -- Forbindelsesstrenke, skemascripter og dataadgangsmønstre
  • Lokalt API Setup -- Komplet trin-for-trin opsætningsvejledning
  • ApiHelper -- Det delte bibliotek, der leverer CustomBaseController og auth middleware