Supabase Architecture
학습 목표
•
유지보수 가능한 구조 설계
1. Layered Architecture
1.
Router: 요청을 수신하고 적절한 컨트롤러로 라우팅합니다.
2.
Controller: 사용자 입력을 처리하고 서비스 계층을 호출하여 비즈니스 로직을 실행합니다.
3.
Service: 비즈니스 로직을 구현합니다. 이 계층에서는 주로 애플리케이션의 핵심 기능이 구현됩니다.
4.
Repository: 데이터베이스와의 상호작용을 처리합니다. 데이터 저장소와 관련된 작업을 캡슐화합니다.
아키텍처에 정답은 없습니다. 현재 서비스의 규모, 앞으로의 확장 가능성을 고려하여 가장 적절한 아키텍처를 선정하거나 변형하여 사용하시면 됩니다.
이번 강의 내용은 매우 심플한 기능만 있기 때문에 위 구조로 작성하는것도 오버엔지니어링이라고 생각되지만 각 역할의 분리와 레이어의 필요성을 다루기 위해 위 구조로 구현하겠습니다.
2. 디렉토리 구조
3. 코드 구현
supabase/functions/api/repositories/shortPathRepository.ts
export class ShortPathRepository {
async insertShortPath(redirectURL: string): Promise<string> {
// TODO: v1_short_path 테이블에 데이터 적재
}
async getRedirectURLByShortPath(shortPath: string): Promise<string> {
// TODO: v1_short_path 테이블에서 shortPath에 매칭되는 redirectURL 반환
return "";
}
}
TypeScript
복사
•
Repository에서는 DB 수준에서 접근하여 데이터를 CRUD하는 로직 작성
supabase/functions/api/services/shortPathService.ts
import { ShortPathRepository } from "../repositories/shortPathRepository.ts";
export class ShortPathService {
private shortPathRepository: ShortPathRepository;
constructor() {
this.shortPathRepository = new ShortPathRepository();
}
async insertShortPath(redirectURL: string): Promise<string> {
// TODO: 비즈니스 수준에서 shortPath를 추가
}
async getRedirectURLByShortPath(shortPath: string): Promise<string> {
// TODO: 비즈니스 수준에서 redirectURL 탐색
return "";
}
}
TypeScript
복사
•
Service에서는 Repository를 소유하고 활용
•
비즈니스 수준에서의 로직 수행. 요청을 수행하기 위해 다양한 Repository를 활용하여 데이터 처리 가공.
supabase/functions/api/controllers/shortPathController.ts
import { ShortPathService } from "../services/shortPathService.ts";
import { Context } from "https://deno.land/x/hono/mod.ts";
export class ShortPathController {
private shortPathService: ShortPathService;
constructor() {
this.shortPathService = new ShortPathService();
}
async postShortPathV1(c: Context) {
// TODO: 사용자 입력 처리, 파라미터 유효성 검사
return c.json("postShortPathV1 호출됨");
}
async getRedirectURLByShortPathV1(c: Context) {
// TODO: 사용자 입력 처리, 파라미터 유효성 검사
return c.json("getRedirectURLByShortPathV1 호출됨");
}
}
TypeScript
복사
•
API Endpoint와 method와 1:1 매칭되는 역할
•
http method와 API버저닝 정보를 함수명에 포함하는 것은 선택이지만 추천
•
파라미터 정보를 분석하고 정보 유효성 체크를 진행하는 단계. ex) 필수 파라미터 체크
supabase/functions/api/routers/shortRouter.ts
import { ShortPathController } from "./../controllers/shortPathController.ts";
import { Hono } from "https://deno.land/x/hono@v4.3.11/hono.ts";
export const shortPathRouter = new Hono();
const shortPathController = new ShortPathController();
// /v1/shortPath 경로로 들어오는 POST 요청을 shortPathController의 postShortPathV1로 전달
shortPathRouter.post("/v1/shortPath", (c) =>
shortPathController.postShortPathV1(c)
);
// /v1/shortPath 경로로 들어오는 GET 요청을 shortPathController의 getRedirectURLByShortPathV1 전달
shortPathRouter.get("/v1/shortPath", (c) =>
shortPathController.getRedirectURLByShortPathV1(c)
);
TypeScript
복사
•
HTTP Request를 Controller를 전달하는 역할.
•
서비스 도메인별로 URL 하위 path를 적용하기 위한 역할
supabase/functions/api/index.ts
import { Hono } from "https://deno.land/x/hono/mod.ts";
import { shortPathRouter } from "./routers/shortPathRouter.ts";
// Hono 인스턴스를 생성하여 애플리케이션을 설정합니다.
const app = new Hono();
// 기본 경로를 "/api"로 설정하고, "/users" 경로에 대해 userRouter를 설정합니다.
app.basePath("/api").route("/shortPath", shortPathRouter);
// 애플리케이션을 시작하여 요청을 수신합니다.
Deno.serve(app.fetch);
TypeScript
복사
•
URL 하위 Path에 따라 적절한 Router로 분배하여 처리하도록 함. 이를 통해 로직, 역할 분리 수행.
•
Router가 추가되면 .route 함수가 체이닝형태로 붙게됨.
4. 중간 점검
3번 과정까지 완료 후 로컬 배포하여 코드가 정상 수행되는지 확인합니다.
브라우저에서는 GET요청이 수행되므로 getRedirectURLByShortPathV1 함수가 호출됨을 확인할 수 있습니다.
끝.