Introduction to File Uploads in Go
What's up YouTube? Welcome to another edition of Coding with Robbie. My name is Robbie and in this video, we're going to be covering file uploads in Golang.
So I'm going to be using Gin and I'm going to be giving you two examples. So the first example we're just going to upload to disk and the second example we're going to upload to Amazon S3.
So like and subscribe and let's get right into it.
Initial Project and Gin Setup
So first things first, I'm just going to open up my terminal and I'm going to cd to my Go workspace. And I'll just go inside the folder and make all my projects and I'll create a new folder for my project called upload.
I'm going to cd into that folder and then I'll run go mod init and uh now let's go to the Go documentation or Gin documentation. And I'm just on the quick start guide. I'm going to grab the library right here, and that's going to install it. And then I'll scroll down and check out their example. I'll just paste this in a file called main.go.
So let's open this up in VS Code. And uh, let me create a new file called main.go. Let's paste in that code. And uh, let's run it and see if it's working. So let's just go go run main.go. So it should be running on port 8080. So I'm going to go back here, I'll go to port 8080 and I get page not found. And that's because the only route we have is that /ping and it gives me a pong back. So everything seems to be working.
Configuring Gin for Static Files and HTML Templates
So uh, before we get into the upload stuff, we're going to set up a few Gin configuration things. So let's check out their examples. The first one I want to set up is serving static assets. Uh let's see, let me just search for static, serving static files. And I just add this line right here. So let's copy that. I'll go right down here. Mine is just r. And this just makes anything in the assets folder just, it'll serve it. So let's create an assets folder. So that looks good.
Next up, we got to set up HTML rendering. So let's look for that, HTML rendering. And uh, we add this line right here. So this line just loads all the files within templates, within the templates folder. So let's uh, create that folder. So we've got templates, uh, let's create a file in there called index.html. I'll just do that. And let's put 'Hello World'.
All right. So we're loading the HTML templates and then we're going to serve one of those templates. So let's copy this line right here. I'll get rid of the starting route and replace it with this. Change the route to just slash. Change this to r. So now when someone visits the root path, it should serve our index.html template. And then I don't need to pass any data, so I'm just going to delete that and let's try this out. Let's go here, go to the root path. And we have to restart our app. So let's go back here, Command-C, uh, rerun it. And here we go, we get 'Hello World'.
So now we can start the upload stuff. So the first example I said we're going to do to the disk. So let's do that.
Let's go to our index file and let's create a new form. So let's go form and action, we're going to do just the root path again. For the method this time, it's going to be post since we're going to be sending in our file. And then since we're sending a file, we have to enctype and it's a multipart/form-data. And I don't really know what that means but that's what you got to do for files.
So now let's add our file field. So let's go input type is equal to file. And I'll go name is equal to image. And then let's add a submit button. So I'll just go input type submit. Save that. Let's restart our server. And uh, let's see if it worked. There we go. I got my form right here.
Implementing File Uploads to Disk
So now let's check out file uploads.
So let's see, where is it? Upload files, single file. All right, so it's super easy to upload to disk. So the first thing we have to do is add this configuration line. Uh, so let's go to main.go. And this basically just says, hey, the uh, the max form data size should be eight megabytes. And I think that's a good size, so we'll leave it at that.
And then next up, let's see. So we have a route here. Here's how you get the file from the context. And then here's how you save it. So let's do that in ours. So let's go to our main.go. We're going to add a new route and we're going to do our post route, which matches our form action.
And then let's paste in that line. Whoops, let's paste in this line right here. So let's get the file and it's going to come from, what do we call ours? We called ours image. So let's change this to image.
Whoops. And then this also returns an error which I want to check for. So if air is not equal to nil, let's render the page, but let's pass an error message. So let's go air, fail to upload image. And then let's return so it stops the function.
Alright. So we're getting the file here and now we want to save the file. So let's check out how to do that. We'll go back. And it's this line right here. So let's paste that in. And uh, here we get, we pass it the file, which we got right there. And then dst is short for destination, I think. So we just put a path at where we want it to save. So let's save ours in assets/uploads/file.Filename. Just like that. And file.Filename is just the name of the file so whatever their file is named that they're uploading.
And then uh, I think this returns an error too, yeah. So let's check for that. Let's go error is equal to—and it's giving me a bug, no new variables. So let's just reuse the one we declared up here. And then let's check for it and show the same error if it doesn't work. And then if we get down here, it works.
Displaying the Uploaded Image and Handling Errors
And we're going to render the page. And if it worked, let's uh, let's give this image, and we'll give it a path to the image so we can display it on the page. So let's go right here and let's paste that in right here. I'm going to start it with the slash this time.
Let's see. So, we're getting the file, we're checking for the error, we're saving the file, checking for the error. So we got to create this folder. I forgot to do that. So let's go in assets. Let's create a new folder called uploads. So we're saving the file, checking for the error, and then we're rendering the page and we're passing it um, an image.
So let's go to our template here and above the form, let's go, uh, if .image, so if an image exists, we'll render it. Let's go img src, .image. Uh, let me just fix that. Just like that. That looks good. And then if there's an error, we also want to render that. So let's put that down here. Let's go p... err. And we want to render the error if .error exists.
That looks good. Let's try it out. So we'll go back. I'll just refresh. I got to restart my server. Let me restart it. Okay, go back. I'll refresh. Let's choose a file. I just happen to have a play button right here. Submit. And I get the image right here. So it's working. And if we go to our folder, we can see it uploaded in assets/uploads, and yeah, that's uploading to disk. And just one thing to note is that in a real application, you would probably want to save this file path somewhere in a database just so you can reference it later when you want to display it.
Setting Up an AWS S3 Bucket
Alright, so next up, we're going to cover uploading to S3. So I just went ahead and logged into my AWS account. And what you're going to want to do is go to S3, and then you're going to want to create a bucket.
And uh, for bucket name, let's just go 'coding-with-robbie'. And then I'll leave mine in us-west-1. And then for object ownership, you're going to want to do ACLs enabled. And then right here, I'm going to uncheck this to allow public access. And I'll acknowledge that some stuff might become public.
Scroll down, we can leave all this. Let's go to create. And there we go, we just created a bucket.
Creating an AWS IAM User for Programmatic Access
And now we got to create an access uh, account thing so we can access this in our code. So to do that, just search for IAM and then go right here. And then let's go to users and let's create a new user. So I'll just call mine codingwithrobbie and I want programmatic access. So let's go next. And then we got to add permissions right here. So I'm going to go to existing policies. Let's just search for S3 and I'm going to grant Amazon S3 full access. So let's go next. I'll leave the tags empty, go to review. It looks good. I'll hit create user. And there we go. We got our user right here.
Configuring the AWS SDK and Environment Variables
So let's copy the key ID and the secret access key. So I get the key ID and I'm just going to put it in my code for right now and we'll use it later. So there's the key and then let's get the secret key right there.
All right. So to interact with our bucket, we're going to be using the AWS SDK for Go. So I'll link up this page in the description, but you can come here and just click Getting Started. And then they give us some instructions on how to install it. So we just got to grab these libraries right here. So let's copy this one and we'll paste it in our terminal. We'll get the config one. And then we'll get the S3 service one down here.
And then if you go to configuring the SDK, one thing I want to show is that it's going to be looking for specific environment variables. So we're going to want to set AWS_REGION, AWS_ACCESS_KEY_ID, and SECRET_ACCESS_KEY. So to do environment variables, we're going to use go.env. You can just Google it and you'll find this repo. And they have instructions down here. So let's grab it. And then we just create a .env file in our root with our environment variables. And then we load those variables with the code right here.
So let's copy this and I'll just paste it at the top. And then let's create our .env file. So .env. And we're going to need AWS_REGION. And what were the other two? Let's go back to the documentation. So it's AWS_ACCESS_KEY_ID and uh, AWS_SECRET_ACCESS_KEY. So it said all these are uh, well my region was us-west-1. If yours is different, make sure to put the correct one. And then our access key ID is what we copied right here. So it's the shorter one. And then the secret access key is the longer one. So let's grab that. And there we go, we got our environment variables set up so we can delete these right here.
Implementing the S3 Uploader in Go
And then let's go back to the docs and there's a good example under SDK Utilities, Amazon S3. Here's how you can upload a file right here. So we need one more library. So let's copy the one we didn't get, this manager one. Let's go back to our terminal and we'll go go get and paste it in. And uh, yeah, we're ready to set this up.
So let's copy this code right here and go to our code. We'll go below the environment variables. Let's see... Set up gin app... Load env variables... And we'll create a new section right above the routing called a Setup S3 Uploader. So let's paste in that code we copied. And then let's go back. So once we got the config set up, we create a client with it. So let's copy this. And then with that client, we can create an uploader. So let's copy that line.
And yeah, now we can use this uh uploader within our route to upload to S3. So let's uh, copy the code right here, and let's go down to where we're saving it to disk and we'll just, uh, let's just get rid of all that. Let's paste in this code. result. And we'll call this uh, uploadError. And then we can leave all this. For our bucket name, mine was coding-with-robbie.
So for the object key, this is where we want to save it. So we could go like images/1.jpg or whatever, but we're just going to use our file name. So let's go file.Filename. And then here's where we put the file. So to get the file, we actually have to open uh, the file. So, uh, to do that, let's go up here and open the file.
So let's go f and openError is equal to file.Open. And then let's check for that error. Let's go if openError is not equal to nil, let's render that error page. And then if it is equal to nil, we know the file is opened and assigned to this f. And then down here, we can put the f right here. And then one other thing we want to set is just the ACL and we want to set it to public-read. And this just makes it publicly accessible so we can display it on our website.
So let's check for this upload error now. We'll do the same thing we did above. And then if we get past all this, it should be uploaded to S3. And uh, the location is result.Location. So paste, we'll pass that to image, and it should be working. Let's try this out.
We'll go back to our our page right here. Let me start the app. go run main.go. Whoops. And we have an error. It says uh, this package is in there. So let's go back to our code. And up here, it's actually got to be v2. So that'll fix it if that happens to you. Let's run our code again.
It's running now. And let's try it out. We'll go here. And I'll choose a file, I'll just do uh, this guy. And I'll hit submit. It's going to take a second; it'll upload it. We can see the image is uploaded. And now let's check our bucket. We'll go back here and refresh. And we got the image right there. So it's uploading successfully.
Outro and Final Thoughts
Alright, and there you have it. That's how you can upload to S3. So I hope you enjoyed this video. Make sure to like and subscribe, leave a comment, let me know you're there, and I'll see you in the next one. Peace.
End Screen
[Music] you