Introducing Dependency Injection in Controllers
The controller is refactored into a struct that accepts dependencies, specifically a database connection. A constructor function initializes the controller, enabling scalable and maintainable dependency injection.
Controller Struct and Constructor Pattern
A Controller struct is created with a database dependency, and a New function returns an initialized instance. This pattern allows additional dependencies like caching or locking to be added cleanly in the future.
Reusable Render Helper Function
A helper render method is implemented to reduce repetitive rendering logic. It renders a template component into a buffer and sends the resulting HTML response with an HTTP 200 status.
Refactoring the Home Controller Method
The home handler is converted into a method on the controller struct. It retrieves articles using the injected database connection and uses the new render helper to return the home view.
Updating Router and Application Wiring
The router is updated to use the new controller struct instead of standalone functions. The main.go file is modified to instantiate the controller with the database dependency and pass it into the router.
Application Execution and Result
After wiring dependencies correctly, the application runs successfully. The home page renders properly, though no articles appear yet because none have been inserted into the database.
We got our models now and we got our views. But to actually showcase the data from the database interview, we need to pass it through the controller. And we also need to make sure that our controllers can accept dependencies in a clean and maintainable way, which is also known as the dependency injection or DI for short.
All right, let's begin by adding a controller struct so we can have some dependencies live on this struct. So you're gonna go into controllers, and we're gonna create a struct called controller. And we're gonna say this needs a dependency that's gonna be database just dot psql. And then also a new function to initialize this struct.
It's going to be accepting the database.psql struct. Going to be returning our controller. Return controller. And we passed the dependency. There we go. So this pattern scales really, really well. We can add the caching, locking, and any other dependencies that we might need, simply by just adding onto the struct and then wiring in here, and then expose
the actually controller functions we have now as methods. So they have access to all of these dependencies. Now I also want to add a render function because we are doing some repetition here. So let me quickly create a new function here called render that takes in the echo context and a temple component that we're just gonna name t.
and returns us an error. And in here, we're gonna create a buffer, TimbleGetBuffer. We also need to import TimbleGetBuffer. We're gonna defer TimbleReleaseBuffer and pass the buffer. Then we're gonna say ifError equals to tRender, and we're gonna pass the requestContext and the buffer.
And if we have an error, we are simply gonna be returning this error for now. But if there's no error, we're gonna say E and HTML. We're gonna pass HTTP status. We have status okay, okay. And this string value from the buffer.
Yes, so all this does is simply take a terminal component like our home view and render it into a buffer and send it back to the browser as HTML. And we simply keep this as a helper because it's something we will do quite a lot. And it's going to be looking a bit cleaner. So a small detail, but it makes a difference in the end when we have to type this over and over. Finally, we can go up and update our home
home function, our home controller. So we're going to start by making it our method on the controller struct. And we actually need to rename this one. Let's just call it EC for echo context. And you also need to update it here. And you can see we have an error here because this model function expects the database connection to be passed. So we're going to pass ECDB.
This is the connection setup in the database package. And then down here, instead of doing all of this, we can simply say render, easy, views, home, and then pass the articles and close the preferences. And now we are actually able to showcase articles in our home view.
Now we will deal with the article view and all of the related data fetching in the next module. So I'm just going to be covering this out. And now we don't have any more errors in the controller package. OK, so now we need to update our router. So if we go into router, we can see we now have an error because the controller package no longer exports these two functions, home and controller.
So let's pass in the new controller struct we just created, and let's shorten this to CTRL, controllers, controller. Let's comment this out, because again, we are dealing with this in the next module. And then we can simply say CTRL, home. Now,
The only thing left is to update our main.go function, because we need to pass the controller struct to the router struct, and then we can actually run our application again. All right, so I'm in the main.go file here, under the command slash app.vectory, and we can see our router here expects the controller struct. So let's create this quickly and say CTLs, controller, controllers new, and
We can now use this variable up here past the database and then past controllers. And we can actually now go ahead and run our app. So if we go in here and say just run, we should actually be able to go into the browser and see our application once more. And here we have our not so great looking block. You can see we have the section outlined with the styles we have added and
We have no articles because we have not inserted any articles yet. We will do that in just a second, but everything is working now. And once we actually add articles, we will see them showing up here in our home page view.