Transcript from the "API Handlers for GET" Lesson
>> Its time to see how to work with web services. If we want to create a little API that can serve our exhibitions as an API. They are still staying with vanilla Go, so no libraries, okay? Then I will show you some libraries that are available to do this faster if you want, I don't know.
[00:00:20] But anyway, we go is pretty straightforward. So we are going to create for that a package. So I'm going to create a new folder. Let's call that folder API. In the API, we are going to make two RESTful operations, I get and a post of course then you can add the rest.
[00:00:42] It's pretty straightforward. So I can separate this by verb if you want to, like all the gate operations in the gate.go and all the post operations in the post go. So we will make code up so we can add a new exhibition for example, okay? Remember you can connect these to a database or to any data source if you want just using a library and understanding how to use SQLite or SQL Server or MongoDB or so on.
[00:01:14] So, what are we going to see here? We're going to create here is, for example, a function to get one, or more, exhibitions. In fact, we can read the query string, and if we receive an ID, or an index, we are going to return 1. And if we don't receive that argument, we will return all the exhibitions.
[00:01:37] The exhibitions that we have here, okay? Yeah, it's a very simple, static, hard coded database, okay? That's not a good idea, don't do that at home. But so we are going to then create a gate that we have the writer. It's always the same thing. Responsewriter and then http.Request, that's the signature of every handler.
[00:02:05] Let's start first serving all of them. So what I need is to send to the output JSON, okay? And remember that we've seen Marshall and Marshal so we could convert the JSON, just ring, blah, blah, blah but fortunately, we have something much simpler. There is a way in the JSON package to create a new encoder.
[00:02:32] And the encoder receives as an argument a writer. Who is the writer? The argument that we are receiving the handler. So in this case, instead of receiving a string and using our Marshall and Marshal to work with the strings, we can just send directly the stream of JSON to the output.
[00:02:54] This is even faster. I don't even need to create a temporary string in memory. So basically in this case, while the encoder is taking out my object and creating the string for the JSON, we are sending the device to the network directly. We go to a string. And we asked that encoder to encode one particular object, which object?
[00:03:20] The one that we have in data, GetAll, very simple. Do we need something else? No. The only thing that if you want to be a good citizen for API's, the only thing that you need to add is a header to specify that you're sending JSON. Because by default, HTTP understands that you're sending text.
[00:03:43] Some APIs will never care about that header, but maybe it's a good idea to add a header. And to add a header, we also talk to the writer. And we say, header, it's a function that returns an object value. So with some functions for example set we can set a header.
[00:04:01] I'm not sure if you are experienced with HTTP headers but the header is content type and the value that we need to send is the type that for JSON is typically application JSON. That's a handler, and to test the handler, I need to register the handler in my server.
[00:04:30] So we need to go to the main and register this handler. So I will go to main.go. I will put it here so you can still see my get there for a while. So I will add server HandleFunc, and I can say /api/exhibitions will go to api because a different package .Get.
[00:05:02] So when that API is hit, we're executing the get function from the API package. I need to restart my server because I have changed Go code. Let's try this. I will go to api/exhibitions, and now I got a nice JSON back as a result. So pretty simple, right?
[00:05:33] Then I said that I wanna also to maybe pass an ID or an index so I can say I want the third one. I'm still getting all of them. So let's add some more behavior here. And let's say that if the ID is not nil, and what's ID?
[00:05:54] Where I can get that ID? Well, we have something known as r. The r is the request, the second argument, the request is what's coming from the browser. The r has a URL value, and that value has a query, Function that returns a map with everything that was set in the URL bar.
[00:06:22] So it can actually access ID, something like that, does it make sense? In this case we are going to talk to api/exhibitions and ID?=34. Well, we are going to read 34 here. Makes sense? In our data structure we don't have ID so we can treat that as a just you by order.
[00:06:56] Well if I have it then what I need first is to convert that into an integer because this is something the user can change. So I cannot just treat it as a number. I need to convert that into a number, and see if it's a real number. Because maybe it says hello.
[00:07:16] Okay, so also for security reasons. So there is a, remember I mentioned before that there is a package strconv for string conversions. Here we have a lot of functions actually to convert from and to strings. And there is one with the name Atoi. Atoi. It's actually similar to Parseint that is prepared.
[00:07:47] So it's parsing this as an integer using automatically the decimal base, so base 10. So in this case I can parse that ID and every converter tool will return me the, let's say the finalid and also possible error because maybe and you know what maybe this is not working.
[00:08:14] Because maybe you are parsing something that it doesn't look right and by the way always all these objects that you receive when you look at the value is not actually one string it's in a slice. It's always in a slice, why, because technically you can parse more than one ID with a comma.
[00:08:36] So that's part of the protocol, okay? Even if you parse only one, you receive a slice of an array collection. So we get the first one. Make sense? Well, if there is error here, so if error, let's start with if there is no error. So, if error is nil, and also I should verify, that the final ID is not bypassing the length of the data.
[00:09:08] Make sense? Because if that happens, I'm trying to get an exhibition that doesn't exist. So in those cases I'm going to return an error. And we already return a 500, setting the header, but I will show you another way to return an error, a faster way. You can talk to http and say http.Error.
[00:09:33] It's a function receiving the writer, A message like Invalid Exhibition, and then the status that you wanna send back, status bad request. This is just a utility function to reduce the steps. And if not, well, we actually have one, the element that we want to send. So we are going to also, similar to the encoder that we have here, we are going to create a new encoder based on our writer, the output.
[00:10:09] To the browser, and we are going to code not all the objects but the final ID, the one in that position. We can call this index as well instead of final id. Does it make sense? So in this case we read the URL if we have that argument, we just return one element So I'm going to stop the server run again.
[00:10:45] I'm going to try this, again, let's see exhibitions give me all of them exhibitionsid1. It's giving me 1, but also the rest that's because I have this here and that shouldn't go here but in an else, right? If not I'm returning both, one element and also the array.
[00:11:14] So in this case, we want all. And here, we will try to serve only one, that's the idea. So now, try again and now I have the first one. Id0, next one, and if I'm not parsing the id, I have everything. What happens if I parse, Hello or maybe Panic, as an id I'm getting invalid exhibition.
[00:11:47] By the way here I said get but am I verifying that that request was actually made with a Get or not? Actually, no, I can actually make a POST to that URL, or a DELETE to that URL. I'm also returning a GET. In this case, it's harmless, because nothing happens.
[00:12:06] But with a POST or a DELETE, you need to be sure that the verb that you're receiving is the one that you're expecting.