1

I'm having a problem. When I make too many requests from browser or postman rightly the API (slowapi) blocks me as I have correctly set, but if I make a request via AJAX and jquery's $ .getJSON, the APIs don't block me. How can I solve? My code (extracted from the complete code):

from fastapi import FastAPI, Request, Response, status
from fastapi.middleware.cors import CORSMiddleware
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded
from slowapi.middleware import SlowAPIMiddleware
limiter = Limiter(key_func=get_remote_address, default_limits=["2/5seconds"])
app = FastAPI()
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)
app.add_middleware(SlowAPIMiddleware)

@app.get('/schools/{regione}/{provincia}/{comune}')
def search_school(request: Request, response: Response, regione: str, provincia: str, comune: str):
    if(request.headers.get("Provider") == "Test-User-Provider"):
        return {"message": "OK", "status": "success", "code": 200}

    else:
        response.status_code = status.HTTP_400_BAD_REQUEST
        return {"message": "Provider not found", "status": "error", "code": 400}

Browser result (WORK):

{"error":"Rate limit exceeded: 2 per 5 second"}

Jquery code (NOT WORK):

$.getJSON(apiURL+"/schools/Test/Test/Test", function(data) {
        console.log(data)
});

Obviously with jquery I tried to make a lot of requests per second Console browser result (Not limited!):

{message: '...', status: 'success', code: 200}

Request not rate-limited

A thousand thanks.

UPDATE Through jquery I tried to make requests to other paths and it is correctly rate-limited. If I make the request to this path /schools/{region}/{province}/{municipality} the rate-limit does not work

UPDATE 2

I refer the updated and tested code. When I send a request to path /testpath /{region} it is correctly rate-limited. If instead I send a request to some sub-paths (/schools/{region}/{province}/{municipality} it is not rate-limited.

The jQuery code is the same as listed above

from fastapi import FastAPI, Request, Response, status
from fastapi.middleware.cors import CORSMiddleware
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded
from slowapi.middleware import SlowAPIMiddleware

limiter = Limiter(key_func=get_remote_address, default_limits=["2/5seconds"])
app = FastAPI()
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)

origins = ["http://127.0.0.1/", "http://localhost", "http://192.168.1.75"] ## CORS

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)
app.add_middleware(SlowAPIMiddleware) ## Rate-limit all request

@app.get('/schools/{regione}/{provincia}/{comune}')
def search_school(request: Request, response: Response, regione: str, provincia: str, comune: str):
        return {"message": 'No schools found!', "status": 'error', "code": 200} ## Or if found return schools informations

@app.get('/testpath/{regione}') ## Works with one path. If I add "provincia" and "comune" non work
def search_school(request: Request, response: Response, regione: str, provincia: str, comune: str):
        return {"message": 'No schools found!', "status": 'error', "code": 200} ## Or if found return schools informations

If i use schools path: enter image description here

If i use testpath it's correct rate-limited: enter image description here

Matteo
  • 118
  • 2
  • 12
  • The URL in your `getJSON` call doesn't match the URL path used in your example; have you actually limited the endpoint you're calling? Are you actually getting data _from the endpoint_ and not being terminated by a dependency? – MatsLindh Feb 17 '22 at 20:21
  • no sorry, I wrote wrong now I correct it. However all requests are limited with middleware – Matteo Feb 17 '22 at 20:23
  • Since the `status` entry is error - are you sure your request even passes? Is your view function _actually_ invoked? (attach a debugger or do a print statement) - that something gets logged doesn't mean that it was actually invoked. – MatsLindh Feb 17 '22 at 21:58
  • Everything works correctly the same request that the I do it as a jquery or I do it as a browser, it returns what I want. the problem is with jquery that it is not rate limited which happens correctly with browser. In the console it prints me the requests I make and what I get back. – Matteo Feb 17 '22 at 22:15
  • the status response is personalized and I decided it myself. – Matteo Feb 17 '22 at 22:16

1 Answers1

1

Tested your code and works fine, as long as you replace the closing double quote with a straight double quote " in the getJSON() method:

$.getJSON(apiURL + "/security/validate_token", function(data) {
        console.log(data)
});

Above you wrote "the status response is personalized and I decided it myself". So, if you still get a {message: '...', status: 'success', code: 200} response, I would suggest you try returning a simple message instead, e.g., return {"status": "success"}, and see if that works as expected. If not, it might be something not implemented in the right way in your custom response.

Update

The below should work as expected. If it doesn't, then the issue likely lies elsewhere in code that is not inlcuded in your question. I would also suggest to add it as a tempalte to your app, as from the error you posted you seem to be getting Cross-Origin warnings.

<!DOCTYPE html>
<html>
   <head>
      <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
      <script type="text/javascript" >
         function on_click(){
            $.getJSON("http://127.0.0.1:8000/schools/Test/Test/Test", function(data) {
                 console.log(data)
            });
         }
      </script>
   </head>
   <body>
      <input type="button" value="submit" onclick="on_click()">
   </body>
</html>
Chris
  • 18,724
  • 6
  • 46
  • 80