Check out a free preview of the full Cross-Platform Mobile Apps with Flutter course:
The "Request Data with Futures" Lesson is part of the full, Cross-Platform Mobile Apps with Flutter course featured in this preview video. Here's what you'd learn in this lesson:

Maximiliano fetches remote JSON data using a Future, which is similar to a Promise in JavaScript. Annotating a function's return type as a Future allows the async/await keywords to be used within the function. Data is loaded with an imported http module and a for loop is used to populate the menu.

Get Unlimited Access Now

Transcript from the "Request Data with Futures" Lesson

>> Are we ready? Well, we are ready to download the data and parse the data. We didn't do that yet, okay? So now, we are getting into our companion website, into the latest chapter that has to do with coding. Because the rest is the final compilation. So we already added the dependency, we already did that.

[00:00:22] So we are in 5.2, we're going to request data with futures. It's like, what is that? Well, first, Dart doesn't include an automatic way to map JSON to objects of a class. So typically we do it manually, okay? So how is manually? First, what's the type of a JSON?

[00:00:47] A JSON will give you a map of a string dynamic. So the key is a string, and the value can be anything. Because it can be a number, it can be a string, it can be an array that's a JSON, okay, makes sense? So this is what we're getting.

[00:01:04] So where we're going to do typically is a factory constructor for the product and for the category. That is just making the map. So I'm taking from the JSON the id, and I'm saving that in the id of the product. And as int, it's actually how we cast here in Dart, yeah.

>> Max, what happens if the data structure came back with a null, like, for example, on price?
>> So if the structure is not matching this, as the code that is right now, will actually give you an a runtime error. So if that might happen, well, first, you can wrap this in a try catch.

[00:01:45] We do have exceptions in Dart. So you can trap this in a try-catch and then say, okay, it didn't work. We don't know why, but it didn't work. Or you can play with the map, and before actually doing this, you can validate if the map has the keys that you want.

[00:02:01] One by one, you can do a manual validation. Okay, makes sense?
>> But what if you did Map<String, Object>?
>> The same happens. So if the type is different when you are casting, it will generate the runtime exception. So if the key is not there, or if the key is there but of a different type, you will get the runtime exception.

[00:02:22] And you can catch that exception with try-catch. I think that's what we're going to do. That's a more general error handling, or you can go first and validate your JSON first. Okay, makes sense? So this goes in the product class. I mean, we can type this, but it's actually simple to get.

[00:02:45] Within the product, that's a constructor. We are going to add another factory constructor, factory constructor that take this. Okay, like so, from a JSON, and something similar for the category. Okay, so not really a big deal. It's just, Taking the the id and the products and creating all the structure.

[00:03:16] Okay, so you get a JSON. And we are mapping property by property that JSON with the right type or with the expected type here directly in the code. Does it make sense? Of course, there are some frameworks and libraries that are actually not part of Dart that can help you with doing this with a more complex scenario.

[00:03:37] Also, if you have the URL of the JSON. Let's look at the JSON, we haven't seen the JSON yet. It's, you have the URL to copy and paste in the here. If you go down a little bit, it's here, that's the JSON, okay? So let's look at the JSON for a second, so we can see a structure.

[00:04:01] So we have an array of categories. Each category has an array of products. That's kind of the idea. Okay, so if you have these, you can actually go on Google JSON to Dart. And you will find some web apps where you can actually generate Dart code, your Dart cloud.

[00:04:24] I need to create a class name like Testy, whatever, or copy their code to the clipboard. For some reason, I sure see that button is working. It says, I pasted the URL, and not the JSON, sorry about that. View page source. This is the JSON, okay? So now we have the JSON.

[00:04:47] I'm not sure it's that one. Generate Dart, there we are. And this is creating the code for you. Actually, it's creating the same fromJson factory method that we have just seen. So when you have a very complex structure, typically, you have one of these tools to generate rapidly, or fast, the factory methods, okay, makes sense?

