imprun Platform

함수 간 호출

클라우드 함수끼리 호출하기

함수 간 호출

함수에서 다른 함수를 호출하여 코드를 재사용하고 모듈화할 수 있습니다.

cloud.invoke() 사용

cloud.invoke()를 사용하여 다른 함수를 호출할 수 있습니다:

import cloud from '@imprun/sdk'
import type { FunctionContext } from '@imprun/sdk'

export default async function (ctx: FunctionContext) {
  // 다른 함수 호출
  const result = await cloud.invoke('send-email', {
    body: {
      to: 'user@example.com',
      subject: '환영합니다',
      content: '가입해 주셔서 감사합니다!'
    }
  })

  return {
    success: true,
    emailSent: result
  }
}

유틸리티 함수 만들기

공통 로직을 유틸리티 함수로 분리할 수 있습니다:

// functions/utils/index.ts
import { createHash, randomUUID } from 'crypto'

export function md5(data: any) {
  return createHash('md5').update(data).digest('hex')
}

export function sha256(data: any) {
  return createHash('sha256').update(data).digest('hex')
}

export function uuid() {
  return randomUUID()
}

export function formatDate(date: Date) {
  return date.toISOString().split('T')[0]
}

유틸리티 함수 사용

다른 함수에서 ./로 시작하는 상대 경로로 임포트할 수 있습니다:

// functions/create-user/index.ts
import { uuid, md5, formatDate } from '../utils'
import type { FunctionContext } from '@imprun/sdk'

export default async function (ctx: FunctionContext) {
  const { email, password } = ctx.body

  const user = {
    id: uuid(),
    email,
    passwordHash: md5(password),
    createdAt: formatDate(new Date())
  }

  console.log('새 사용자:', user)

  return {
    success: true,
    userId: user.id
  }
}

공유 상태 (Shared State)

cloud.shared를 사용하여 함수들 간에 데이터를 공유할 수 있습니다:

// functions/cache-set/index.ts
import cloud from '@imprun/sdk'
import type { FunctionContext } from '@imprun/sdk'

export default async function (ctx: FunctionContext) {
  const { key, value, ttl } = ctx.body

  // 데이터 저장
  cloud.shared.set(key, value)

  // TTL 설정 (선택사항)
  if (ttl) {
    setTimeout(() => {
      cloud.shared.delete(key)
    }, ttl * 1000)
  }

  return {
    success: true,
    size: cloud.shared.size
  }
}
// functions/cache-get/index.ts
import cloud from '@imprun/sdk'
import type { FunctionContext } from '@imprun/sdk'

export default async function (ctx: FunctionContext) {
  const { key } = ctx.query

  const value = cloud.shared.get(key)

  return {
    found: value !== undefined,
    value
  }
}

메모리 캐시 구현

재사용 가능한 캐시 모듈을 만들 수 있습니다:

// functions/memcache/index.ts
import cloud from '@imprun/sdk'

export function get(key: string) {
  return cloud.shared.get(key)
}

export function set(key: string, value: any, ttlSeconds?: number) {
  cloud.shared.set(key, value)

  if (ttlSeconds) {
    setTimeout(() => {
      cloud.shared.delete(key)
    }, ttlSeconds * 1000)
  }
}

export function has(key: string) {
  return cloud.shared.has(key)
}

export function keys() {
  return Array.from(cloud.shared.keys())
}

export function size() {
  return cloud.shared.size
}

export function remove(key: string) {
  return cloud.shared.delete(key)
}

export function clear() {
  cloud.shared.clear()
}

캐시 모듈 사용

// functions/get-user/index.ts
import * as cache from '../memcache'
import cloud from '@imprun/sdk'
import type { FunctionContext } from '@imprun/sdk'

