외부 API 호출
클라우드 함수에서 HTTP 요청 보내기
외부 API 호출
클라우드 함수에서 외부 API로 HTTP 요청을 보내는 방법을 소개합니다.
Fetch API를 사용하여 네트워크를 통해 리소스를 비동기적으로 가져올 수 있습니다.
GET 요청
JSON 데이터 가져오기
import type { FunctionContext } from '@imprun/sdk'
export default async function (ctx: FunctionContext) {
const res = await fetch('https://api.github.com/users/imprun')
const user = await res.json()
return {
login: user.login,
name: user.name,
followers: user.followers
}
}텍스트 데이터 가져오기
export default async function (ctx: FunctionContext) {
const res = await fetch('https://www.example.com')
const html = await res.text()
return {
length: html.length,
preview: html.substring(0, 100)
}
}바이너리 데이터 가져오기
export default async function (ctx: FunctionContext) {
// 이미지 다운로드
const imgUrl = 'https://imprun.dev/logo.png'
const res = await fetch(imgUrl)
const imageBuffer = Buffer.from(await res.arrayBuffer())
return {
size: imageBuffer.length,
contentType: res.headers.get('content-type')
}
}POST 요청
JSON 데이터 전송
export default async function (ctx: FunctionContext) {
const url = 'https://api.example.com/users'
const user = {
name: '홍길동',
email: 'hong@example.com'
}
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(user)
})
const result = await response.json()
return result
}Form 데이터 전송
export default async function (ctx: FunctionContext) {
const formData = new FormData()
formData.append('username', '홍길동')
formData.append('email', 'hong@example.com')
const response = await fetch('https://api.example.com/submit', {
method: 'POST',
body: formData
})
return await response.json()
}헤더 설정
인증 토큰이나 커스텀 헤더를 포함할 수 있습니다:
export default async function (ctx: FunctionContext) {
const token = 'your-api-token'
const response = await fetch('https://api.example.com/protected', {
headers: {
'Authorization': `Bearer ${token}`,
'X-Custom-Header': 'imprun',
'User-Agent': 'imprun-function/1.0'
}
})
return await response.json()
}에러 처리
HTTP 에러를 처리하는 방법:
export default async function (ctx: FunctionContext) {
try {
const response = await fetch('https://api.example.com/data')
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
const data = await response.json()
return { success: true, data }
} catch (error) {
console.error('API 호출 실패:', error)
return {
success: false,
error: error.message
}
}
}타임아웃 설정
요청 타임아웃을 설정할 수 있습니다:
export default async function (ctx: FunctionContext) {
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), 5000) // 5초 타임아웃
try {
const response = await fetch('https://api.example.com/slow', {
signal: controller.signal
})
clearTimeout(timeoutId)
return await response.json()
} catch (error) {
if (error.name === 'AbortError') {
return { error: '요청 타임아웃' }
}
throw error
}
}프록시 서버로 사용
외부 API를 프록시하는 함수:
export default async function (ctx: FunctionContext) {
const { url, ...options } = ctx.body
if (!url) {
ctx.response.status(400)
return { error: 'URL이 필요합니다' }
}
try {
const response = await fetch(url, {
method: options.method || 'GET',
headers: options.headers || {},
body: options.body ? JSON.stringify(options.body) : undefined
})
const data = await response.json()
return {
status: response.status,
headers: Object.fromEntries(response.headers.entries()),
data
}
} catch (error) {
ctx.response.status(500)
return {
error: '프록시 요청 실패',
message: error.message
}
}
}API 응답 캐싱
import cloud from '@imprun/sdk'
export default async function (ctx: FunctionContext) {
const cacheKey = 'github:user:imprun'
// 캐시 확인
let user = cloud.shared.get(cacheKey)
if (!user) {
console.log('캐시 미스 - API 호출')
const res = await fetch('https://api.github.com/users/imprun')
user = await res.json()
// 5분간 캐시
cloud.shared.set(cacheKey, user)
setTimeout(() => cloud.shared.delete(cacheKey), 5 * 60 * 1000)
} else {
console.log('캐시 히트')
}
return user
}여러 API 동시 호출
Promise.all을 사용하여 여러 API를 병렬로 호출할 수 있습니다:
export default async function (ctx: FunctionContext) {
try {
const [user, repos, events] = await Promise.all([
fetch('https://api.github.com/users/imprun').then(r => r.json()),
fetch('https://api.github.com/users/imprun/repos').then(r => r.json()),
fetch('https://api.github.com/users/imprun/events').then(r => r.json())
])
return {
user: {
name: user.name,
followers: user.followers
},
repoCount: repos.length,
eventCount: events.length
}
} catch (error) {
return { error: 'API 호출 실패', message: error.message }
}
}Rate Limiting 처리
API Rate Limit을 처리하는 패턴:
export default async function (ctx: FunctionContext) {
const response = await fetch('https://api.github.com/user', {
headers: {
'Authorization': `Bearer ${process.env.GITHUB_TOKEN}`
}
})
// Rate Limit 정보 확인
const rateLimit = {
limit: response.headers.get('x-ratelimit-limit'),
remaining: response.headers.get('x-ratelimit-remaining'),
reset: response.headers.get('x-ratelimit-reset')
}
if (response.status === 429) {
return {
error: 'Rate limit exceeded',
rateLimit,
retryAfter: response.headers.get('retry-after')
}
}
const data = await response.json()
return {
data,
rateLimit
}
}Webhook 호출
외부 Webhook을 호출하는 예제:
export default async function (ctx: FunctionContext) {
const webhookUrl = process.env.SLACK_WEBHOOK_URL
const message = {
text: '새로운 이벤트가 발생했습니다!',
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: `*이벤트:* ${ctx.body.event}\n*시각:* ${new Date().toISOString()}`
}
}
]
}
const response = await fetch(webhookUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(message)
})
return {
success: response.ok,
status: response.status
}
}Fetch API에 대한 더 자세한 내용은 MDN 문서를 참고하세요.