Skip to main content

Astro와 MongoDB

Astro와 MongoDB 사용하기

who: Alex

astro_main_page.png

Astro Ecommerce 템플릿

Astro 소개에서 선정했던 템플릿과 Astro 공홈에 있는 프로젝트 구조를 통해 전체적인 구조와 사용법에 대해 살펴 봅시다. 하지만 그 전에 무료 템플릿 사용 시 보이는 warning, error들은 수정해 둔 뒤 시작!

Astro MongoDB 연결

간단한 웹 싸이트의 경우 사실 백엔드가 많이 필요하지도 않고 데이터베이스만 연결되면 참 좋을텐데 이런 생각하게 되는데 그렇다고 백엔드를 구성하고 따로 배포하고 하기가 참 불편하다.

위의 불편을 해소하기 위해 Astro를 이용해 프론트엔드, 백엔드 모두 구현하는 방법을 강구해 봤다.

데이터베이스는 평소 가장 만만하게 생각하는 MongoDB로 정했다!

Astro와 MongoDB 연결은 간단하다.

npm i mongodb @astrojs/node 를 입력하면 일단 설치는 끝났다.

배포 시 빌드 셋팅하기 좋도록 astro.config.min.mjs를 아래와 같이 살짝 수정해준다.

import { defineConfig } from "astro/config";
import node from "@astrojs/node";
// https://astro.build/config
import react from "@astrojs/react";

// https://astro.build/config
export default defineConfig({
output: "server",
integrations: [react()],
adapter: node({ mode: "standalone" }),
site: "<<YOUR WEB SITE>>",
base: "/",
});

그런 후 .env에 접속 정보를 저장하고 MongoDB를 연결해 버리면 끝! 🚀

import { MongoClient, MongoClientOptions } from "mongodb";

if (!import.meta.env.MONGODB_URI) {
throw new Error('Invalid environment variable: "MONGODB_URI"');
}

const uri = import.meta.env.MONGODB_URI;
const authSource = import.meta.env.AUTH_SOURCE;
const username = import.meta.env.USERNAME;
const password = import.meta.env.PASSWORD;
const authMechanism = import.meta.env.AUTH_MECHANISM;
const options: MongoClientOptions = {
authSource,
auth: {
username,
password,
},
authMechanism,
};

const connectToDB = async () => {
const mongo = await new MongoClient(uri, options).connect();
return mongo.db("test");
};

Astro에서 데이터베이스 활용

그럼 이제 어떤 collection을 활용할 거고 그 collection을 어떻게 활용할 것인지 정해야 하는데 어디 폴더에 설정해도 상관 없고 원하는 폴더(Pages 폴더 빼고)에 아래 코드를 저장한 후 getDB를 활용해 연결을 가져온 후에

export const getDB = async () => {
const mongo = await connectToDB();
return mongo;
};

아래와 같이 collection을 선택해 추가하거나 데이터를 불러오거나 하면 끝

export const Users = async () => {
const db = await getDB();
return db.collection("users");
};

export const getAllUsers = async () => {
const users = await (await Users()).find({}).toArray();
return users;
};

export const createUser = async (newUser: any) => {
const user = await (await Users()).insertOne(newUser);
return user;
};

그런 뒤 src 폴더 안에 api 폴더를 만들고 그 안에 위의 기능들을 담은 api들을 endpoint로 만들어 주면 api로 활용도 가능!

아래처럼 기능을 불러와서 사용도 가능하고

import { getAllUsers } from "../lib/users";

const users = await getAllUsers();
if (!users) {
return new Response(null, {
status: 404,
statusText: "Not found",
});
}

아래처럼 실제 endpoint로 fetch 해 데이터를 가져오면 간단! (fetch 사용도 간단)

async function onSubmit(e: any) {
const formData = new FormData(e.target);
const data: any = {};
for (let field of formData) {
const [key, value] = field;
data[key] = value;
}
try {
await fetch("/api/users", {
method: "POST",
body: JSON.stringify(data),
});
window.location.replace("/");
} catch (error) {
alert("Oops. We failed.");
}
}
document.getElementById("createUser")?.addEventListener("submit", onSubmit);

이렇게 데이터베이스에 연결해 데이터를 가져오거나 추가하거나 하는 작업이 손쉽게 마무리...;

아래와 같이 화면 구현도 아주 간단하게 가능합니다.

<form id="createUser">
<h3>CREATE USER</h3>
<span class="row mb-2"
>NAME: <input type="text" name="name" required /></span
>
<span class="row mb-2"
>EMAIL: <input type="email" name="email" required /></span
>
<span class="row mb-2"
>AGE: <input type="number" name="age" required /></span
>
<button type="submit" class="row mb-2">Submit</button>
</form>
<h3>Users</h3>
<ul>
{
users.map((user) => (
<li>
{user.name}, {user.age}
</li>
))
}
</ul>

결론

간단한 웹 페이지는 Nextjs에서와 같이 백엔드도 같이 붙여서 작업해 유지 관리 리소스를 줄이는 것도 좋은 방법