Transcript from the "Parsing an HTTP Response" Lesson
>> Request went through, things are cool. But you also don't actually see any of the request body, we don't see that giant JSON object of people that we eventually want to parse. So you need to do a couple additional things. So underneath our print line here, we're going to use another library called ioutil.
[00:00:26] So ioutil, the method we want off of this guy is read all And read all is going to take an argument and the thing we want to actually be, the thing we want help parsing is our response.body. So we can say response.Body. On the left-hand side here, before we get too far, just make sure at the top of your file, you are importing ioutil.
[00:00:57] And that is from the Oops, io/ioutil package. So kind of demonstrate here. Even though we're importing io/ioutil, the only part of this we need to access is that part of the right hand side. So we've only been using HTTP and now we only need to use ioutil. So that last part of the path on the right-hand side is giving you access to the whole library.
[00:01:28] Let's go back down to this guy, and we want to call ioutil.ReadAll on the response.Body. And so this function is going to hand us back a couple things. Let me see this, okay, it's gonna hand us back data. And potentially an error. And so once again, first thing we're gonna do is check for that error.
[00:01:54] If error does not equal nil, We're gonna send it up to HTTP which takes our three arguments. Print something for our human eyes to read, failed to parse request body. And if everything goes well, let's print line again and just see what we're working with. What is data?
[00:02:35] I'm gonna kill my server and restart it. Refresh. Cool. So assume you get a huge array of numbers and if you recall from earlier examples, like when we were iterating over letters in a sentence. We need to do an additional step to kind of parse this information into the actual format we want to use it in.
[00:03:10] So what we're looking at here is a set of bytes. So I'm actually gonna modify this variable here to be a little bit more accurate. So we're talking about bytes. So instead of just printing it, we need to parse it. So here is where we're going to start using the JSON library.
[00:03:27] And so at the top of the file, you can import Encoding/JSON, And back down to where we get our bytes back. We're gonna say JSON.unmarshal, and unmarshal takes a couple things. So JSON.unmarshal is going to parse encoded data, and then store the result in a variable that we tell it to.
[00:03:59] So similar to like JSON.stringify or JSON.parse, we are taking information that isn't in a format we want. And then using the JSON library to get it to a place and in a format that we can use. So the unmarshal takes two things. It's gonna take what we're trying to parse, which is that big array of bytes.
[00:04:16] And then some variable where we want to put it. And we haven't defined this variable yet, but because we're gonna be modifying it permanently, we're gonna use the at, sorry, ampersand and send it to our variable people which we have not defined. So what are we trying to unmarshal and give me the memory address, where you want me to store this information.
[00:04:48] So we can just stick this variable here so it's easy to see. We'll say we're gonna initialize a var, people. And then we're gonna create a people struct, which doesn't exist yet. So let's scroll up a bit and get out of this function and define our people struct.
[00:05:16] So we have type people, which is a struct. And people is going to have a People attribute. And it's going to be assigned to a collection of person types. For clarity, I'm gonna do a quick modification, instead of calling the struct type people, I'm gonna change this to be all people, just so we're not talking about the same word in various ways.
[00:05:58] Which means that I also need to scroll back down and modify that my variable people is actually assigned to a type of AllPeople. We're gonna be throwing this word a lot, let's produce some confusion. Okay, so let's create our person struct. Type person. We're gonna have person defined with a couple attributes.
[00:06:25] And if we flip back over to the API, the attributes I want to pull off of this JSON object are the name and the homeworld URL. We're gonna need to make a second request to actually get that information. But for now, we know we want the name, the homeworld URL and then eventually, we're going to want whatever this homeworld URL and point returns which we'll look at in just a second.
[00:06:48] So back in the code. Person will take a capital N name which is a string, a Homeworld URL which is a string, and then eventually an actual Homeworld, which is going to be defined by the planet struct we haven't defined yet. So next steps. Let's add one more struct here.
[00:07:16] We're just gonna be type planet. And you'll notice that so we don't have any attributes in planet. Let's go check out the API and see what we get back from a planet request. So let's grab this one. So we've got the base URL/planets/an ID. So up here in our little sandbox, we can do /planets/1 just to kinda see what we're working with.
[00:07:47] So on a planet, we have additional information name, rotation, period, climate, etc. And a bunch of residents that live on that planet. So let's just grab a couple. Let's do like name, which is a string, terrain, which is a string, and population which is also a string. So we'll hop back over to our code.
[00:08:09] And on planet, we want name which is a string, population, which is a string and terrain which is a string. And once again, all of these because they are being potentially exported to use elsewhere, we need comments. Cool. So now we have three different structs which are kind of nested and related to each other in different ways which means we can start adding some data to our variable.
[00:09:12] We'll scroll back down to our function. So now that we've defined all of the different shapes of all people, we can tell our JSON.unmarshal function that once it receives the bytes, parse them and throw them on to Allpeople. So for now, let's just print out People. All right, cool.
[00:09:38] So we have on line 57, we're calling JSON.unmarshal and parsing it a series of bytes and then saving whatever gets parsed to our people variable. Using the ampersand indicates an address. Let's throw a error handling, additional error handling right after this guy in case anything goes wrong. So I'm going to set another err equal to our JSON.umarshal.
[00:10:03] You'll notice if I hit save that we've already established that this guy is called err. And then we have some error handling. And so we haven't been taking advantage of the structure where we can wrap the functionality in the if block to scope that err, so that we top getting error that.
[00:10:20] So I'm gonna do that real quick here. So instead of defining the error immediately, I'm gonna say if and then we're going to set the variable err to our JSON.unmarshal semi colon. And then if it does not equal nil, We are going to, oops, print error. We're going to print line error parsing JSON.
[00:10:54] And then display the err. So by wrapping our err in our if block, which we probably should have done from the first get go up here, we can avoid that duplicate variable declaration error. Okay, so notice that if we actually run the print line function here we were getting that empty object.
[00:11:14] So I'm gonna wrap The JSON in a string. Just getting up on line 55 we want to print line not just the bytes, but like what is the string version of all these bytes giving us back. Similar to when we were talking about iterating over each letter. Start on the server.
[00:11:39] Refresh here and you'll see in our response, we're getting some actual text back so this is helpful we can kinda see what our API response is giving us back. If we scroll to the top, You'll notice that our actual array of data is kinda nested deeply within here, but we're seeing that we have a key of results.
[00:12:02] And then it's an array of JSON objects that have our person information attached. So if we go up to where we're storing our information on this Allpeople struct We're telling it to look for some sort of key called People, which does not exist on our JSON object. And this is where we can use something called a JSON Flag to kind of bridge that gap between what our JSON is giving us and what we wanna call it in the Go syntax.
[00:12:28] So to do that, we're gonna use backticks to the right hand side of the strut attribute. And in our JSON block, so we're talking about JSON not XML. We are actually looking for the results. And the results is going to be an array of person and objects. But similarly if we go up to person, we're saying we want JSON to go find Name, Homeworld URL and Homeworld, these things don't exist either.
[00:12:58] So let's go ahead and modify all of our struct attributes to match what exists on our JSON object. So here we have JSON:"name", lowercase n. And our HomeworldURL is json:"homeworld". Our Homeworld that's set to a Planet can stay the way it is because we're defining that on its own right above here.
[00:13:27] But we do need to hop into here and make sure that these are going to be mapped correctly too. So these guys, we're going to have JSON set to lowercase name, Lowercase population And lowercase terrain. Now that we've mapped kind of what our ghosts and texts look like to what our JSON object will give us back, go ahead and save this guy.
[00:13:58] Restart our server. Refresh my browser and you'll see we're getting a list of people with the information we kinda expect.