by Paul Breslin
保罗·布雷斯林(Paul Breslin)
如何使用async / await和Firebase数据库编写漂亮的Node.js API (How to write beautiful Node.js APIs using async/await and the Firebase Database)
This tutorial will cover the typical use cases you’ll come across when writing RESTful API endpoints to read and write to a Firebase Database instance.
本教程将介绍编写RESTful API端点以读写Firebase数据库实例时遇到的典型用例。
There will be a focus on beautiful asynchronous code, which makes use of the async/await
feature in Node.js (available in v7.6 and above).
我们将重点关注漂亮的异步代码,该代码利用Node.js中的async/await
功能(在v7.6及更高版本中可用)。
(Feel free to smile sweetly as you wave goodbye to callback hell ?)
(在向回调地狱挥手道别时,请随意甜蜜地微笑吗?)
先决条件 (Prerequisites)
I’ll assume that you already have a Node.js application set up with the Firebase Admin SDK. If not, then check out the official setup guide.
我假设您已经使用Firebase Admin SDK设置了Node.js应用程序。 如果没有,请查看官方安装指南 。
写数据 (Writing data)
First off, let’s create an example POST
endpoint which will save words to our Firebase Database instance:
首先,让我们创建一个示例POST
端点,该端点将单词保存到Firebase数据库实例中:
This is a very basic endpoint which takes a userId
and a word
value, then saves the given word to a words
collection. Simple enough.
这是一个非常基本的终结点,它接受一个userId
和一个word
值,然后将给定的单词保存到words
集合中。 很简单。
But something’s wrong. We’re missing error handling! In the example above, we return a 201
status code (meaning the resource was created), even if the word wasn’t properly saved to our Firebase Database instance.
但是出了点问题。 我们缺少错误处理! 在上面的示例中,即使单词未正确保存到我们的Firebase数据库实例中,我们也会返回201
状态代码(表示资源已创建)。
So, let’s add some error handling:
因此,让我们添加一些错误处理:
Now that the endpoint returns accurate status codes, the client can display a relevant message to the user. For example, “Word saved successfully.” Or “Unable to save word, click here to try again.”
现在,端点返回了准确的状态代码,客户端可以向用户显示相关消息。 例如,“ Word保存成功。” 或“无法保存单词,请单击此处重试。”
Note: if some of the ES2015+ syntax looks unfamiliar to you, check out the Babel ES2015 guide.
注意:如果您不熟悉某些ES2015 +语法,请查阅Babel ES2015指南 。
读取数据 (Reading data)
OK, now that we’ve written some data to our Firebase Database, let’s try reading from it.
好的,现在我们已经向Firebase数据库中写入了一些数据,让我们尝试从中读取数据。
First, let’s see what a GET
endpoint looks like using the original promise-based method:
首先,让我们看看使用原始的基于promise的方法的GET
端点是什么样的:
Again, simple enough. Now let’s compare it with an async/await
version of the same code:
再次,足够简单。 现在,让我们将其与相同代码的async/await
版本进行比较:
Note the async
keyword added before the function parameters (req, res)
and the await
keyword which now precedes the db.ref()
statement.
请注意,在函数参数(req, res)
之前添加了async
关键字,现在在db.ref()
语句之前添加了await
关键字。
The db.ref()
method returns a promise, which means we can use the await
keyword to “pause” execution of the script. (The await
keyword can be used with any promise).
db.ref()
方法返回一个db.ref()
,这意味着我们可以使用await
关键字来“暂停”脚本的执行。 ( await
关键字可与任何promise一起使用)。
The final res.send()
method will only run after the db.ref()
promise is fulfilled.
最终的res.send()
方法仅 在 db.ref()
承诺实现后 运行 。
That’s all well and good, but the true beauty of async/await
becomes apparent when you need to chain multiple asynchronous requests.
一切都很好,但是当您需要链接多个异步请求时, async/await
的真正优点就显而易见了。
Let’s say you had to run a number of asynchronous functions sequentially:
假设您必须依次运行许多异步函数:
Not pretty. This is also known as the “pyramid of doom” (and we haven’t even added error handlers yet).
不漂亮。 这也被称为“厄运金字塔”(而且我们还没有添加错误处理程序)。
Now take a look at the above snippet rewritten to use async/await
:
现在来看一下上面重写为使用async/await
代码片段:
No more pyramid of doom! What’s more, all of the await
statements can be wrapped in a single try/catch
block to handle any errors:
没有更多的厄运金字塔! 而且,所有的await
语句都可以包装在单个try/catch
块中以处理任何错误:
并行异步/等待请求 (Parallel async/await requests)
What about cases where you need to fetch multiple records from your Firebase Database at the same time?
如果您需要同时从Firebase数据库中获取多个记录,该怎么办?
Easy. Just use the Promise.all()
method to run Firebase Database requests in parallel:
简单。 只需使用Promise.all()
方法并行运行Firebase数据库请求即可:
还有一件事 (One more thing)
When creating an endpoint to return data retrieved from a Firebase Database instance, be careful not to simply return the entire snapshot.val()
. This can cause an issue with JSON parsing on the client.
创建端点以返回从Firebase数据库实例检索的数据时,请注意不要简单地返回整个snapshot.val()
。 这可能会导致客户端上的JSON解析出现问题。
For example, say your client has the following code:
例如,假设您的客户具有以下代码:
The snapshot.val()
returned by Firebase can either be a JSON object, or null
if no record exists. If null
is returned, the response.json()
in the above snippet will throw an error, as it’s attempting to parse a non-object type.
Firebase返回的snapshot.val()
可以是JSON对象,如果没有记录,则为null
。 如果返回null
,则上面的代码段中的response.json()
在尝试解析非对象类型时抛出错误。
To protect yourself from this, you can use Object.assign()
to always return an object to the client:
为了避免这种情况,您可以使用Object.assign()
始终将对象返回给客户端:
Thanks for reading!
谢谢阅读!
Interested in seeing a real-world project built on top of Firebase and Node.js? Check out Vocabify, the vocabulary builder that helps you remember the words you come across.
有兴趣看到基于Firebase和Node.js构建的现实世界项目吗? 查看Vocabify ,它是一个词汇生成器,可以帮助您记住遇到的单词。