Why Do You Need This? What Is The Problem FireCall Trying To Solve?

Read Here

Related Projects

  1. FirelordJS - Typescript wrapper for Firestore Web V9
  2. Firelord - Typescript wrapper for Firestore Admin
  3. Firelordrn - Typescript wrapper for Firestore React Native
  4. FireLaw - Write Firestore security rule with Typescript, utilizing Firelord type engine.

Installation

npm i firecaller firebase zod

and of course you need typescript.

Create Schema With Zod

Normally this file is created on backend and share to frontend.

Tips: You can also use these schemas to validate your form, learn more at zod!

import { z } from 'zod'

export const updateUserSchema = {
    //request data schema
    req: z.object({
        name: z.string(),
        age: z.number(),
        address: z.string(),
    }),
    // response data schema
    res: z.undefined(),
    // function name
    name: 'updateUser',
}

export const getUserSchema = {
    res: z.string(), // userId
    res: z.object({
        name: z.string(),
        age: z.number(),
    }),
    name: 'getUser',
}

Create the Callable Functions

import { initializeApp } from 'firebase/app'
import { callable } from 'firecaller'
import { updateUserSchema, getUserSchema } from './someFile'

export const app = initializeApp(yourConfig) // must initialize app before using firecaller

const funRef = getFunctions(app)

// now create the specific callable
export const updateUser = callable(updateUserSchema) // or callable(updateUserSchema, funRef)
export const getUser = callable(getUserSchema) // or callable(getUserSchema, funRef)

Calling

FireCaller never throw, all errors are caught and returned as object. We choose this pattern because it is impossible to type-safe rejected promise.

By checking the value of the code, you know how to deal with them:

code meaning
ok success, you can access the data value
schema-out-of-sync Incorrect response data shape, your schema is out of sync, you can access the message
'functions/cancelled', 'functions/unknown', 'functions/invalid-argument', 'functions/deadline-exceeded', 'functions/not-found', 'functions/already-exists', 'functions/permission-denied', 'functions/resource-exhausted', 'functions/failed-precondition', 'functions/aborted', 'functions/out-of-range', 'functions/unimplemented', 'functions/internal', 'functions/unavailable', 'functions/data-loss', 'functions/unauthenticated' the error source is FireCall in NodeJS, you can access the message.
import { updateUser, getUser } from './someOtherFile'

const { name, age, address } = someFormData()

updateUser(
    // input type depends on schema.req
    { name, age, address } // { name: string, age: number, address: string }
).then(res => {
    const { code } = res
    if (code === 'ok') {
        const data = res.data // data type depends on what you define in schema.res
    } else {
        const { code, message } = res
        // message is string
    }
})

Usage With Emulator

import { initializeApp } from 'firebase/app'
import { getFunctions, connectFunctionsEmulator } from 'firebase/functions'
import { callable } from 'firecaller'
import { z } from 'zod'

const app = initializeApp({ projectId: `### YOUR_PROJECT_ID` })
const functions = getFunctions(app)

connectFunctionsEmulator(functions, 'localhost', f.emulators.functions.port)

const schema = {
    req: z.string(),
    res: z.string(),
    name: 'hello',
}

const helloCallable = callable(schema, functions)

describe('test callable', () => {
    it('success', async () => {
        const result = await helloCallable('hello')

        expect(result.code).toBe('ok')
        // @ts-expect-error
        expect(result.data).toEqual('how are you?')
    })

    it('invalid arguments', async () => {
        // @ts-expect-error
        const result = await helloCallable(123) // wrong input type

        expect(result.code).toBe('functions/invalid-argument')
        // @ts-expect-error
        expect(result.message).toEqual('invalid-argument')
    })
})