Constantin Beer
Constantin Beer

Reputation: 5835

Can I implement chat functionality via Firebase Cloud Functions?

I'm trying to realize a chat functionality by using Angular for the frontend and Cloud Functions with Cloud Firestore for the backend. Frontend and Firestore only communicates through Cloud Functions. A question by the way, is that a good approach?

My problem right know is to make it possible that my frontend updates in realtime, if one of the chatrooms my user is in receives a new message.

A chatroom is limited for two users, but a user can have many chatrooms with other users.

My code:

Cloud Functions:

chatroomsEndpoint.js:

const chatroomsCollection = db.collection("chatrooms");

exports.getAllChatroomsByUserId = async function (req, res) {
    try {
        let chatrooms = [];
        // console.log(req.params.user_id);

        const resultA = await chatroomsCollection.where("userA", "==", req.params.user_id).get();
        resultA.docs.map(chatroom => {
            return chatrooms.push(chatroom.data());
        })

        const resultB = await chatroomsCollection.where("userB", "==", req.params.user_id).get();
        resultB.docs.map(chatroom => {
            return chatrooms.push(chatroom.data());
        })

        return res.status(200).send(chatrooms);
    }
    catch (error) {
        console.log('Error getting chatrooms', error);
        return res.send(false);
    }
};

I tried it with Postman and I get all the chatrooms where the current user is part of.

Frontend (with Angular)

chat.service.ts:

constructor(
    private authService: AuthService,
    private http: HttpClient,
    private router: Router
  ) {
    this.headers.append('Content-Type', 'application/json');
  }

  getAllChatroomsByUserId() {
    return this.http.get(`${this.apiUrl2}/${this.authService.getUser().uid}`);
  }

chatroom-list.component.ts:

userChats$;

  constructor(
    public authService: AuthService,
    public chatService: ChatService,
    public router: Router,
    public userStoreService: UserStoreService
  ) { }

  ngOnInit() {
    this.userChats$ = this.chatService.getAllChatroomsByUserId();
  }

chatroom-list.component.html:

<ul>
    <li *ngFor="let chatroom of userChats$ | async">
      <a [routerLink]="'/' + chatroom.id">{{ chatroom.id }} - {{ chatroom.messages.length }} Messages </a>
    </li>
  </ul>

All I get then I start my web app is the number of messages in a chat, but if I add another message into the document in Firestore, the value of the messages don't update.

I tried to stick to the example in the video https://www.youtube.com/watch?v=LKAXg2drQJQ&t=440s from Fireship, but in the video he is doing it through direct communication between Angular and Firestore. I also rebuild it and could make it work. Also in that example snapshotChanges() is used - is that how I can realize realtime updates?

I already searched for everything possible, but couldn't find something.

If something else is needed I will update it.

Upvotes: 1

Views: 1031

Answers (2)

ShahAli
ShahAli

Reputation: 36

My answer is yes, you can implement chat functionality with firebase cloud functions. It's quite easy though and I already have implemented this chat functionality with help of some rxjs features

To make it real-time, ya but its also true it's a little bit slower than direct firebase operations.

Let me know if you want any help of it.

Upvotes: -1

JeremyW
JeremyW

Reputation: 5272

I don't think this will be possible using cloud functions the way you want. While there are Firestore triggers for cloud functions, you're quickly going to run into a much bigger issue... how to send that new event from the server back to the browser.

As you see in the video, he's using Firestore listeners (like that .snapshotChanges) on the browser to listen to events fired off from the database. The reason this works in the browser environment is because Firebase opens up a websocket between the browser and the server, which allows real-time communication between the two parties... which, going deeper, works because Firestore has websocket support built in. So if you want to build an app to listen to the database, Firestore will let you do that.

Unfortunately, cloud functions don't have that same functionality. They aren't meant to "stay open" like the websockets from Firestore. In fact, if you try it, they'll be timed-out after a couple minutes... Even if you adjusted the timeout limit, you'll still run into other issues... for example, how do you handle dropped connections? (Firestore websockets will automatically try to reconnect and re-open that channel), Which users are listening to what? etc... The point is, cloud functions are meant to be a short, "do this once", kind of service... they aren't going to "stay open" and continue feeding updates to a client over a 15+ minute timespan.

So long story short, if you want the browser to receive real-time updates from Firebase, then the browser needs to subscribe directly to those Firestore events - no cloud function middlemen - just like you see in the video.

EDIT:

This answer regarding real-time data & cloud functions also points out that cloud functions aren't meant for this kind of use-case.

Upvotes: 2

Related Questions