imprun Platform

외부 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 문서를 참고하세요.

다음 단계