Cloud Functions를 TypeScript로 작성하여 Realtime Database의 모델 정의를 선호합니다.

Cloud Functions for Firebase 을 TypeScript 로 쓰고 있으면 Firebase Realtime Database 이나 Cloud Firestore 을 사용하고 있을 때 모델을 좋은 느낌으로 정의할 수 있습니다.

Cloud Function + TypeScript 환경 구축은 Cloud Functions를 TypeScript로 작성 - Qiita을 참조하십시오.

구체적으로 무슨 일



Realtime Database를 사용하고 있으며 클라이언트 측은 iOS의 경우에 작성합니다.

iOS



Firebase를 사용할 때 클라이언트 측에서 모델을 정의한다고 생각합니다.
예를 들어, 사용자 모델을 다음과 같이 정의했다고 가정합니다.
class User: Object {
    @objc dynamic var name: String?
    @objc dynamic var age: Int = 0
}

Realtime Database는 다음과 같이 저장됩니다.



* 여기에서는 Salada이라는 라이브러리를 사용하고 있습니다.
* 자세한 내용은 Firebase Model Framework Salada를 사용하여 User Model 만들기 - Qiita 등을 참조하십시오.

Cloud Functions



any 형



Cloud Functions에서 User 데이터를 검색할 때 이런 식으로 데이터를 검색하지만 user가 any 형식이 됩니다.
const user = await admin.database()
                        .ref('v1/user/-Kxd4TYd_MgjEYhmEO0p')
                        .once('value')
                        .then(snap => snap.val())

모델 정의하기



이러한 모델 정의를 작성합니다.
declare namespace firebase {
  interface User extends Salada {
    name?: string
    age: number
  }

  interface Salada {
    _createdAt: number
    _updatedAt: number
  }
}

export default firebase

그리고 user 데이터 취득시에 firebase.User 에 캐스트 해 줍니다.
const user = <firebase.User> await admin.database()
                                        .ref('v1/user/-Kxd4TYd_MgjEYhmEO0p')
                                        .once('value')
                                        .then(snap => snap.val())

이렇게 하면 user 형식으로 취급할 수 있으므로 name 이 optional 인 것을 나타낼 수 있습니다.
또, 보완이 효과가 되어 개발 효율도 올라갑니다.

any 형에 user.name를 쓰는 것도 가능하지만 user.nema

보다 편리하게 사용


const user = <firebase.User> await admin.database()
                                        .ref('v1/user/-Kxd4TYd_MgjEYhmEO0p')
                                        .once('value')
                                        .then(snap => snap.val())

이 쓰는 방법도 편리하고 좋지만, user 객체에 id 가 없는 것이 불만이었습니다.-Kxd4TYd_MgjEYhmEO0p 가 userID 입니다만, admin.database().ref 로 취득하면 id 자체의 정보는 없어져 버립니다.

user._id로 액세스 허용



Ref라는 Util 클래스를 만듭니다. 
하는 것은 간단하고, Referenceable 를 extends 하고 있는 Model 이면 취득한 데이터에 _id 프로퍼티을 붙이고 있을 뿐입니다.

ref.ts:
export class Ref {
  static async snapshot<T extends Referenceable>(path: RefPath, id: string): Promise<T> {
    const value: T = await admin.database().ref(`${path}/${id}`).once('value').then(snap => snap.val())
    value._id = id

    return value
  }
}

export enum RefPath {
  User = '/v1/user'
}

export interface Referenceable {
  _id: string
}

firebase.ts:
declare namespace firebase {
  interface User extends Salada, Referenceable {
    name?: string
    age: number
  }

  interface Salada {
    _createdAt: number
    _updatedAt: number
  }
}

이 Util 클래스를 사용하여 데이터를 검색하면 _id로 액세스할 수 있습니다.
const user = <firebase.User> await Ref.snapshot(RefPath.User, '-Kxd4TYd_MgjEYhmEO0p')
user._id // => -Kxd4TYd_MgjEYhmEO0p

Realtime Database의 path도 한 곳에서 정의할 수 있어요.

사실 Path는 T의 Type을보고 자동으로 설정하고 싶었지만 TypeScript의 Interface는 js로 설정하면 더 이상 존재하지 않습니다.

좋은 웹페이지 즐겨찾기