144

Going through the docs, I encountered:

...you can call functions directly with an HTTP request or a call from the client.

~ source

there (link in the quote) is a mention about functions.https.onCall.

But in the tutorial here, another function functions.https.onRequest is used, so which one should I use and why? What is the difference/similarity between them?

Documentation for functions.https is here.

benomatis
  • 5,536
  • 7
  • 36
  • 59
Qwerty
  • 29,062
  • 22
  • 108
  • 136
  • 1
    Possible duplicate of [Is the new Firebase Cloud Functions https.onCall trigger better?](https://stackoverflow.com/questions/49475667/is-the-new-firebase-cloud-functions-https-oncall-trigger-better) – Doug Stevenson Jun 27 '18 at 16:16
  • Thank you @DougStevenson, but I have read that question prior to asking this one and it did not help me understand the topic better. – Qwerty Jun 27 '18 at 17:41
  • I don't think there's anything else to understand. What is your specific confusion? – Doug Stevenson Jun 27 '18 at 17:47
  • I'll add that making a decision about which one to use is entirely dependent on your actual task at hand, and personal preference. One is not strictly better than the other. They serve different purposes. Choose the one that suits the situation. – Doug Stevenson Jun 27 '18 at 18:17
  • 2
    @DougStevenson For one, there seems to be a difference in how those functions can be invoked. One via url, other using an in-app call. – Qwerty Jun 27 '18 at 18:22
  • Yes, they are also different in that respect. – Doug Stevenson Jun 27 '18 at 18:29
  • 2
    @DougStevenson Can you check my answer for possible mistakes please? Thanks! – Qwerty Jul 23 '18 at 11:39

2 Answers2

201

The official documentation for those is really helpful, but from the view of an amateur, the described differences were confusing at first.

  • Both types, when deployed, are assigned with a unique HTTPS endpoint URL and can be accessed directly using an https client.

  • However, there is one important difference in the way how they are supposed to be called.

    • onCall: from the client's firebase.functions()
    • onRequest: via standard https client (e.g. fetch() API in JS)

onCall

  • Can be invoked (and this is also the main purpose) directly from the client app.

     functions.httpsCallable('getUser')({uid})
       .then(r => console.log(r.data.email))
    
  • It is implemented with user-provided data and automagic context.

     export const getUser = functions.https.onCall((data, context) => {
       if (!context.auth) return {status: 'error', code: 401, message: 'Not signed in'}
       return new Promise((resolve, reject) => {
         // find a user by data.uid and return the result
         resolve(user)
       })
     })
    
  • The context automagically contains metadata about the request such as uid and token.

  • Input data and response objects are automatically (de)serialized.

onRequest

  • Firebase onRequest Docs

  • Serves mostly as an Express API endpoint.

  • It is implemented with express Request and Response objects.

     export const getUser = functions.https.onRequest((req, res) => {
       // verify user from req.headers.authorization etc.
       res.status(401).send('Authentication required.')
       // if authorized
       res.setHeader('Content-Type', 'application/json')
       res.send(JSON.stringify(user))
     })
    
  • Depends on user-provided authorization headers.

  • You are responsible for input and response data.

Read more here Is the new Firebase Cloud Functions https.onCall trigger better?

Qwerty
  • 29,062
  • 22
  • 108
  • 136
  • 2
    How can you call an onRequest function? Or onCall functions are the only ones that can be called from the client? – tapizquent Jan 20 '21 at 19:50
  • 1
    @JoseTapizquent You can call it using `fetch()`, it's just an API endpoint. – Qwerty Jan 21 '21 at 11:45
  • 2
    onRequest creates a standard API endpoint, and you'll use whatever methods your client-side code normally uses to make. HTTP requests to interact with them. onCall creates a callable. Once you get used to them, onCall is less effort to write, but you don't have all the flexibility you might be used to. – redcartel Jan 26 '21 at 13:57
  • Is it possible to call a function which is registered with onRequest from the client directly, without making an HTTP request? – SametSahin Feb 19 '21 at 02:41
  • Docs says "With callables, Firebase Authentication tokens, FCM tokens, and App Check tokens, when available, are automatically included in requests.", does it also mean that `onCall` is callable and `onRequest` is not because as you mentioned `onCall`'s `context` has info about `uid` but `onRequest` doesn't. – iDecode Jul 30 '21 at 06:45
  • @iDecode IIRC what you do with the provided metadata in the request handler is up to you. You could call a *callable* function with `fetch()` and return a response or reject it because `context.auth` is missing. And I suspect that you could theoretically *call* an `onRequest` method too and parse the provided metadata yourself. When you are *calling* a *callable* (`onCall`) it's just so much easier than *fetching* from an express endpoint (`onRequest`). – Qwerty Jan 31 '22 at 21:23
  • For all those looking at this answer after years, if you use v2 functions it takes only one request parameter. – Hiimdjango May 31 '23 at 00:07
13

The main difference between onCall and onRequest for the client is the way they are invoked from client side. When you define a function using onCall e.g.

exports.addMessage = functions.https.onCall((data, context) => {
  // ...
  return ...
});

you can invoke it on the client side using the firebase function client SDK e.g.

// on the client side, you need to import functions client lib
// then you invoke it like this:
const addMessage = firebase.functions().httpsCallable('addMessage');
addMessage({ text: messageText })
  .then((result) => {
    // Read result of the Cloud Function.        
  });

more info for onCall: https://firebase.google.com/docs/functions/callable

But if you define your function using onRequest e.g.

exports.addMesssage = functions.https.onRequest((req, res) { 
  //...   
  res.send(...); 
}

you can call it using normal JS fetch API (no need to import firebase functions client lib on the client code) e.g.

fetch('<your cloud function endpoint>/addMessage').then(...)

this is the big difference that you need to consider when deciding on how to define your functions on the server.

more info for onRequest: https://firebase.google.com/docs/functions/http-events

pref
  • 1,651
  • 14
  • 24