Learn GO Fast: Building an API

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
all right let's put everything we learned in the previous tutorials together and make an API and go before we start I just want to note that I'm going to assume that you have some level of knowledge of how restful apis work it's not strictly necessary for this video but it's a nice to have alright so this is what our API is going to look like in the end here I'm using Postman for testing this API we're going to make an account slash coins endpoint which we can use to look up the amount of coins someone has in some imaginary account we got a parameter which is a username and the authorization token in the header which we're using to authorize the call so this tutorial is going to cover go code structures authentication middleware and installing and importing external packages let's create our project with go mod in it and the name of our module so in my case I'll use my GitHub repo for this project where you can check out the code for this tutorial so first let's start with the structure of our project many go projects adhere to a standard layout which I'll vaguely follow here the note you don't have to follow the structure for your future projects do what works for you not to worry I have a permit this just says I can do what I want you can read more about this by Googling golang project structure and you'll find a GitHub repo detailing what code should go in what folder okay so we'll have an API folder here we're going to have our specs things like parameters and response types for our endpoint this is also where you could put your yaml spec file I'm not going to cover creating a yaml file as it isn't strictly needed and it's not the topic of this video next we're going to have a CMD API folder which will contain our main.go file and we're going to have an internal folder this will contain most of the code for this API let's start in our API folder and let's create an api.go file here let's write out the parameters and the responses of our endpoint let's start with some imports which we're going to use in a bit we'll make a few structs which will represent our parameters for our endpoint and responses first we have our coin balance param struct which represents the parameters our API endpoint will take in this case we'll just require the username second we have the coin balance response struct this outlines the successful response from the server containing a status code and the account balance next we have an error struct representing the response returned when an error occurs so we got the Response Code as well as an error message okay so now let's define our main package in CMD API main.go by the way if you like this series or this video so far make sure to tap those like And subscribe buttons if you haven't already alright let's note a few things from our package Imports first in our API we'll use the QI package this is a pretty flexible and easy to use package for web development though there are a bunch of others you could use second we're going to be importing a package from our own module here in the internal slash handlers folder lastly let's use logaris to log errors for debugging when we Import in x external package like logress or Chi we can install it using go mod tidy now in our go.mod file we can see that we have these two packages listed out alright sweet so now let's go back to our main function to start let's set up our logger so that when we print something out we get the file and the line number to do this we call the set report caller function passing in true to turn this on now we create a new Chi mux variable using the new router function which returns a pointer to a mux type which is really just a struct which we'll use to set up our API we're going to pass this into our Handler function which we'll Define in a second in our internal slash handlers folder remember we imported this package up here this will set up our router I add the endpoint definitions that we want let's add a print statement and then another cooler print statement and then let's start the server with our HTTP package this takes the base location of your server which in our case is just localhost on Port 8000 as well as a Handler which are muxtype satisfies and then of course let's log any errors we might have when starting the server okay so now let's actually create this Handler function which will set up our router this is in our internal slash handlers package under the api.go file so let's define our Handler function which takes in that muxtype we just created note that our Handler function starts with a capital H so this just tells the compiler that the function can be imported in other packages if I started with a lowercase and this would have been a private function which could only be used in this Handler's package the main package would not be able to import it as we did now let's cover the concept of middleware so middleware is essentially a function that gets called before the primary function which handles the endpoint let's look at a few examples of how we're going to use middleware you can add middleware to a route by using the r dot use function so first we're going to add a piece of global middleware this is going to be the strip slashes function this is a pre-built function we are grabbing from cheese middleware package Global middleware means that this middleware is applied all the time so in other words to all endpoints we make this strip slashes function will make sure that the trailing slashes will always be ignored otherwise we'd get a 404 error if we included the slash like this all right so time to set up our route to do this we call r dot route which takes in the path which is slash account for us as well as an anonymous function which takes in a Qi router as a parameter we can now use this router to Define our get method but first let's add another piece of middleware to this route where we can check if the user is authorized to access this data first we'll create this authorization function in our middleware package later now every request which wants to access an endpoint starting with Slash account has to pass through this authorization function first if the authorization fails the function will return an error as a response and the rest of the code won't get executed so this function essentially acts like a nightclub bouncer if you don't have the proper ID you can't come in here we'll create a get method inside this route with the slash coins path which will be handled by the get coin balance function we'll Define this function later as well so we just created an endpoint that's now at slash account slash coins alright so now we got to Define our authorization and our get coin balance functions let's start with the authorization function we'll put this in our internal slash middleware slash authorization go file first let's create a custom unauthorized error which we're going to use in this function so because we're using our authorization function as middleware this needs to follow a certain signature I.E it needs to take in and return an HTTP Handler interface now we can make this function return in HTTP Handler like this we're using the Handler funk in the HTTP package so this takes in a function which itself takes in a response writer and a pointer to the request so the response writer is what you use to construct a response to the caller for example set the response body the headers and the status code the request is what contains all the information about the incoming request for example headers payload and other information about the HTTP requests which came in now in here is where we're going to Define all our Logic for authorizing the HTTP request now we can grab the username parameter from the request pointer by calling r.url.query.get and then the name of the parameter which for us is username we can also grab the auth token from the header like this now if either of these are empty we can return an error to do this let's go back to our API api.go file here let's create a function which we can use to write an error response to the HTTP response writer in other words this function is going to return an error response to the person who called the endpoint we want to make a function here because we're going to reuse this in multiple places in our code when we want to return an error let's call this the right error function so it takes in the writer the message we want to return and the status code we're going to use our error struct and write a few things to our response writer so here we set the content type I.E we want to return to Json the error code like this and finally we write the error struct out which is going to be what the user gets back in the response now we're not going to call this directly in our functions when we want to return an error because we want to have a couple of types of error responses so let's make a few wrappers to this function so this request error Handler is going to take in the response writer and the error we're going to use this when we want to return a specific error in our response this might guide the caller to fix a request so for example if the username wasn't passed in we might want to return a message which says username required or something like that on the other hand we'll use the internal error Handler when we want to return a generic error message for example if the error is a result of a bug in our code we don't need to return a detailed message to the user because it's not all that helpful for them okay so if we go back to our authorization function we can log out the error to the console and then call our new request error Handler passing in an unauthorized error and then exiting the function with return now if we have both of these things we can proceed to getting data from our database and checking the username and authorization token is correct we're going to instantiate a pointer to our database like this using an interface type and call the new database method don't worry we're going to Define all these functions and types later if we get an error back we'll return an internal error in this case now let's actually query the database using the get user login details method then finally if we didn't find a client with a username or the token doesn't match what we got back from our database again we're going to return a request error at the end of this function we need to call the next.serv HTTP method what this does is it calls the next middleware in line or the Handler function for the endpoint if there's no middleware left so in our case this will call our get coin balance function at the end which we'll make in a bit and there's our authorization function let's go ahead and create our database interface now we're going to create this in internal slash tool database.go so first let's Define the types of data our database should return these will look like this so login details and coin details the former contains the auth token for validating the request and the latter has the coin balance now the database interface is going to define a few methods that are required for our API we're using an interface here because we can swap out our databases really easily as long as we Define a get user login details method a get user coins method and a setup database method with these signatures all right now that we've defined our interface and the return types let's create a function called new database which returns this interface inside we're going to create a database variable and set it to a mock DB struct this is a struct we're going to create which is going to implement our interface then we call the setup database method do the standard error checks and return the pointer now let's create this mock database an internal tool slash mockdb.go we'll create a mock DB type and let's create some data here we have some login details data as well as some coin details data now these just represent some fake data and in the real world app this would probably just be stored in some form of database remember in order for this mock DB struct to conform to our database interface we need to create a get user login details get coin details and set up database methods so our two Gap methods we'll just look up the data and the maps we defined above and the setup database function for our mock database just does nothing okay so if we go back to our API Handler we still need to Define our get coin balance function now in order to use this function in this get method we need to Define it such that it takes in a response writer and a pointer to the request as parameters so let's do that as our final step here in the same Handler package let's create a getcoinbalance.go file here we're assuming the call is already ran through the authorization middleware so we just need to grab the username from the parameters passed in the easiest and most go-like way to do this is to decode the parameters into our coin balance param struct which we made earlier we can use the gorilla schema package for this calling the new decoder function so this line is just going to basically grab the parameters in the URL and set them to the values in the struct now in this case it'll just grab the username from the URL and put it into the username field in the struct and the rest of this function is very straightforward so we again instantiate a database interface call the get user coins method set the value to our response structure and write it to the response writer and that's it let's go test our awesome API so if we call our API we get the token balance back for Alex if we enter an incorrect authorization we get a 400 error if we enter in a username which doesn't exist another 400 error we can also query another username like Marie and get back her coin balance as well alright so there we go we just built an API and go with authentication make sure you like And subscribe as I got some new stuff coming out less tutorial oriented but should be a lot of fun I'll see you then
Info
Channel: Alex Mux
Views: 12,672
Rating: undefined out of 5
Keywords:
Id: WQxAm0TMwyY
Channel Id: undefined
Length: 12min 5sec (725 seconds)
Published: Sun Aug 27 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.