Netlify Serverless Functions
Short book about the Netlify Functions
1. Quick Start π©βπ»
1. Install Netlify CLI
κΈ°λ³Έ κ°λ μ Vercel Serverless Functions λ₯Ό μ°Έκ³ νλλ‘ νκ³ λ°λ‘ ν¨μλ₯Ό λ§λ€μ΄λ³΄μ.
npm i -D netlify-cli
κ·Έλ¦¬κ³ TypeScript νκ²½μΌ κ²½μ° λ€μμ μΆκ°λ‘ μ€μΉνλ€(Get started with functions μ μ°Έκ³ ).
npm i @netlify/functions
Vercel μ΄ root κ²½λ‘μ api
λΌλ λλ ν 리λ₯Ό μμ±νκ³ νμ κ²½λ‘μ js
λλ ts
νμΌμ λ§λ€μλ―μ΄ Netlify μμ
root κ²½λ‘μ netlify/functions
λΌλ λλ ν 리λ₯Ό μμ±νκ³ νμ κ²½λ‘μ mjs
, mts
νμΌμ λ§λλ κ²μΌλ‘ μμνλ€
(μ΄ λΆλΆμ Module format μ μ€λͺ
λμ΄
μμΌλ μ°Έκ³ νλλ‘ νλ€).
μ΄λ νμΌλͺ μ κ·μΉμ΄ μ‘΄μ¬νλλ° λ€μκ³Ό κ°λ€.
- subdirectory κ° μμ κ²½μ°:
netlify/functions/hello.mts
- subdirectory κ° μμ κ²½μ°:
netlify/functions/hello/hello.mts
λλnetlify/functions/hello/index.mts
subdirectory κ° μμ κ²½μ° νμΌλͺ
μ λ°λμ subdirectory μ λμΌ
νκ±°λ index
λ‘ μμ±λμ΄μΌνλ€.
- package.json
{
"scripts": {
"netlify": "netlify dev"
}
}
Vercel κ³Ό λ¬λ¦¬ netlify.json
νμΌμ λ§λ€μ§ μμλ npm run netlify
λ₯Ό μ€ννλ©΄ μλμΌλ‘ 리μ‘νΈλ₯Ό λμμ€λ€.
Netlify μλ config.json
νμΌμ΄ μ‘΄μ¬νλ€.
- macOS: Library/Preferences/netlify/config.json
- Linux: .config/netlify/config.json
- Windows: AppData\Roaming\netlify\Config\config.json
μ μ μ₯λλ©° netlify init
λλ netlify login
λͺ
λ Ήμ΄λ₯Ό ν΅ν λ‘κ·ΈμΈ μ 보λ₯Ό μ μ₯νλ λ° μ¬μ©λλ€.
2. Create API Functions
Vercel κ³Ό λμΌνκ² /api/user
μ /api/user/uuid005435
λ₯Ό μνλ‘ λ§λ€μ΄λ³΄λλ‘ νμ. Netlify λ
Prefix λ‘ /api
κ° μλ /.netlify/functions
λ₯Ό μ¬μ©νλ©°, Vercel κ³Ό λ¬λ¦¬ μΉμ±κ³Ό λ€λ₯Έ ν¬νΈμμ μ€νλλ€λ
κ²μ μ μν΄μΌνλ€.
- /netlify/functions/user.mts
import { Context } from "@netlify/functions";
const ALLOWED_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
const RESPONSE_INIT = {
headers: {
"Content-Type": "application/json; charset=utf-8",
},
status: 200,
};
export default function handler(request: Request, context: Context) {
const method = ALLOWED_METHODS.find((method) => method === request.method);
if (method === undefined) return;
return user[method](request, context);
}
const user: Record<string, Function> = {
GET: getUser,
POST: postUser,
PUT: putUser,
PATCH: patchUser,
DELETE: deleteUser,
};
function getUser(request: Request, context: Context): Response {
return new Response(
JSON.stringify({ name: "Hogwarts", age: 32, favorite: ["Movie", "Music", "Book", "Beer"] }),
RESPONSE_INIT,
);
}
function postUser(request: Request, context: Context): Response {
return new Response(JSON.stringify({}), RESPONSE_INIT);
}
function putUser(request: Request, context: Context): Response {
return new Response(JSON.stringify({}), RESPONSE_INIT);
}
function patchUser(request: Request, context: Context): Response {
return new Response(JSON.stringify({}), RESPONSE_INIT);
}
function deleteUser(request: Request, context: Context): Response {
return new Response(JSON.stringify({}), RESPONSE_INIT);
}
npm run netlify
λͺ
λ Ήμ μ
λ ₯νλ©΄ μμ μμ±ν Netlify λͺ
λ Ήμ΄κ° μ€νλλ€.
3000λ² ν¬νΈμμ 리μ‘νΈκ° μ€νλκ³ , Netlify λ 8888λ² ν¬νΈμμ μ€νλμ΄ μλ‘ λ€λ₯Έ ν¬νΈμμ μλνλ κ²μ μ μ μλ€.
http://localhost:8888/.netlify/functions/user
μ μμ²μ 보λ΄λ©΄ κ²°κ³Όλ‘ Status Code 200 κ³Ό λ€μ JSON λ°μ΄ν°λ₯Ό
μ»μ μ μλ€.
{
"name": "Hogwarts",
"age": 32,
"favorite": [ "Movie", "Music", "Book", "Beer" ]
}
3. Dynamic Routes
Vercel κ³Ό λ§μ°¬κ°μ§λ‘ λμ λΌμ°ν
μ΄ κ°λ₯νλ€. νμ§λ§ Vercel μ΄ Next.js μ λ§μ°¬κ°μ§λ‘ λλ ν 리 ꡬ쑰μ [urlParam].ts
μ κ°μ
λ°©μμΌλ‘ νμΌμ μμ±ν΄ ꡬλΆνλ κ²κ³Ό λ¬λ¦¬ λλ ν 리 ꡬ쑰λ₯Ό μ¬μ©ν λμ λΌμ°ν
μ λΆκ°λ₯νλ€. λμ Netlify κ° μ 곡νλ Config
λ₯Ό μ€μ ν΄
λΌμ°ν
μ μν¬ μ μλ€.
import { Config, Context } from "@netlify/functions";
const ALLOWED_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
const RESPONSE_INIT = {
headers: {
"Content-Type": "application/json; charset=utf-8",
},
status: 200,
};
export default function handler(request: Request, context: Context) {
const method = ALLOWED_METHODS.find((method) => method === request.method);
if (method === undefined) return;
return index[method](request, context);
}
const index: Record<string, Function> = {
GET: getUser,
POST: postUser,
PUT: putUser,
PATCH: patchUser,
DELETE: deleteUser,
};
function getUser(request: Request, context: Context): Response {
return new Response(
JSON.stringify({ name: "Hogwarts", age: 32, favorite: ["Movie", "Music", "Book", "Beer"] }),
RESPONSE_INIT,
);
}
// ...
export const config: Config = {
path: ["/user"],
};
μ κ°μ΄ μ€μ νλ©΄ μ΄μ μμ² URL μ http://localhost:8888/.netlify/functions/user
κ° μλ
http://localhost:8888/user
κ° λλ€.
μ΄μ Config
λ₯Ό μ¬μ©ν΄ λμ λΌμ°ν
μ μμν΄λ³΄μ.
μμ κ°μ΄ λλ ν 리λ₯Ό ꡬλΆνμ§ μκ³ μμ±ν μ΄μ λ λ€μκ³Ό κ°λ€.
- functions νμ subdirectory κΉμ΄λ₯Ό 1κΉμ§λ§ μ°Ύλλ€.
- subdirectory κ° μ‘΄μ¬ν κ²½μ°, κ·Έ μμ μμΉν νμΌμ subdirectory μ λμΌνκ±°λ index μΈ νμΌλ§ μ°Ύλλ€.
λ°λΌμ λλ ν 리 ꡬ쑰λ₯Ό νμ©ν λΌμ°ν
λΏ μλλΌ νμΌ μ 리 μμ²΄κ° λΆκ°λ₯νκΈ° λλ¬Έμ μμ κ°μ΄ -
λλ _
λ₯Ό μ¬μ©ν΄ ꡬλΆνμλ€.
- /netlify/functions/user-id.mts
import { Config, Context } from "@netlify/functions";
const ALLOWED_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
const RESPONSE_INIT = {
headers: {
"Content-Type": "application/json; charset=utf-8",
},
status: 200,
};
export default function handler(request: Request, context: Context) {
const method = ALLOWED_METHODS.find((method) => method === request.method);
if (method === undefined) return;
return user[method](request, context);
}
const user: Record<string, Function> = {
GET: getUser,
POST: postUser,
PUT: putUser,
PATCH: patchUser,
DELETE: deleteUser,
};
function getUser(request: Request, context: Context): Response {
const { id } = context.params;
return new Response(JSON.stringify({ message: `${id} μ¬μ©μ μ 보μ λν μμ²` }), RESPONSE_INIT);
}
// ...
export const config: Config = {
path: ["/user/:id"],
};
μ΄μ API μμ²μ λ€μκ³Ό κ°μ΄ URL Parameters λ₯Ό ꡬλΆν μ μκ² λλ€.
- GET
/user/
μμ²μ λν μλ΅
{
"name": "Hogwarts",
"age": 32,
"favorite": [ "Movie", "Music", "Book", "Beer" ]
}
- GET
/api/user/uuid005435
μμ²μ λν μλ΅
{
"message": "uuid005435 μ¬μ©μ μ 보μ λν μμ²"
}
Reference
- λ°μμ , βνλ‘ νΈμλ μΉ κ°λ°μ λͺ¨λ κ² μ΄κ²©μ°¨ ν¨ν€μ§ Online.β fastcampus.co.kr. last modified unknown, Fast Campus.
- βConfiguring Projects with vercel.json.β Vercel. Feb. 21, 2023, accessed May. 04, 2024, Vercel - Project Configuration.