Alrighty, now for the long requested article of…
Who am I kidding? No one reads these things. I just like writing about random shit.
Anyway. I was working on my random anime website recently. I completely re-wrote my back-end code, which is in PHP, to act more like an API. It’s nothing fancy, I just restructured the files to make it feel more API-y. And, they are in a directory called “api”. Boom. Official.
There’s only one problem: the URLs are ugly.
Instead of something clean like “api/anime/get/”, it looks like “api/anime/get.php”. Gross.
So, how do we make it look pretty?
The .htaccess file, and mod_rewrite.
What The Heck Are Those?
My…ninja info cards.
No?…No one?…Alright, I’m old.
The .htaccess file is something you can create on your server that can control how pages are accessed. You can allow, deny, redirect, all sorts of shenanigans. What we are going to focus on, mostly because I don’t understand any of that other stuff, is a module called mod_rewrite. This module allows you to create rules for rewriting the URL, which is how we are going to make our API look all pretty.
Just throwing it out there, I’m not an expert on this stuff. The only experience I have is a lot of Googling and the fact that this works on my website. Proceed with caution.
The Rewrite Rule
The first thing we have to do is turn on the rewrite engine. Doing this is pretty simple, all you have to do is add the following line to your .htaccess file. If you don’t have an .htaccess file, you can create one.
RewriteEngine on
Done. Simple.
This lets our server know that we are going to be doing some sweet URL rewriting. Just to review, we are wanting our ugly URL of “api/anime/get.php” to look like “api/anime/get/”. To do that, we need the browser to be able to match our pretty URL, and point it to the ugly one. We’re going to do that with a regular expression.
Let’s do it.
RewriteEngine on
RewriteRule ^api/([a-z-0-9/]*)/$ /api/$1\.php [L]
That’s not too scary, right? Let’s break this down.
The URL To Match
After we declare “Rewrite Rule”, we have a regular expression “^api/([a-z-0-9/]*)/$”. This regular expression is looking for our pretty URL, from earlier. Here is what each part matches:
- ^api/ – URL, after the domain, starts with (^) the string api/ (api/)
- ([a-z-0-9/]*) – After api/, match any lowercase letter (a-z), hyphen (-), number (0-9), or forward slash (/), any amount of times (*)
- /$ – Ends ($) with a forward slash (/)
You may be wondering, what are the parenthesis for? Anything within those parenthesis will stored to use later in the rule. Think of () as storing anything inside it in a variable.
The URL To Point To
For the second part, we have “/api/$1\.php [L]”. This is the file we want our server to point the matched URL to. In other words, our pretty URL is what matches in our regular expression, and we want to point that toward our ugly URL.
Let’s break it down:
- /api/ – This is a static string, it means what it means
- $1 – This is telling our server to place whatever matched in the earlier parenthesis here; ie. printing a variable
- \.php – A period is a special character, so we have to escape it with a back slash, so it reads .php
- [L] – A flag that means no more evaluations, we done
If we put it all together, we are telling our server “Hey, if someone navigates to /api/anime/get/, that URL should read/output the file at /api/anime/get.php”.
At this point, if it’s not working, your server may not have the mod_rewrite module, in which case, you need a smarter person than me.
Expanding On The Rule
Our rule works! Yay!
If we try to navigate to “/api/anime/get/”, we should no longer get a 404, but instead see the output, whatever that may be, from the file “/api/anime/get.php”. We could, honestly, leave it there. There’s no harm in that. However, if you accidentally omit the trailing forward slash, you’ll get a 404. That’s no good. Let’s fix that real quick.
RewriteEngine on
RewriteRule ^api/([a-z-0-9/]*)([^/])$ /api/$1$2/ [R=301,NC,NE,L]
RewriteRule ^api/([a-z-0-9/]*)/$ /api/$1\.php [L]
Above our previously written rule, we have a new one. Let’s check out the differences:
- ([^/]) – The caret, when inside brackets, acts as a negation operator. That means, this will match if the trailing forward slash is missing
- $1$2/ – Remember the parenthesis earlier? Well, there are two sets now, so there are two variables, $1 and $2
- [R=301,NC,NE,L] – A whole bunch a flags, honestly, I don’t understand. The important one is R=301 which equates to a 301 redirect
Now, if our URL is missing the trailing forward slash, it matches the first rule, which ends in a 301 redirect. The redirect goes to the same URL with an added trailing forward slash.
Alternatively, we could make our original rule have an optional trailing slash, that way it matches either way and we avoid a redirect. I’m not entirely sure how to do that, which is why I did it this way.
Conclusion
There you have it. All of this writing for three lines of an .htaccess file. I hope that I’ve explained everything properly, and I’m not sending people into a pit of misery. As I mentioned before, I’m not an expert. This is a problem I came across, and my solution for it. I can only hope it’s helpful to someone out there.
Thanks for sticking it out this long.