export default async function (ctx: FunctionContext) {
  const { userId } = ctx.query
  const cacheKey = `user:${userId}`

  // 캐시 확인
  let user = cache.get(cacheKey)

  if (!user) {
    console.log('캐시 미스 - DB 조회')

    // DB에서 조회
    const db = cloud.database()
    user = await db.collection('users')
      .where({ _id: userId })
      .getOne()

    // 5분간 캐시
    if (user) {
      cache.set(cacheKey, user, 300)
    }
  } else {
    console.log('캐시 히트')
  }

  return user
}

인증 미들웨어 패턴

공통 인증 로직을 재사용할 수 있습니다:

// functions/auth-middleware/index.ts
import cloud from '@imprun/sdk'
import type { FunctionContext } from '@imprun/sdk'

export async function requireAuth(ctx: FunctionContext) {
  const token = ctx.headers['authorization']?.replace('Bearer ', '')

  if (!token) {
    throw new Error('인증 토큰이 필요합니다')
  }

  const payload = cloud.parseToken(token)

  if (!payload) {
    throw new Error('유효하지 않은 토큰입니다')
  }

  return payload
}
// functions/protected-api/index.ts
import { requireAuth } from '../auth-middleware'
import type { FunctionContext } from '@imprun/sdk'

export default async function (ctx: FunctionContext) {
  try {
    // 인증 확인
    const user = await requireAuth(ctx)

    // 비즈니스 로직
    return {
      message: `안녕하세요, ${user.username}님!`,
      data: {
        // 보호된 데이터
      }
    }
  } catch (error) {
    ctx.response.status(401)
    return {
      error: error.message
    }
  }
}

비즈니스 로직 분리

복잡한 로직을 별도 함수로 분리:

// functions/user-service/index.ts
import cloud from '@imprun/sdk'

export async function createUser(data: any) {
  const db = cloud.database()

  return await db.collection('users').add({
    ...data,
    createdAt: new Date()
  })
}

export async function getUserById(id: string) {
  const db = cloud.database()

  return await db.collection('users')
    .where({ _id: id })
    .getOne()
}

export async function updateUser(id: string, data: any) {
  const db = cloud.database()

  return await db.collection('users')
    .where({ _id: id })
    .update(data)
}

export async function deleteUser(id: string) {
  const db = cloud.database()

  return await db.collection('users')
    .where({ _id: id })
    .remove()
}
// functions/api-users/index.ts
import * as UserService from '../user-service'
import type { FunctionContext } from '@imprun/sdk'

export default async function (ctx: FunctionContext) {
  const { method } = ctx

  try {
    if (method === 'POST') {
      const result = await UserService.createUser(ctx.body)
      return { success: true, data: result }
    }

    if (method === 'GET') {
      const { id } = ctx.query
      const user = await UserService.getUserById(id)
      return { success: true, data: user }
    }

    if (method === 'PUT') {
      const { id } = ctx.query
      await UserService.updateUser(id, ctx.body)
      return { success: true }
    }

    if (method === 'DELETE') {
      const { id } = ctx.query
      await UserService.deleteUser(id)
      return { success: true }
    }

    ctx.response.status(405)
    return { error: 'Method Not Allowed' }

  } catch (error) {
    ctx.response.status(500)
    return { error: error.message }
  }
}

체인 함수 호출

여러 함수를 순차적으로 호출:

import cloud from '@imprun/sdk'
import type { FunctionContext } from '@imprun/sdk'

export default async function (ctx: FunctionContext) {
  const { email, name } = ctx.body

  // 1. 사용자 생성
  const userResult = await cloud.invoke('create-user', {
    body: { email, name }
  })

  // 2. 환영 이메일 발송
  await cloud.invoke('send-welcome-email', {
    body: {
      to: email,
      name
    }
  })

  // 3. 관리자에게 알림
  await cloud.invoke('notify-admin', {
    body: {
      event: 'new_user',
      userId: userResult.id
    }
  })

  return {
    success: true,
    userId: userResult.id
  }
}

함수 간 호출은 같은 애플리케이션 내에서만 가능합니다. 다른 애플리케이션의 함수는 HTTP API로 호출해야 합니다.

다음 단계