Adding the Database

Slugs and Human Readable URLs

Summary

In this video, I explain what a slug is and why we use it. A slug is a lowercase, dash-separated version of a title that provides SEO benefits, improves user experience, and helps with analytics. I demonstrate how to implement article creation with slugs in our codebase using SQL and Go. I show how to use the go-slug package for generating slugs, and implement data validation for new articles. I also set up error handling with a grouping error approach to validate fields like title, filename, and excerpt. Finally, I mention that in module six, we'll focus on authentication and setting up the dashboard.

Transcript

All right, so I've been using the word slug in the last few videos, but I haven't really touched upon what it is. And to explain this, let me just jump into our old metadata on our articles here in content. Let's just check article one. And if you jump down here to this slug field, we see article dash one. Now, this is not really how a real slug would look like. It would probably be more like my first article. So a common thing that you will see is that you take the title and then turn it into a slug. You can use whatever you want. I like to use title. So a slug is literally just all lowercase, and then instead of spaces, we have dashes. So this becomes a lot more descriptive of what we are accessing, what is the resource we are accessing. And it also provided some benefits in terms of SEO, search engine optimization, right, where search engines prefer descriptive URLs. We can also add keywords into our URLs, which improves our search rankings and makes our content more discoverable. The user experience becomes better. They are easier or they're more likely to understand the links that they are clicking. It looks more professional. It's easy to remember and share, right? Also, if we add something like analytics to our website, we have more meaningful insight into the traffic that we receive and what pages our users visit. The alternative to this is just to provide the ID. Let's say we use a UUID that is a long string of numbers, right? That is not so easy to understand. It also, you know, it's just a bunch of numbers. And if we were to look in an analytics screen, seeing a bunch of IDs, we would have to go in and, like, find those IDs to know what it is that they are looking at. So there are some SEO benefits. There are some user experience benefits. There are also some analytics benefits. So this is the main reason why we use Slugs. Now, let's jump into actually creating articles and do some data validation all through our models layer. All right, so we start in our psql package, jump into our articles.sql file, where we will create a new statement called insert article, and we're going to return one record. And I'm just going to copy paste the query statement here. So this is pretty standard SQL. We just have some Postgres-specific syntax, and this is the way you specify arguments or inputs in Postgres. So we specify the columns we want, and then sqlc will take these values here and turn it into a struct that we can then pass to the function that gets generated. Now, notice here that we use one, so we return the inserted record instead of returning many, as we did up here. We can also opt for saying something like exec, remove the returning here, turn this here, and now we would just, the function would just return us an error if there are any, and then we can react to that. I like to return the inserted rows whenever I do insert statements, but the other one is just as feasible. Now we can go ahead, jump into our terminal, and say sqlc compile and generate. And with that run, we can go into our models, articles here, and you can see we now have this insert article params. We have this insert article function on our query struct. So we are basically ready to start inserting articles into our database. But before we do that, I want to add a package, this go symbol slash slug package here that just take care of everything related to generating slugs. So we just pass this a piece of text and it will transform it for us, so it makes our life a bit easier. Add that to the go.mod file. And then finally, we can go into our models and our articles file here. And I'm just going to add a struct here that is going to be called new article payload that just specifies the data that we need to create an article. You could also accept ID and create it at updated at all of that for here. But since we are dealing with this on the model layer anyway, I just, I tend to deal with it in the function, right? But if you want to, you know, feel free. Next, I'm going to create a function here called new article. And this will also take in the context and the db.dbtx as we did with the get latest articles with the addition of the payload, right? And that will return us an article or an error. And I'm just going to grab a bunch of code here because we're not really doing that much new here. We are just calling the insert article function that we just created. And then we transform the data that we receive into whatever pdx, which is the library that we use to handle all of the database stuff expects. They have some internal types. For example, if you look at the created at here, it is a pd type timestamp that we didn't, you know, we create here and we just pass the time.now whenever this function was called, we generate a UUID, we pass the title, file name, everything. So pretty straightforward. The only thing is that we use the package that we just added and we call make, which will, you know, generate a slot from the provided string. And we use English as a default. So this is looking all good. We just need to go up here and say, we want to use version five from the pdx package. And then we insert the article and then transform it back into the data structure that we have defined using the standard libraries data types. So pretty straightforward. What I want to do next is I want to do some data validation. I want to make sure that we only insert articles that fulfill the requirements that we have for a valid article. So that's what we're going to do in just a second. All right, so to handle validation, we also need to pass back or return some errors that we can react to higher up in the chain. So for example, you know, handles or controllers, when we recall the models, we need some sort of way to check what went wrong, what specifically went wrong. So we can return the correct error message or correct view to the user. So we are going to start out by creating a new variable here called error invalid payload. And this one is going to act as sort of a grouping error. And I'm going to explain that in just a second, what I mean by that. So yeah, errors.new, you're going to say provided payload did not pass validation. Give that a save. And now in here, in our new article function, we can go ahead and check for the data we got passed. For example, I want to make sure our title for the article is not an empty string. So we check here, is it empty string? If it is, we're going to return an article, just an empty article. And then we're going to say errors.join. And errors.join just accepts a bunch of errors. So we're going to start first with saying error invalid payload. Then we're going to say errors.new title cannot be empty. There we go. Give that a save. Oh, in order to prevent this, give that a save. Now in the handlers or controllers, we can then check for if this error is present and then return a message back to the user saying like, hey, you know, you need to provide us with a title. And this is where this grouping error comes in because then we just check for this error and then we just pass in the other, the message here that something went wrong, right? Or what specifically went wrong. And I want to repeat this for two other fields. I want to make sure that our file name is also not empty. So we just update the explainer error. And again, for except here also cannot be empty. And the message is except cannot be empty. And now we have some basic validation. We make sure we have a title file and except. We have a grouping error that we can check for. Okay, this is what went wrong. And then we can use this extra, like explaining explanatory error that, okay, the title cannot be empty. Or in this case, except cannot be empty and show that to the user. One more thing we have to handle here is also the fact that we could have an error with inserting the article into the database. And right now we're just returning the error, but I want to use the same concept to say here, var error DB insert, errors new could not insert record into database. And then here we literally do the same. We say errors join, say error DB insert, and then pass the error, right? So now we have some basic data validation. We're going to be reusing these errors when we start to add users and subscribers so that we have a general idea of what went wrong and then we can react to it as we need. Now we still need to provide a view and controllers that allows us to actually pass some data and create articles. And this is going to be the focus of the next module where we are going to be adding authentication. We're going to be adding a dashboard that only we can access and start to manage our articles through there. So this is basically what inserting records through models look like. And then, yeah, in the next module, we'll be focusing on getting authentication and the dashboard setup, login, all of that. So yeah, see you in module six.

Early Access

$95 $65 USD

Get access

Invoices and receipts available for easy company reimbursement