Lesson Description

The "Creating the Go Project" Lesson is part of the full, Complete Go for Professional Developers course featured in this preview video. Here's what you'd learn in this lesson:

Melkey scaffolds the Go API project. The main.go file starts the application, but most of the application logic will be in the app package or other sub-packages to keep the application modular.

Preview
Close

Transcript from the "Creating the Go Project" Lesson

>> Melkey: And I'm actually going to get out of that previous directory we have, because here I would like us to start the go project, okay? So this is going to be us now working and creating the go project again from scratch, following this similar pattern, or quote, unquote style of the previous one. But I'm not gonna just write a bunch of stuff in main and delete and rewrite, delete and rewrite. We are actually going to be building out the product structure. So I just want to kind of emphasize that all that beginning stuff that we just did will help us create the project as we move forward right now. And there's also gonna be new stuff that we didn't cover in the beginning section, but that's gonna be expected, especially when we spin up an HTTP server. We didn't cover HTTP servers at all, right? We covered maybe underlying data structures, but now we're gonna kind of just utilize those into what I hope to be a more applicable side of writing go, okay? So let's start. So go ahead and make a new directory, mk directory, I'm just gonna say, Frontend Masters will do project. I'm gonna cd into this project. And for the go mod init, I'm gonna leave it up to you. If you want to the full implementation of, let's say, github.com/the author name/the project, fem, and I'll just do Project. Go ahead and do this, right? If you wanna make it shorter, it's gonna be easier. I'm gonna go ahead and do the full length here, okay? So if I create this, now we have our new go.mod, and then I'm gonna do touch, oops, touch main.go
>> Melkey: Okay, in our main.go file, let's quickly just put our package main and then func main, and then get our compiler to stop yelling at us. The first thing, and I just alluded to this earlier, is we're not gonna bog down our main.go. You wanna keep it as slim and as simple as possible. Now, that's not a hard rule of thumb, there's gonna be certain cases where you just need to instantiate a bunch of things you may not go, that's completely fine. But your main.go should be just the entry point to application. And then you're other data structures that house the rest of your app should be responsible for other functionalities that are the core implementation of whatever you're building. So in that, let's go ahead and make a new directory in the root of our project now, I'm gonna call this internal, all right? And within internal, we're gonna make a new folder called app. In this folder, I'm gonna stop referring to them as folders. I'm gonna start referring to these as packages, okay? Within app, let's make a new file called app.go. Okay, here we'll make and declare our new package app, and this app is going to be housing our application. So when I say housing, the first thing I want us to start to think about is data, okay? When he says housing, okay, data. And then the second thing is, how are we gonna handle data?. And whenever you ask that question of how you're gonna handle data in go, the first question or answer you should have is, do I need a struck? Does this package need a struck, yes, no. In our case, our app package, the responsibility of this app package is going to be having a bunch of resources that we can use throughout our application. And because we're gonna be passing this around, a struck is a viable solution here. So we're gonna do type, let's just call it Application, it's gonna be a struct. And the first thing I'm gonna put is gonna be a Logger. So let's just go ahead and create a Logger. We're gonna use the built-in Logger library, which you can use if you go up here. Let's do import and let's just do "log". And here it's going to be a pointer to log.Logger.
>> Melkey: And with a shrug, I didn't show this in the previous example, I like constructors. I like the theme and I like the purpose of a constructor. And I think for certain structs, a constructor makes a lot of sense. So here we're gonna create our first constructor. We're gonna do func capital NewApplication, all right, and this is gonna return two things. It's gonna return a pointer to application, and a potential error, okay? And here we're gonna instantiate our logger. So here we do log.New, okay? We're gonna have all of the message from a logger go to our standard output. So we're gonna use os.Stdout, okay? If you have go pls setup, you should get the built-in auto import. If not, make sure that you are bringing the OS package at the top. The order does not matter between this and the log import. Okay, the second order is to be blank, so don't really care about any of the semantic styling of log. But what we do wanna add to our logger is timestamps. So what we can do is log.ldate. I'm gonna pipe this with log.ltime. I mean, every time we use any of the methods built into our logger, like printing, failing, error printing, we'll get the timestamp from our logger as well. Next we're going to declare our app. So this is gonna be a reference to our application. I'm gonna do logger like so, and then we're gonna do return app and nil. What is the logger doing? We're going to use the logger as opposed to format print line across our application. So this is gonna be a more structured way for us to understand what's happening in our backend system. And for us to properly diagnose maybe error print statements or just things that we need to kind of dig deeper and use print debugging.
>> Melkey: Okay, so a few things I wanna quickly mention here. So one, we are returning a pointer to application and an error type. This is the first time we should be seeing the error type in our code. And you can see my return type, I have app and nil. So nil are valid error types, okay, they satisfy the interface for an error. So you can put nil, that's gonna be good, okay? As for the app itself, you can see here I have the ampersand cuz I'm pointing to the memory of an application. If I remove this, a compiler yells at us, right? If you want to solve this, you can just move the pointer that we're responding with or returning with, to be more exact. But here, because we're gonna be modifying our application and using it. And I also typically strongly recommend that if you know the data structure of your app, I'd recommend using a pointer to that struct. So here we have our application, okay, and right now it's simple functionality is to create a new app for us. Next, in internal, I'm not gonna write anything here, but to make a new package called routes. And then within routes, we do routes.go and all I'm gonna write here is package routes, cuz if you don't, your code's not gonna compile. That's all we're gonna do for now, okay? And then back in our func main, we are going to do a couple of exciting things. So first, we're not gonna change any of the signature of the func main cuz we can't, but what we are going to do is create and instantiate our app struct. So here let's do an import, and this is gonna be where we import something from our package, our own project here. If you need a reminder of what your modules is called, the go.mod is kind of the equivalent of the package.JSON for those of us who are familiar with web dev. Go.mod has the name of your module here. It will also have the version of go that was used to spin up, so the go mod init. And as we bring in different imports through our project, those direct and indirect projects and imports will be listed in the go.mod. So here, I'm gonna go back to my main, I'm gonna import the name of my module against a Github melkeydev femProject. And in here, I'm gonna route it to internal/app, like so. And if you wanna confirm that it worked correctly, you should be getting this error message, imported but not used. If it says it cannot find the import, you may have some sort of mistake going on between your module name. Don't forget the internal part, I do that sometimes. Here we're gonna instantiate our app. We're also gonna explicitly check for the error, even though we know at this time that error is always gonna be no. We're gonna do app error as the app name. So app, I'm gonna do new application.
>> Melkey: Okay, here we'll say, if err != nil. We're going to PANIC. So this is the first introduction to PANIC. Now, PANIC and go is exactly how it sounds like, it's gonna PANIC and completely wipe and cloche app. It's self-destruction, it's going to exit the application with a fatal error message. We reserve PANIC in situations where it should never occur. And if it does, stuff has hit the fan and we need to in our app deservedly should turn off or break. You don't use PANIC if there is a foreseen potential for an error or a controlled error statement, because it will crash your application. So in this case, we should never see our app. The kind of first step in our application, we spin this up, error out. If we do, then we know we can continue our app, we know if there's an error in getting our application struck, that the rest of the app is gonna probably fault as well. So we have this PANIC here on purpose. It's a keyword, and it has some pretty powerful use cases that we can use, okay? Next thing I'm gonna use app. I'm gonna use that logger property, so .logger. I'm just gonna do a print line, and all I'm going to write is, "we are running our app" like so.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now