Turso를 알아보자
10/20/2024
Turso는 SQLite 기반의 서버리스 플랫폼으로, 기존 데이터베이스 시스템과는 다소 다른 독특한 특징을 가지고 있습니다.
그중 가장 눈에 띄는 특징은 사용자별로 데이터베이스를 생성할 수 있다는 점인데요, 새로운 사용자가 회원가입을 할 때마다 서버는 그 사용자만을 위한 전용 데이터베이스를 만들어 다른 사용자의 데이터와 격리시킬 수 있습니다. 이런 점은 SaaS 제품을 개발할 때 특히 유용할 것 같습니다.
그렇다면 이 특징을 실제로 코드에 어떻게 적용할 수 있을지 궁금하실 건데요, 간단한 예제를 통해 그 방법을 살펴보겠습니다.
Turso 감잡기
libsql://{databaseName}-{orgName}.turso.io
이 주소는 Turso로 생성한 사용자별 데이터베이스의 주소 형식입니다. 여기서 orgName
은 여러분의 Organization 이름이고, databaseName
은 여러분이 만들고자 하는 데이터베이스 이름입니다. 제 경우, 사용자별로 데이터베이스를 생성하고 싶어서 userId
값을 데이터베이스 이름으로 사용합니다.
따라서 사용자별로 서로 다른 데이터베이스에 쿼리를 요청하려면, 서버의 컨트롤러나 라우터 단에서 세션이나 토큰을 통해 userId
를 확인하고, 이를 바탕으로 해당 사용자의 데이터베이스에 쿼리를 보내는 방식으로 코드를 구성하면 됩니다.
그 전에 이 주소로 요청을 보내기 위한 userId
를 기반으로 한 데이터베이스를 어떻게 만들 수 있을까요?
import { createClient } from "@tursodatabase/api"
function createUserDatabase(userId) {
const turso = createClient({
org: process.env.TURSO_ORG_NAME,
token: process.env.TURSO_AUTH_TOKEN,
})
const database = await turso.databases.create(userId, { schema: process.env.TURSO_SCHEMA })
}
이런 방식으로 Turso SDK를 사용하여 코드 내에서 사용자별 데이터베이스를 생성할 수 있습니다. 이 코드를 회원가입 로직에 추가하면 돼요.
그렇지만 데이터베이스 이름에 userId
를 사용할 때 주의할 점이 있어요. 이름에는 소문자 알파벳, 숫자, 그리고 대시만 사용할 수 있다는 제약이 있어서 저는 nanoid라는 라이브러리를 사용해 이 조건에 맞는 userId
를 생성하고 있답니다.
import { customAlphabet } from "nanoid"
async function signUp() {
const userId = customAlphabet("0123456789abcdefghijklmnopqrstuvwxyz-", 8)()
// ...
await createUserDatabase(userId)
}
그럼 회원가입을 완료한 사용자가 서버에 요청을 보냈을 때의 전반적인 처리 과정을 어떻게 이루어질까요?
router.get("/todos", async (req) => {
// 세션으로부터 userId값을 획득
const userId = await validateSessionCookie(req)
const todos = await todoService().getTodos(userId)
return todos
})
async function todoService() {
return {
getTodos: (userId) => {
const libsql = createLibsqlClient({
url: `${userId}-${process.env.TURSO_ORG_NAME}.turso.io`,
token: process.env.TURSO_AUTH_TOKEN
})
const db = createDB(libsql)
return db.todo.findMany()
}
}
}
기존 데이터베이스 방식과 달리, 이 경우에는 사용자별 데이터베이스를 사용하기 때문에 findMany
실행 시 userId
로 필터링할 필요가 없어요. 단순히 모든 투두를 불러오면 해당 사용자의 데이터만 조회됩니다.
이어서
Turso에 관심이 생기셨다면 공식 문서를 확인해보세요. 부모 스키마, 마이그레이션, 그룹, 복제 등 이 글에서 다루지 못한 주제들과 부족한 부분들은 시간 날 때마다 이 글에 조금씩 추가해 나가도록 하겠습니다.