REST API with Go / Gin + Some Simple Tests

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

I apologise in advance about the video quality. Looks like screen capture software is more complicated than writing software! If people like the content, I'll re-record it and continue doing more videos.

👍︎︎ 3 👤︎︎ u/apatheticonion 📅︎︎ Mar 18 2019 🗫︎ replies

Thanks for taking the time to put this together! I look forward to seeing more.

👍︎︎ 2 👤︎︎ u/luv2lrn 📅︎︎ Mar 18 2019 🗫︎ replies

I'm at work so I can't watch right now but just based on the title it sounds awesome. I love using Golang and Gin I just wish there were more in-depth tutorials. Especially when it comes to TDD

👍︎︎ 2 👤︎︎ u/SphincterGypsy 📅︎︎ Mar 18 2019 🗫︎ replies

I'm starting my first golang rest API and I'm curious why you picked gin over chi or gorilla.

👍︎︎ 2 👤︎︎ u/futuregerald 📅︎︎ Mar 19 2019 🗫︎ replies
Captions
hello my name is Dave and today we'll be making a web api using go and the popular web framework gin let's get started so the first thing you want to do make a folder and we're gonna call this folder news feeder and as the name suggests it's gonna be an app that helps people post news items and read news items it's just a news feed open it up with your favorite editor in my case that's Visual Studio code but there are plenty of editors available now we have goal and then you take your pick cool we're gonna make a main dog go with a package called main and a function called main in it great now the first thing you want to do when starting a go project actually technically before you make the main go is set up the module and the way you do that is you open up your terminal you you hold on let me figure out the combination so you jump into the folder that you you're working with and in my case it's the news feeder photo and you run a fun you run a command called go mod in it and the name of the project num my case it's news feeder right now what this is gonna do is it's gonna create an index file it's called a mod file and this mod file if you've used nodes like your package lock sorry so your package JSON and it contains an inventory of all of your dependencies also it allows your go compiler to know where your project is indexed with with a root folder of your project is and in our case it's gonna be here next to this main go now the first thing we want to do after that is just make sure it all works we good let's have a look now if we run go run main go we good that's great now what I like to do here is create a make file and in that make file I usually have a rule called div if for those of you that are unfamiliar make is an old new tool and it's sort of like the if you've used again the node example if you use node in your package Jason you've got those scripts this is kind of the same thing allows you to run scripts I'm using commands so I the come on we're gonna run on dev will be go run main go and if we jump into our terminal type in make dev it'll run it doing the same thing as before fantastic okay now gin what's that about let's open up a browser and let me just grab a window all right so if we go to github actually just go to Google you go to google and type in go gin it will pop up with this git repo and in this git repo contains gin now gin is a web framework I'm gonna tie this a lot to node um because it's a familiar place for a lot of developers and so Gina's basically expressed for go now if you use the Express framework and node and you could consider it flask for Python if you're coming from a Python back-end background or probably difficult to make any parallels in languages that I'm unfamiliar with here but essentially it's it's a routing solution that includes things like Jason Marshall a Jason on marshalling like an attack like grabs parameters from your URL it'll do all the convenience things that you would like to see have like like to have out of like an agent pirata so how do we do the installation we copy this go get command obviously just pretty much follow the instructions here you go get gin now it's gonna grab all these dependencies and it is going to add them to our go mod file we've only we personally in this project we only need the gin dependency but it depends on all these other packages or it obviously imports them with that and this is the package lock type concept where it's on it's a some like sort of verifies that all the projects all the dependencies are as other they match their signatures cool now let's let's proceed let's create and there's some basic project so what does the basic project look like it's um it is a it's composed of three main blocks we've got this default statement we declare a route and then we run the project we run the router so what does this all mean Jin you can create a new gem so Jin dot near and that's gonna create a new instance of Jin this jindal default is creating a new Jin except it attaches some middleware it is a logger this on recovery middle where the recovery middleware essentially caches and endpoints should it panic and logger just provides convenient logs to be to the console and actually quite like the aesthetic of these logs I've got coloring and it's pretty cool and what we have is a reference to this gin logger so it's gin Namrata and on the router we declare these routes we have a get request here which is on the ping endpoint and it executes this function when it's hit it's passed this gin context and using the gin context we're able to respond to the incoming request and normally the application would just sort of die this run here prevents that from happening it stops the application from conclude concluding and it starts up the router and make sure that these endpoints are all listening and waiting for requests great let's run this and see what what it all looks like so if we go make dev it spins off the server it you can see here that it's declared that there's a get request on ping and it this function here and if we open up a browser and we navigate to whoops and we navigate to here it is and we go to localhost 8080 because that is the default port it's gonna say nothing because the endpoint is slash ping / ping and it responds with this pong message that's cool right so let's continue now that we've done that we're actually gonna want to start building out the application and actually make it do stuff and in order to do that we need to sort of have a structure in mind and a pattern that I quite like to follow is I will create an HTTP D folder sometimes I'll actually create a CMD folder sorry let me just get out of this mode sometimes I'll create a CMD folder and inside that CMD folder I'll create an HD PD folder and also create like a lambda folder and sometimes I'll create like a CLI folder and these will just be entry points to my application but because we're just making a web server here I can just remove this and we can just say HTTP D and this is gonna contain our actual HTTP server our service is gonna live here and it'll be the orchestrator for the underlying functionality I like to have a folder here called handler and it contains a package obviously called handler and that handle a package is where I'll keep all of my individual endpoints as projects grow in size you can kind of pull this out onto multiple different folders or if it's getting really big you might want to consider a different architecture potentially looking at micro servicing or possibly some sort of better management solution but so far I haven't really seen I haven't really come across a point where I've struggled with this pattern but maybe there'll be a day so now I like to use this naming convention I'll say the route name it's usually in - case and then I'll underscore and then the method name it's just a pattern that I like and you can name it well however you'd like to the reason why I like this is it kind of gives me an indication in the tab up above it's a bit more practical um I can just read it and see and know exactly where I'm at we are in the handle a package we want to create a function and the function I'm gonna call it ping get and it is going to take a gin context and it's going to not return anything because it needs a return it's going to do it Jason with an H HT p dot status okay and it's gonna have a response which is a map with a stroke string string for those of you from a JavaScript background a map of string of string is essentially an object literal where the key is a string and the value is a string so essentially this and if from from a Python background you probably looking at dictionaries that's essentially what this is and we're just going to create a hello how many great so that's this that's this end point and up here we're not gonna remove the original one and we're gonna say handler dot you can get and what we're doing is declaring that this function will be executed when this end point occurs now if we restart this it'll say main doc oh no such file directory and the reason for that is I've moved the file the folder where main doc go lives it now lives under httpd run it again and we'll see that everything is running and if we I really like closing those windows I promise I'll keep this one open if we got a localhost:8080 again slashed ping we're going to hit this endpoint hello found me great now I'm just ashes all over here for later okay cool so what's the next step from here one thing I like to do with these these end points is I like to return a function and anonymous function and that anonymous function takes the Jin context and this function will return a Djinn handler func the difference here now is you must execute the function in order to obtain its return value and the reason why I like to do this is I can pass dependencies into the ping get function and it's sort of available in this closure which is quite nice it's really really good for testing oh look I'll demonstrate how that works later and I'll show you the value there great so the next step here would be this is a news feed type software and what we want to do with this is ensure that people can add news feed items and they can view all of the news feed items I'm not gonna worry about accounts or anything like that and also I'm not gonna be integrating this with a database or any sort of permanent data storage or third-party solution that will help with that I'm just gonna use a slice and I'm gonna leave it in memory to keep this as simple as possible now to achieve this I usually create a folder called platform and this will be where I keep all of my project specific dependencies anything that spans multiple projects say I create I'm a package like that does something like string obfuscation or you know anything with very general functionality that I often use between different services I will take them out of this platform folder and I'll promote them to say github or some sort of central repository where I can use it in multiple projects but for project specific dependencies I like to keep them in this platform photo and in our case we're going to have the newsfeed package inside of platform your speed so go package newsfeed great a package newsfeed it's going to have a type we're going to have a newsfeed item and it's going to be a struct and it's going to contain a title and it's going to contain a post we can add other properties to it like date and stuff but we're not going to worry about that we're going to give it some JSON bindings title there's some metadata to help marshal it between this struct type and the JSON JSON type now we're going to want to make a newsfeed list so type let's call it repo type repo and it's also going to be a struct now the repo struct is going to contain items which is a slice of item to a slice of item now we'll create a function called new and this new function is going to return a pointer to a repo return and repo now the repo I'm going to create a function receiving a pointer to a repo and we're going to call the ad and ad is going to simply add an item to the list of items so what we needed to do is take a item and it will take the r dot items and say that it equals to append our dot items and the item itself so we're going to just simply replace we're gonna append items to this array sorry the slice every time this add function is called and we have another method which we're going to call get all and it will return a slice of items and they will be the value of these items great obviously there's a lot of tech debt with these comments but that's okay we'll leave that for later for when this video is off finished and this effectively describes the you know the data structure that we'll be using this this repository for everything now I'm just gonna remove the HTTP service part of this and we're just gonna in isolation make sure that our news feed is working how do we do that now let's create a news I'll just call feed equals news feed mute now we have this news feed being imported if we go fmz dot print what we'll see on the feed is probably nothing at this point but we want to say feed dot add and we're gonna add a news feed item and in this item we'll just add a couple of values this is the title hello how you doing mate then we will print it again and with any luck we'll see that result so let's clear that and say make dev now we see the news feed is empty and then after our ad gets run we have this hello how you doing getting wrong cool so we can see that our news feed is working what I would like to do is take this a little bit further and actually add some tests to this so let's go a news feed underscore test go and here we've got package news feed we're gonna have a function and this function is gonna be we've got to test each of these individually but really we're just gonna test two things we're gonna test ad and get all the rest is kind of implicitly tested I guess you can really test these but you know you go what I'm saying so I call it test ad and another func called test get all and I can't I can never remember what this was but it's like T and then testing mmm how let me just double check I've got a good reference somewhere else I'll just dig up an old project just remember what type is obviously I don't test enough if I don't remember this but that's okay we have got here we go mmm this is some terrible code from a long time ago pay no attention to the testing behind the curtain and we have these two functions great mm-hmm okay cool so let's do quickly test this ad and how do we test it how do we know that something's been added what we'll do we'll create in your feed so a new feed equals new then we'll say the dot add and we're going to add an item in this case we'll say the item is and cool and here we're going to do the actual assertion we're gonna say if feed dot items no oh yes capital that's right if feed items zero well firstly let's just check which is chicken from you know what we don't even need to add a value to it we don't need to add titles or anything we just see if an item was added at all so you can say if link of length of feed items equals equals zero then we have a problem oops error or item was not added cool and let's say get holes we want to see that it's getting everything what's wrong yeah undefined cool and so same kind of deal we want to create an ear feed we want to add an item to the feed we'll give this one some text or we don't really need to do that now we can say all tained elliptical results all about results and the results will just be a feed dot get all and same kind of question here which can say if the length of the results equals zero then obviously we didn't get the results we didn't get all the results it should he call it should equal one actually really if the results do not equal one and again if the results do not equal one cool now let's test it how does how does testing work we've written these pretty script for tests we can say go test and then we'll say platform platform the news feed and it says okay what I'd like to do is usually I just do it dot I think it's this way what could be other way I've got I've got my reference one sec as I check my other make fall yes it's dot slash dot which will test everything and also we can do something cool which is - cover and it will provide the coverage for the testing so we can see that in our new speed package we're covering 100% of statements without testing ok moving right along then so we've got some testing we've got some you know data stuff now let's add stuff from our endpoints now back at our main logo we have this ping everything's good to go let's create some endpoints we're gonna create a news feed underscore get don't go and we want to add a news feed on the scope post don't go and let's just copy this boilerplate because I don't really want to type it out again and we want to do news feed get and we're gonna do news feed post I think I've made in used to be the single word so I'll just keep it lower case feels wrong but that's okay I think I've misspelled it that's alright so we're gonna have a get news feed and we want to post news feed news feed get news feed post and the skies they post great so now we have these two end points and what do we want to do that well firstly we want to get all of the news feed in this case and on the other one we want to add an item to it now how do we get the data that comes in from this repository how do we put it into these handlers I mean we could we could declare it globally right I guess and then have or like yet have it appear by global scope possibly or we could do something weird like we can create some bootstrapping logic elsewhere like create some bootstrappers and have them return like singleton values or or something like that my personal preference is I like to simply declare the dependency here in my main go where I would create a news feed down here it's gonna say it's not being used and then I would like I usually just pass it into the places that that are using it so in this case we've got news feed get news feed post day both obviously not taking it just yet but I will pass in a feed of type news feed thought item as things need to be the list have I mistaken something I perhaps this doesn't automatically import it no okay something signs up what's up mmm oh let's see have I named something weird I've named it a news feed repo fancy cool and same deal here so these both take these news feed repos and they're generated when the application bootstraps from the application itself loads these dependencies are created typically I'll do the same thing with the database I'd create I'd establish my database connection and then I'd have sort of my DB variable here which I then pass in to the functions that require database access I'll do the same thing for like anything that that that was a shared dependency and it's typically only things that are shared dependencies that I would do with this level something that's that needs to be kind of at that global level cool so we pass in the feed and this is our get and what do we want to do with that what we want to do is get the results we'll get the results and the results are going to be made up of the feed dog get all now we pass in this get all and it's going to return it's going to create this response as JSON response and it's gonna be made up of these results and on the other side we've got this post now the post a little bit more complicated because we obviously need to take a body a request body and to do that the first thing we want to do is declare what the what the response is gonna look like also what the request is gonna look like and I typically just use the name of the method of the the function which I use to define the method and say that plus request title post this has the same signature as the newsfeed item but that's okay sometimes it might be sometimes it might not we're going to annotate this with some information to tell the marshal marshaling system where to find the properties and how to map them to these values okay cool so we've got this request struct which we've defined now in the request itself what we're gonna do is say we're going to create this news feed post so I'm gonna say request request body and the request body is a as one of these guys and you one of them now CDOT find this is a method available in the air it is in Jin so if we go to the Jin yeah cool if we go to the Jin documentation we can look up post I'm sure the word post must appear on us oh I see it's not even the documentation ko ko ko' that's fine uh-huh there should be some documentation somewhere around here well we can see examples are all documentation is available in these languages hectic and from here we can probably dig up like how to deal with post information anyways you use this bind method to bind your request body to the incoming request essentially what it's doing is saying I'm creating I've created struct now let's call these two properties and bind the incoming request the property is in the incoming request try to map them and bind them to the values and in the struct if they if there are more values in the request and they are on the struct they'll be ignored if there are less these will be set to their zero values which are in this case string and in post okay so we've we've bound this request body now what we want to do is add the news feed item and how do we do that firstly we when we need to create a item and what's an item made of it's a news feed dot item and its title is going to be the request body dot title and it's post is going to be the request request body dot post now we've created this item the next thing we want to do is say B dot add add this item to the feed and down here we want to return something just to say that it that it happened so I'm gonna return a status I'm not gonna worry about a body and the status code is going to be no content so this will return a to a full response which is yeah it means that there's no body but all is well good job cool so that's my news feed post endpoint great let's let's have a look let's see what this looks like running now if we go make dev runs we have the service running now let's check out oh there it is let's check out newsfeed newsfeed says null now why does it say null the reason it's saying null is because when we create a newsfeed item when we create a repo it doesn't instantiate any items inside of this list so what I actually have to do is manually declare the items inside of the constructor function for the repo now when I restart this and come back to it refresh we have an empty array just a little bit so it's a little bit more readable cool now let's test a post I guess that's pretty much next step now if we open up the inspector or I'm just gonna quickly do some JavaScript weight fetch and the endpoint we created was news feed the method is a post the headers we have oops we have one header and that header is content type and the value is no application slash Jason and the body the body is a string of fide JavaScript object and the object has two properties it's got a title and it has a post and the title is hello and the post is world cool now we get a 204 status response if we take a look at the logs we can see that we've had a a post request newsfeed let's just expand this codes kind of ugly we've got a post request to newsfeed and it's given us a 2 a 4 if we refresh this page we can see that we now have one result hello world now if we do that multiple times we can see multiple entries so it seems to be like everything is now adding and we have this the service now that's running it's adding items of this repository which is sweet great now the only thing left to do to improve this is to start using interfaces on the on the function parameters for these news feed gets and news feed post functions now how do we do that now in my news feed package I'm going to define two interfaces type getter interface and it's going to have one method called get all and we're going to define another one called adder interface and it's gonna have a single method on it called add now the getter has a signature where it where it's method of get all will return in a slice of items and the adder will simply take one item now these interfaces they you can use these as function parameters and we're gonna do that here in the newsfeed items so what we say is we have a feed now the feed is no longer going to be a type of pointer to a repo instead what we're gonna do is it's going to be a news feed getter how does this work because this function is only ever using this get all function I'll just get all method on the feed and this interface it describes itself as having only have as only having one method and that method is this getall method returning a slice of items then feed having only that one method is usable in this context because we are only ever using feed to use it for its get all method now it doesn't explain this interfaces and explain anything about its behavior like we're not talking about how it creates anything but what we are doing is defining what it does and because the feed itself being passed in as a parameter it satisfies the requirements for this interface that requirement being it just needs a method on that does get all returns a slice of items because it satisfies that signature the compiler won't throw any errors it'll say this is a valid input for this function good to go and the same thing we'll do on the other side here with the post will say we will remove the pointer to a news feed repo and we'll change it to a news feed adder and because again we're only using the add method in this function we have this add up now a really cool thing about this is let's say today I have this I'm using this in memory database to store my news feed items the secret the only thing that these two functions these get and post functions the only thing they care about is that the thing that via their being passed and matches the signature of these interfaces that they have a get all and an ADD then let's say tomorrow I decide hey look you know what I'm gonna implement dynamodb or I'm going to implement PostgreSQL something else suddenly I can implement those those technologies and as long as the inputs that I provide to these functions still satisfy these same interfaces the underlying mechanism by which I use to store my items it doesn't matter doesn't matter to these two these functions they just take a generic interface and those interfaces define what the function requires in order to be satisfied cool another cool thing about these interfaces is they provide us with the capability of simply mocking the dependencies so rather than so that same example where I would say let's say I built this from the beginning using MySQL and in order for me to test this functions handle function I would actually need to spin up a you know instance of MySQL I'd need to populate it with some data then I'd have to start doing some testing based on that that proceeded data what interfaces allow me to do in this case is I can actually rather than using the MySQL database I can just use an in-memory replacement like this News Feed thing that I've already made I can because it satisfies these interfaces these interface signatures because it matches them I'll be able to use a drop in in-memory replacement and use that as my mock for the database being provided as a function parameter so it's another power of using interfaces in the context of this sort of thing cool thanks thanks for sitting around and listening and and hearing what I have to say about go I hope was useful if it wasn't that's cool if it was great if you have anything you want to add please feel free to leave a comment if you saw something you thought I could improve on please I feel free I'd love to hear what you have to say in addition if you want me to do any videos on any particular subjects feel free to ask as well I'm gonna extend this in the future with another subject with another video talking about how to integrate react with this and then possibly another video how to integrate angular with this and maybe even one on just integrating native web components without any framework whatsoever but going on let me know what you want to see and thanks please
Info
Channel: David Alsh
Views: 53,082
Rating: 4.9460316 out of 5
Keywords: Go, Golang, Web API, REST API, RESFUL API, Programming, Coding, Go Gonic, Gin Gonic, Go Gin
Id: LOn1GUsjOF4
Channel Id: undefined
Length: 38min 52sec (2332 seconds)
Published: Mon Mar 18 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.