[00:05:11] So, good, so the next step, is to now go to the network and fetch the data. So for that, I'm going back to the DataManager. And I'm going to create two functions, first a function called fetchMenu, that will actually go to the network. And the other one is only just going to be a getter.

[00:05:30] Okay, so, getMenu, that will do something like this. If the menu is null, is because we don't have it, we are going to fetch the menu, okay? And then after fetching, we're going to return the menu, make sense? It's a getter, it's like a lazy getter. There are other ways to do a lazy getter.

[00:05:57] But I'm trying to do it so we can actually understand what's going on. So we're going to do, what's the type that we're going to return? Are we going to return a menu? A menu is actually a list of Category. We have a problem, the problem is that going to the network, and you know that if you're a developer, a frontend developer, it's an async operation.

[00:06:23] So I can't just return the menu because I need to go to the network. So Dart supports async programing with futures. A future is something very similar to a promise. So if you're used to promises in JavaScript, it's actually pretty similar. So instead of returning a list of categories, we are going to return a future list of Category.

[00:06:47] Think about promise, okay? So it's a promise of a list of categories, it's a future in this case, okay? That's what we're going to say here, does it make sense? But now, if you're going to return a future, our function must be annotated with async. And fetchMenu we need to await.

[00:07:14] So we have async await as we are used to, okay, on other platforms. Okay, makes sense? So it's a similar way, that we have on other platforms. So we will solve that problem in a minute. So fetchMenu needs to go to the network, okay? So we're going to now create a constant for the URL.

[00:07:44] Let me take the URL from here, from the JSON. I will need to use the HTTP API that we've seen before, okay, that we added. And for that, we say response is equal to, we are going to await for http.get. And we're going to create a Uri object from that url string, okay?

[00:08:14] So await, it says hey, if you wanna await, you need to be in a async function. The http package needs to be imported, actually. So to import the package, if the ID is not helping you to automatically import that, the package is package:http/http.dart. And I'm actually renaming that as http.

[00:08:40] So you can actually use any name here. And then, of course, you need to use that name down, okay? So when you have the response, you can just take directly the body of the response. But the problem is that we are doing http. We know that sometimes the server is giving us errors, 400, 404, okay?

[00:09:01] So typically you wanna check if the response status code is 200. And if it's 200, what we need to do is to try to decode our content. Okay, does it make sense? So we can take, for example, response.body will give me the body. What's the body? The contents of the HTTP response, the string of the JSON, makes sense?

[00:09:30] So now, what I need is to decode that data. And for that we have a JSON decoder, so we don't need to do it manually, the manually string parsing. jsonDecode will actually take that body, and we need to specify what are we expecting. jsonDecoder needs to be imported, let's finish this, so like that.

[00:09:57] I think my imports are kind of crazy today. Anyway, so we need to import the body, and we just specify what are we expecting. And this JSON, if we look back to the JSON, it start with an array. A list, it's not an object. Okay, the root element.

[00:10:19] So that's why we're going to say it's a list, of what? Of whatever, that says list of dynamic. Okay, so that is that problem. And here I have a typo, because it's jsonDecode, not jsonDecoder, and now, I can import the library. So what to do with that data?

[00:10:39] So I have the list now, I need to actually start create an empty menu. And start looping through all the decoded data objects. And within that menu, I'm going to add what? A new category from a JSON. Makes sense? I have an error here, because it says hey, the menu can't be null.

[00:11:13] So you cannot call el, remember how to solve the problem? I know it's not null because I have just created one, okay? Sorry, what?
>> The bang, non-null [INAUDIBLE]
>> It's a non-null, we can use that, or we can also use the safe operator. The safe operator if it's null, so the question mark, if it's null, we need to ignore the declaration.

[00:11:35] Both in this case will kind of work, okay? And that will make the trick. What happens if the JSON is not valid? If it's not JSON? What happens if the keys I'm expecting are not there? Well, we can put this in a try-catch. Okay, that's a possibility.