[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.