Introduction of IP Rate Limiting
The video demonstrates how to implement an IP-based rate limiter in a Go web application. It uses an in-memory caching strategy to track request counts per IP address.
Using Otter for In-Memory Caching
The implementation relies on Otter, a high-performance Go caching library. It enables efficient in-memory storage without adding external infrastructure components.
Avoiding Circular Dependencies
The rate limiter middleware is placed in the routes package to prevent circular dependencies. This ensures proper architectural separation while maintaining access to route definitions.
Cache Configuration
A cache is initialized with a maximum size of 1,000 entries and a 10-minute expiration time. The cache maps IP addresses (string) to hit counts (int32).
Rate Limiting Logic
For each request, the client’s real IP is retrieved from the Echo context. If the IP is not present in the cache, it is added with an initial hit count of one.
Enforcing Request Limits
If the number of hits for an IP is below the limit (10 requests), the counter is incremented. If the limit is exceeded, the user is redirected to the login page with an HTTP “Too Many Requests” status.
Middleware Integration
The rate limiter is registered as middleware in the router. Since it follows the required Echo handler signature, it can be added alongside other middleware functions.
Next Steps
The video concludes by planning to implement authentication middleware and integrate it into a complete authentication flow.
OK, let's add the IP rate limiter. And to do that, we will be using Otter, which is a high-performance caching library for Go that uses in-memory caching. And this is a really great project. And it's perfect for what we're going to be using or what we need to be using. It's also great if we want to cache our pages at one point or want to cache certain files. All of this can be done with Otter. And since Go is so memory efficient,
This is a really good starting strategy. We don't really spend a lot of memory resources when using Go. So there is typically sufficient amount of memory in place for us to use something like an in-memory cache. And we can always extend it or implement something else if we need to.
Other is a great starting point for caching, and it also removes or doesn't add any more components to our setup, which is also very important to consider when building these kind of things. So we'll be using other to implement our rate limiter. So we will go in here into our routes folder and
We need to create this in the routes package simply because we want to be referencing our routes from the routes package. And if we create another package and we then reference the routes in the middleware and then reference the middleware in the router, but also the routes in the router, we get a circular dependency chain, which we cannot have in Go. So we are going to be creating them in routes because they technically belong together.
So create a middleware.go file package routes. And then we create a function here called IP rate limiter. It's going to be a function with no arguments that returns and next echo handler funk or takes in service. Next echo handle funk and also returns and echo handler funk. Exactly like we did in for the
for the register flash context, right? Same signature. And in here, we can create the cache. So this will get run when it first initializes. And we say, other, must, must. And then we provide some options. And we are using v2. And we need to get it and add it to our go.mod file. We restart. Great. So we want to set other.
options, and this is generic, so we can specify that we're going to set a string, which is going to be the IP address, and then the size or how many elements can be in the cache. Right. Then we say maximum size, which is going to be 1,000. So we're specifying that the, you can see here the V is going to be of type N32, and we specify just 1,000 that can be in there at one time.
Then we set this expiry calculator. The other expiry creating is going to be string in 32. And we set this to 10 time dot minutes, right? So that the elements in this cache will expire after 10 minutes.
Let me say to turn and then funk. And we have this signature that should be familiar now from the flash episode. We will say IP and then we will grab it from the echo context. On echo context, they have this real IP method. So hits, okay. Check the cache we just created and say get if present, pass in the IP.
if it's not okay, meaning we do not have the IP in the cache, we will say cache.set. Use the IP and pass one. So it just associates the value if it's not already, the key is associated with the value, and if the key is already
associated with a value if we return the existing value on false wide so that should make sense and then we simply just return to the next the next function in line of this wavequest chain then we say if hits is below there we don't have we say
We are gonna be saying, what do we have here? We need the limit, right? So the limit is gonna be 10. So if hits is below 10, then we say cache.zip and then hits plus one. So up here we check if it's present, if it's not present, then we set the first instance and set the value to one, right? So we have one cache hit.
And then down here, we check how many hits we have. So on the first attempt, this will be one. This is below 10, so we increase it. Then we say hits is above the limit. Then we return R. We will return the, let's just return R redirect and then say HTTP status.
to many requests, and then we redirect to the route we actually haven't created yet. So we're going to redirect to the login page. Let me just create a route for that. So log in page. And just going to be to slash login. So we redirect to log in page. Great.
And if nothing of those are true, then we just return next and pass AC. All right, we create a cache. We set the maximum size to be a thousand. We set the expiration to be 10 minutes. Then we check the incoming request as IP. We check if that IP is present in the cache. If it's not, we create an instance in the cache with the IP as the key and then the value of one. We check the
Hits is below 10. If they are, we increase the number of hits this IP has. If it's above 10, then we redirect to the login page with status too many requests. Great. And this is our rate limiter. And now we can go into our router here and we can add it. So let's just, for example, with the admin, it's not going to be on the admin, but we can say routes IP rate limiter. And we don't need to
I mean, you call it right because we return the middle of a function and you can see here they have this M where we can provide as many equal middle of functions as we want. So this is just technically accepting a slice, but this is just another way. There's three dots here to specify that we can pass in multiple functions that matches the signature. Great. Next, let's create the
the off only middle work with cookie and then add everything together so we have a proper authentication flow.