[MUSIC PLAYING] DAVID EAST: One of the
core principles of Firebase is to simplify development. And that's why last year, we
released the Firebase Emulator Suite. The Emulator Suite is
a command line tool that allows you to run Cloud
Firestore, Cloud Functions, Cloud Pub/Sub, and the
Realtime Database right on your local machine. And this makes
prototyping your app and running tests and continuous
integration much easier. But we heard from you that you
wanted more than just a command line tool, that you wanted
visual tools to help you develop locally, to
do things like filter through your Cloud Functions
logs, bulk import local data, and visual tools to test
your data structures. So here at Firebase, we formed a
team to build that visual tool. And last week, we released the
local Firebase Emulator UI. My name is David East. I'm a developer advocate
here at Firebase. And I'm going to
teach you how to get started with the Emulator
UI in just 15 minutes-ish. And that's a lot
to cover, so I'm going to need the
help from an expert. TYLER CROWE: Hey, everyone. My name's Tyler Crowe, and
I'm the product manager for the Emulator Suite. I'll be popping in
from time to time to answer David's questions
and give some helpful hints and tricks as we run through
the Emulator Suite UI. DAVID EAST: Seriously, I'm
going to need that help. But the goal in this
video is not just to show you how the
Emulator UI works but also to transition you
to a local first Firebase development. So, let's get started. Even though the Emulator UI
is a local web app itself, we boot it up in the terminal
with the Firebase CLI. Make sure you've upgraded
to version 8.4 or above, but I recommend
being on the latest version because a couple of
new features are already out. I'm going to start by
initializing a blank Firebase project with Firebase init. Then I'll select
the products I need. And since I'm
demoing everything, I'll select everything. I'm going to enter my project ID
and other important information to get to the spot
where I specify which emulators I
want initialized, which, again, I want them all. Here is where you
can specify what ports you want to run
each emulator and UI on. For me, I'm fine with
all the defaults. Now I just need to
boot up the emulator with Firebase Emulators Start. This gives me a screen
letting me know what emulators are running on what ports. The Emulator UI port by
default will boot up on 4,000. So let's open it up. The emulator starts
out by showing you an overview of all your
local running services. Now you might notice
this looks a little bit different from the
Firebase console. It's purple. And why did we do that? Actually, why did we do that? Hey, Tyler. TYLER CROWE: We wanted to be
extra clear that the emulator UI was different from
the production UI. Mixing those up
could be dangerous. So we introduced a new color
to the Firebase palette-- purple. You'll notice as
you navigate around that purple appears in the
buttons, the select states, and the hover states. And if you look
really closely, you'll notice that we've introduced
a new favicon for Firebase with that purple flavor in it. If you do need to get
to the Firebase console, you can go there through a
link in the Overview page. DAVID EAST: Now let's
see this thing in action. I'm going to start with
the real time database. First off, I want to call out
that the Realtime Database Viewer has been
completely overhauled. It might look familiar now,
but the editing controls are a bit more sophisticated. Adding new nodes gives
you an inline editor similar to Firestore. By default, we'll populate child
nodes with push IDs for keys. And you can select from a
whole array of data types, like arrays, but also
including a map, which is basically an object. Now this is great for
quick data manipulation. But what I really need
when developing apps is a bulk import of data. And you can do exactly that
from either a file select or a drag-and-drop
on the viewport. Just like that, we have a
whole data set to work with. And while it's really nice to be
able to look at this test data here in the emulator, I really
want to hook it up to an app. So let me dive over
to my code editor. Right here, I have
some code in editor, and it works as a
task app that hooks up to the Realtime Database. So rather than preferring
this configuration to talk to a
production instance, I am going to write this
little if statement. And I'm going to check to see
if the location's hostname is equal to hosts because
I know I'm local. And if that's the
case, then I'm going to use a config that only
supplies the database URL, which is local host 9000,
the port I have it booted up on, and then a
query string of ns equals my project ID emulator
UI, and ns being namespace. And what's great about this
is just because it's hooked up to the local
emulator doesn't mean I have to make any
other code changes except for this configuration. So if I open up
my app, you'll see that it all works exactly
the same, except it just runs locally. So this app has
different filter states. I can filter tasks whether
they're complete or incomplete, whether they're due
today or this week, or they're by a certain
category-- work, fitness, personal, finance, whatever. And so I know with
the Realtime Database that I get one explicit
query on the tasks node. So I'm not exactly sure how I'm
going to do multiple queries. Tyler? TYLER CROWE: Instead
of relying on a query, we can store the completed
tasks and nodes in the database. This implicitly
will give us a query and still allow us to query
within the completed tasks. This is a classic example
of de-normalization. DAVID EAST: Oh,
that's a good idea. Let's refactor our database
structure in the UI. The Realtime Database viewer
has a filtering feature that creates a query
behind the scenes and filters down the data set. Oh, you can even enable a
table view for your RTDB data at any level. So I have this
data filtered but I want to copy it to a new
location in the database, which I can do with the
new clone feature. The clone feature will take
all the data at this location and copy it to a new
path in the database. If there is a
filter applied, you have the option of only
cloning the filtered data set, which is exactly what
I want to test right now. Now I have all these tasks
split out by completed state, but what about category? Could I do the same thing? This is a bit more
complicated because I could have an infinite
number of categories, so I can't just
clone them by hand. Tyler? TYLER CROWE: Now for
something really powerful. If you open up the DevTools,
we send you a little message letting you know that you can
use the Firebase SDK right there in your browser. This means you can write
JavaScript to read, write, and manipulate the data in
the Realtime Database emulator in any way you see fit. DAVID EAST: Chrome makes this
really easy with the Snippets feature. So to store each
task by its category, I'm going to de-normalize. So I'll create a method
called de-normalize that takes in a
database instance. And inside of here, we're
going to read all the tasks with async await. I want to make sure
that each task is underneath each category
that it belongs to. And so to do this, I'll
loop through each snapshot and get its category and
then create one big object. And this object will store
each category as a key. And then within each one
of these category keys, we'll store the actual task. And then once that's done,
we can save the whole thing to the root of the database. And just like that,
when the snippet is run, we have all of the
data de-normalized out to the right spots,
so by each category. The Emulator UI gives you
a bunch of visual tools to help boost your productivity. But whenever you
need to do something a bit more complicated, you can
always head to the DevTools. Now with the Realtime
Database covered, let's go over Firestore
and functions. The Firestore Data
Viewer is going to be very familiar to all of
you long-time Firestore users. You can do all the
things that you'd expect from the console, such
as finding documents or even filtering them. So you can enter the field
you want to filter by, the condition, what the value
is, and then also whether it's ascending or descending. And as always, we
will show you what that query looks like in code. And then when you apply
it, you can see the walks that met that criteria. But another awesome
thing that we added was the ability to
clear all of your data with just this one button,
which you should not be afraid to do because while
we don't have any UI tools just yet for importing
data into Firestore, you can do that with the CLI. In the command line, you
can export existing data in a running emulator. You can do that
with the command, firebase emulators
export, and then you provide the export path. So you can call it
seed, test data-- whatever. I'm going to name it seed. And if you have
existing data, it's going to ask you if
it's OK to override it, which in this case,
I think that's fine. And my export is complete. Now, remember what
this path name is because you're
going to use it when you restart the Emulator UI. And I will use the Firebase
Emulator's start command to start it back up
again, but this time I'm going to use this import flag. And I can specify my path,
which we named as seed. And we're up and running again. And for some reason, this time,
due to all the crazy things I do in my dev machine, I
wasn't able to start on 4000. But the CLI will start me
on the next available port, which in this case is 4001. Now back in my Emulator
UI, we have all the data that we exported,
and that means I don't have to worry about
deleting it whenever I want to. The Firestore UI is
already pretty advanced, so there's not too
much to show off. What I'd really
like to do right now is show you how it all
works with Cloud Functions. The data in this
Firestore Viewer represents a walk logging app. Every time you take a
walk, you log an entry. I'd like to add a feature
where I can automatically log the weather from the location. So let's write a Cloud Function. We'll trigger it
off of an On Create trigger on the walks location. And when a document
is created, I'm going to query a weather API
and then update the documents. And all of this is
going to happen locally. Now we recommend that when you
write Cloud Functions that you try to mock your services
locally when developing, so everything is really fast. So instead of using
a real weather API, I'm going to mock one
with a Cloud Function. I know, it's very meta. This is just my
preference, but feel free to call out to over the network
if that best suits your needs. So this mock function
is just going to retrieve the
location from the body, just pass that into this
little fake weather map, and return back what will
be a hard-coded weather. I could do something
with random, but this is just easy for now. Now I want to call out to
this Get Weather trigger, so I'm going to save the
endpoint as a constant. And then now, inside
of Update Weather trigger, we'll get the location
of the newly created documents, and we can use that
to pass as the body of the fetch request of our
Cloud Function we just created. When we get back the
weather data as a response and then subsequently as JSON,
we can update the document with the weather data. And since we're
using async awaits, we have to make sure to mark
this method as async, which I forget to do all the time. The emulator instantly
picks up these code changes, and we are ready to test. So let's create a new walk. But nothing is happening. Hey, Tyler. TYLER CROWE: In
the logs tab, you can see all the logs from all
the emulators in the suite. Using a Fuzzy Search, if we
search by the function name, we can find all the logs
for that function trigger. Now you'll notice here
that we made a mistake because we used a relative URL
instead of an absolute URL. If we do a quick change here
and a quick test, there we go. We have a successful
trigger now. DAVID EAST: OK, that was
a lot, and we didn't even get to that Pub/Sub
Emulator, which if you want to see
a video on that, make sure to leave a comment. And if you want to see a video
on how to test your security rules with the emulator,
check out Todd Kerpelman's and Rachel Meyers' video
that happened just last week. I hope in these 15-ish
minutes that you learned how to have a local
first Firebase development workflow. And if you want to see any
features out of the Emulator UI, make sure to hit us up on
GitHub because this project is open source, so we love to
see issues and pull requests from you. And remember, this
UI, it's brand new. So as excited as we are
about what it can do today, we're even more excited
about the features that we can add in the future.