In a nutshell, I'd like to get meaningful validation errors from firebase/firestore when doing a transaction in an app, when changing users nickname.

I'm struggling to find a good approach. Let me explain by this simple example:

A "nickname" TextInput for a user profile page in React Native. User can change the "nickname" value and click Save. If there's anything wrong with the nickname string, user is shown meaningful errors/feedback, e.g.: Nickname too short / long. Nickname contains bad words. Nickname is already in use.

I've done this already by using Cloud Functions and a https call from the app when clicking Save. This allows me to show any input validation errors to the user, since it's a proper request to the server, where I can throw an error that can be shown directly to the user. But it feels... clumsy?

The serverside validation of the nickname itself checks for length > 4 && length < 20, as well a check for uniqueness of the username, plus some checks for bad words. Uniqueness is done by having a firestore collection with nicknames already in use.

Is there really not a simpler way to do this? Is the above the best approach?

It would be easy if I somehow could throw an error within firestore rules and catch it on the client side, then show it to the user - then I could have all my validation with regex etc. just inside firestore rules. But all I've seen is allow and deny - it's purely access based, so the user ends up with "permission denied" if I try to do any validation. So I have to both do the rules in firestore (for security), AND write validation on the client side to show meaningful errors to the user (i.e. client doesn't send any data unless it's valid). Without the client-side validation, it would just throw "permission denied" errors when trying to update directly with firebase.firestore.doc('users/blahblah').update({ nickname: new_value }).

That's of course doable, but not as flexible as just having the server validate and give out error messages - saves a lot of typing - and doesn't require an app update if I have to add more validation rules later on - can just do it on the server.

I just feel it would be more elegant to do a simple transaction in the app via firebase.firestore functions, and be able to catch errors.

I have a feeling I might be missing something, but I've spent two days scouring Google, reading all the firebase + firestore docs and react-native-firebase docs + examples. So I hope someone here has been in a similar situation with a few minutes to spare some wisdom :)

Cheers!

2 Answers

0
Muhammad Faizan Uddin On

In such cases for designing user friendly interfaces, error messages should be decorated properly with meaningful message by mapping them with HTTP status codes:

200 - valid input
422 - input should meet certain criteria

In your case an approach could be by sending an HTTP request to server (on each user tap when characters are > 4) keeping the SAVE button disabled till latest success from service.

The cloud HTTP call should response with 200 status only when below criteria is met:

  • input length > 4 && length < 20
  • check for uniqueness of the username
  • checks for bad words

Otherwise non success codes should return from server (which can be used for mapping with a user friendly message to be shown to the user). Mapping of HTTP codes can be done either client side or server side.

1
Dilyan Trayanov On

So what you want is to implement an application logic inside database. That is completely fine. Your model (Entity) has validation rules defined on the client side (User interface) and on the server side (Server application).

In order to centralize the validation, the way you want, you have to move all rules inside database functions and/or triggers. That's something that i will never recommend, because you will base somehow a very important part of your application inside database layer. After that step you still have to delegate all errors to the server application layer and back to the user, because you need to authorize the user properly.

So to answer the question - YES. That is the best way of doing validation - inside APPLICATION LAYER. Leave the database alone, that is just a storage. And YES you can duplicate some of the rules there, but that is just a matter of good practice these days.

If on the other hand, you read some books about database design and how things work there, you will find strong recommendations to implement a very restrictive rules for the objects inserted/updated for specific model.

So after all that reading you will end up with validation in:

  1. User interface
  2. Application layer
  3. Database layer

There is no easy way to centralize validation without loosing some flexibility.