Now that we have the functionality to add images from Unsplash to our canvas, let's go ahead and let's implement file uploads. So for that, we're going to be using something called Upload Thing. So go ahead and Google upload thing and create an account. Once you've created an account go ahead and create a new application. I'm going to call this image AI and I'm not going to change anything else.
Go ahead and create your application. After that let's go inside of API keys and let's copy these two. So you can simply click copy, go ahead inside of your .environment.local file and simply add those two. You should have the upload thing secret and the upload thing app id. Now let's go ahead and let's look at the instructions on how to set this up.
So I'm going to click on the documentation here and I'm going to select the Next.js app router like this. First of all, let's install the packages. So we need upload thing and add upload thing slash react. I'm using bun, so that's what I'm going to copy right here. Let's go ahead inside of the terminal.
I'm going to shut down my app and I'm going to install those two. There we go. Let's run bunrun-dev again and we've already set up our environment variables. What we have to do now is we have to create this endpoint app.api.uploadthing.core.ts and we have to copy this example right here. We're going to slightly modify it.
Let's go ahead inside of our source folder here inside of app API so we're not going to be using the route here we are going to be using upload thing and inside of here we're going to be using core.cs So go ahead and copy this entire file and paste it inside. There we go. So inside of here you can see we have a lot of comments. So let's go ahead and let's slightly modify this. So the fake out function can actually stay the same for now.
But I want to remove all comments simply because I'm going to, you know, it's pretty self-explanatory so I prefer it this way. There we go. It's much cleaner for me now. So I'm only going to leave the fake out function here. And I'm going to slightly modify the our file router here.
So, inside of here, I'm going to add a to-do. Replace with next out. So we currently don't have actual authentication so this actually won't work right so right now every user will be authorized because we are mocking this out function, right? So the user will always be an object with an ID because we tell it to be that right here. In real example, once this becomes actual authentication, If there is no user we are gonna throw an error like this.
And now we have to modify the onUploadComplete. So what we write and return in the onUploadComplete is what will be returned on the client. So inside this we can go ahead and do the following. We can simply return the URL file dot URL. So if you're wondering why did we actually have this metadata for example.
So if you want to in here in the future you can for example store file in the database with user id. So that's what you would use the metadata.user id for example. But we're gonna keep it simple and we are just gonna return back to the front end the URL of the file which is uploaded so that we can easily display it in our canvas. So if you don't want to copy this from the documentation you can pause the screen and write it out or you can also simply take a peek in my source code and copy it from there. Great!
So we have our file router ready. Let's take a look at what we have to do next. So now we have to create a Next.js API route to actually use the file router. So in the same folder, so API upload thing, we now create a route.ts. So far we created core.ts inside of the API folder but now we are adding route.ts.
Let's paste this inside. There we go. ./.core gets the our file router with our image uploader right here and we can remove the comments for everything else. There we go. So we are handling the get and the post methods.
Perfect. Now that we have that let's go ahead and let's add upload thing styles. So we are using Tailwind so we are not going to use this. We are going to be using Tailwind. So let's go inside of our tailwind.config.ts and let's go ahead and let's import upload thing, Sorry, with upload thing from upload thing slash TW representing Tailwind.
And what we can simply do is go to the end here and wrap with UT with our config like this. There we go. So that will prevent any overrides or you know global bugs with Tailwind so it's important to actually add this with UploadThing from UploadThing slash tw here and save your Tailwind config. Great And now let's go ahead and let's create Upload Thing components. So inside of here I'm gonna go inside of Source, lib and I'm gonna create upload thing dot DS and I'm just gonna copy these and paste them.
We don't have to do a slight modification here so in their documentation they use this curly little line as the alias, but we are using the at sign. So we change this to at app API upload thing core. And in here we are getting access to our file router, which we've defined. And then using that, we create type safe components like upload button and even upload drop zone if that's something you will want to use in the future. And great we can now go ahead and actually mount a button.
So let's go ahead and let's go inside of our image sidebar. I'm going to go ahead and I'm going to upload, I'm going to import the upload button. So import, upload button. From at slash lib slash upload thing so make sure you've imported it from here and not from upload thing react, right? So this upload button has all the types necessary which we define here in our file router for example it can specify that we are only allowing images with a maximum file size of 4 megabytes and it also has the instructions for the errors and it also has the API structure about what we return, right?
So that's why we want to use this upload button. You can see how it knows the metadata and it also knows all the errors, the output, it knows everything. So that's the one we want to use. Now let's go ahead and let's actually use this button. So we're gonna go and find where our toolbar, our tool sidebar ends.
And then we're gonna create a div here and let's go ahead and give this div a class name of padding4 and border-bottom and let's simply render the upload button. We're gonna go ahead and give this an endpoint which will very simply be our autocomplete image uploader like this. So that's why we have to use that component because it can read this file router. So if I renamed this to image uploader2 I would have to change the endpoint here as well. So that's the cool thing about upload thing is because it allows us to have our own API for handling this kind of stuff.
Great. And now I'm going to go ahead and add on client upload complete. And in the response here, I'm simply going to call editor, add image, response first in the response dot URL so you can see how it has URL because in on upload complete we return the URL. So if I change this to test, for example, the URL actually will not exist, I believe, right? So let's just go ahead and return it like this.
There we go. So now we are sure that the URL will exist. Perfect. And I just want to add a couple of slight modifications here. So the appearance of the button will be full width, text small and font medium.
And the allowed content will be hidden. Content prop will have modifications to the button element, which will say upload image. And I think we might be ready to try this out now. Let's go ahead, go inside of the editor. And let me just refresh this.
So I've shut down my server, so I have to wait a bit and there we go. Let's go ahead and upload an image here. Let's wait a second and after it's been uploaded it should be added right here. There we go. So in case you were not able to upload your image and instead you got an error that you have to add something to your next config similar to the error we had when we tried to render an image from Unsplash, here's what you have to do.
So go inside of your next config.js right here and you simply have to copy and paste these existing remote patterns and change this hostname, well, to whatever your error will say, but I assume it will be utfs.io, like this. So That's something you have to add as well. Great.