Switch to infinite scroll (Full book)

Define Callable functions

The code we run in Callable functions has access to the user's authentication status along with the request's data.

Callable functions support streaming responses: we describe the pattern in a dedicated section.

Overview and syntax

synopsis

onCall<ReqData, Promise<ResData>>(options, callback)
onCall<ReqData, Promise<ResData>>(callback)

the callback

The callback has access to the request object (CallableRequest), which exposes auth and data.

We define the callback async so it returns a promise. The connection is kept open until the promise settles.

;async (req) => {}
;async ({ auth, data }) => {}
  • auth is undefined when the request is unauthenticated. It has uid otherwise.
  • ReqData defines the data sent by clients.
  • ResData defines what the callback returns.
onCall<ReqData, Promise<ResData>>(async (req) => {
    req.auth // AuthData | undefined
    req.auth?.uid
    req.data // ReqData
    return { message: "" } // ResData
})

add options

The options object, of type CallableOptions, a subclass of GlobalOptions, sets the region, the secrets, and the number of instances and the concurrency for each instance:

const options: CallableOptions = {
    concurrency: 1,
    minInstances: 1,
    maxInstances: 1,
    region: "europe-west1",
}

An instance can handle several requests at once. By default, Firebase runs with no minimum and no maximum.

  • Since there are no minimum (minInstances defaults to 0), Firebase doesn't run any instance when the endpoint is inactive. When a request is received, it spins up an instance, which requires some time (cold start), and keeps it alive for a while.
  • To avoid cold starts, we can set minInstance to 1, which keeps the instance warm at all time but costs much more.
  • We can limit maxInstances to 1 if we prefer throttling traffic instead of scaling up.

concurrency sets how many requests a single instance processes in parallel. Since it can process multiple requests in parallel by default, We only set it to 1 if we want a clean instance for each request or, if we also limit maxInstances to 1, if we want to process one request at a time.

Streaming version

Streaming the response means to send small chunks of data with sendChunk().

The third type argument (StreamData) defines what kind of chunk we stream. We usually stream string chunks.

The request exposes acceptsStreaming, which we read to check if the client supports streaming. When it does, the callback has access to an extra response argument, on which we call sendChunk().

onCall<T, U, V>(options, callback) // streaming Callable
onCall<ReqData, Promise<ResData>, StreamData>(async (request, response) => {
    if (response.acceptsStreaming) {
        response?.sendChunk("abc") // StreamData
        response?.sendChunk("def")
    } else return { message: ".." } // fallback
})

Patterns

halt and send an error immediately

We throw an HttpsError with a specific error code which conforms to a predefined list. It defaults to internal error if omitted.

throw new HttpsError("unauthenticated", "unauthenticated")

logger

logger.debug("")
logger.info("")
logger.warn("")
logger.error("")

Callable v1 (deprecated)

define the function

functions.https.onCall(async (data, context) => {
    const auth = context.auth
    const message = data.message
    return { message: ".." }
})

the context object

The context object provides the authentication details, if any, such as the email, and the request metadata such as the IP address, or the raw HTTP request. It is of type CallableContext

check authentication

if (!context.auth) {
    throw functions.https.HttpsError("unauthenticated", "you must be authenticated")
}
earlymorning logo

Define Callable functions

The code we run in Callable functions has access to the user's authentication status along with the request's data.

Callable functions support streaming responses: we describe the pattern in a dedicated section.

Overview and syntax

synopsis

onCall<ReqData, Promise<ResData>>(options, callback)
onCall<ReqData, Promise<ResData>>(callback)

the callback

The callback has access to the request object (CallableRequest), which exposes auth and data.

We define the callback async so it returns a promise. The connection is kept open until the promise settles.

;async (req) => {}
;async ({ auth, data }) => {}
  • auth is undefined when the request is unauthenticated. It has uid otherwise.
  • ReqData defines the data sent by clients.
  • ResData defines what the callback returns.
onCall<ReqData, Promise<ResData>>(async (req) => {
    req.auth // AuthData | undefined
    req.auth?.uid
    req.data // ReqData
    return { message: "" } // ResData
})

add options

The options object, of type CallableOptions, a subclass of GlobalOptions, sets the region, the secrets, and the number of instances and the concurrency for each instance:

const options: CallableOptions = {
    concurrency: 1,
    minInstances: 1,
    maxInstances: 1,
    region: "europe-west1",
}

An instance can handle several requests at once. By default, Firebase runs with no minimum and no maximum.

  • Since there are no minimum (minInstances defaults to 0), Firebase doesn't run any instance when the endpoint is inactive. When a request is received, it spins up an instance, which requires some time (cold start), and keeps it alive for a while.
  • To avoid cold starts, we can set minInstance to 1, which keeps the instance warm at all time but costs much more.
  • We can limit maxInstances to 1 if we prefer throttling traffic instead of scaling up.

concurrency sets how many requests a single instance processes in parallel. Since it can process multiple requests in parallel by default, We only set it to 1 if we want a clean instance for each request or, if we also limit maxInstances to 1, if we want to process one request at a time.

Streaming version

Streaming the response means to send small chunks of data with sendChunk().

The third type argument (StreamData) defines what kind of chunk we stream. We usually stream string chunks.

The request exposes acceptsStreaming, which we read to check if the client supports streaming. When it does, the callback has access to an extra response argument, on which we call sendChunk().

onCall<T, U, V>(options, callback) // streaming Callable
onCall<ReqData, Promise<ResData>, StreamData>(async (request, response) => {
    if (response.acceptsStreaming) {
        response?.sendChunk("abc") // StreamData
        response?.sendChunk("def")
    } else return { message: ".." } // fallback
})

Patterns

halt and send an error immediately

We throw an HttpsError with a specific error code which conforms to a predefined list. It defaults to internal error if omitted.

throw new HttpsError("unauthenticated", "unauthenticated")

logger

logger.debug("")
logger.info("")
logger.warn("")
logger.error("")

Callable v1 (deprecated)

define the function

functions.https.onCall(async (data, context) => {
    const auth = context.auth
    const message = data.message
    return { message: ".." }
})

the context object

The context object provides the authentication details, if any, such as the email, and the request metadata such as the IP address, or the raw HTTP request. It is of type CallableContext

check authentication

if (!context.auth) {
    throw functions.https.HttpsError("unauthenticated", "you must be authenticated")
}