mirror of
https://github.com/AnimeThemes/animethemes-server.git
synced 2026-07-11 01:24:46 +02:00
refactor(graphql): improve graphql rate limiting (#1162)
This commit is contained in:
+1
-1
@@ -175,7 +175,7 @@ FORTIFY_URL=http://localhost
|
||||
# graphql
|
||||
GRAPHQL_URL=
|
||||
GRAPHQL_PATH=/graphql
|
||||
GRAPHQL_RATE_LIMIT=90
|
||||
GRAPHQL_RATE_LIMIT=135
|
||||
GRAPHIQL_ENABLED=true
|
||||
|
||||
# hashids
|
||||
|
||||
+1
-1
@@ -173,7 +173,7 @@ FORTIFY_URL=http://localhost
|
||||
# graphql
|
||||
GRAPHQL_URL=
|
||||
GRAPHQL_PATH=/graphql
|
||||
GRAPHQL_RATE_LIMIT=90
|
||||
GRAPHQL_RATE_LIMIT=135
|
||||
GRAPHIQL_ENABLED=true
|
||||
|
||||
# hashids
|
||||
|
||||
@@ -41,49 +41,49 @@ class RateLimitPerQuery
|
||||
$ip = $forwardedIp;
|
||||
}
|
||||
|
||||
if ($query) {
|
||||
$rootFields = 0;
|
||||
|
||||
try {
|
||||
$ast = Parser::parse($query);
|
||||
|
||||
foreach ($ast->definitions as $definition) {
|
||||
if ($definition instanceof OperationDefinitionNode) {
|
||||
$rootFields += count($definition->selectionSet->selections ?? []);
|
||||
}
|
||||
}
|
||||
} catch (JsonException|SyntaxError) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
$hits = max(1, $rootFields);
|
||||
|
||||
$key = sprintf('graphql:%s', Auth::id() ?? $ip);
|
||||
|
||||
foreach (range(1, $hits) as $_) {
|
||||
if (RateLimiter::tooManyAttempts($key, $limit)) {
|
||||
$retryAfter = RateLimiter::availableIn($key);
|
||||
|
||||
return new JsonResponse([
|
||||
'message' => 'Too Many Attempts.',
|
||||
], 429, [
|
||||
'Retry-After' => $retryAfter,
|
||||
'X-RateLimit-Limit' => $limit,
|
||||
'X-RateLimit-Remaining' => RateLimiter::remaining($key, $limit),
|
||||
'X-RateLimit-Reset' => now()->addSeconds($retryAfter)->getTimestampMs(),
|
||||
]);
|
||||
}
|
||||
|
||||
RateLimiter::hit($key);
|
||||
}
|
||||
|
||||
return $next($request)
|
||||
->withHeaders([
|
||||
'X-RateLimit-Limit' => $limit,
|
||||
'X-RateLimit-Remaining' => RateLimiter::remaining($key, $limit),
|
||||
]);
|
||||
if (! $query) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
$rootFields = 0;
|
||||
|
||||
try {
|
||||
$ast = Parser::parse($query);
|
||||
|
||||
foreach ($ast->definitions as $definition) {
|
||||
if ($definition instanceof OperationDefinitionNode) {
|
||||
$rootFields += count($definition->selectionSet->selections ?? []);
|
||||
}
|
||||
}
|
||||
} catch (JsonException|SyntaxError) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
$hits = max(1, $rootFields);
|
||||
|
||||
$key = sprintf('graphql:%s', Auth::id() ?? $ip);
|
||||
|
||||
$current = RateLimiter::attempts($key);
|
||||
|
||||
if (($current + $hits) > $limit) {
|
||||
$retryAfter = RateLimiter::availableIn($key);
|
||||
|
||||
return new JsonResponse([
|
||||
'message' => 'Too Many Attempts.',
|
||||
], 429, [
|
||||
'Retry-After' => $retryAfter,
|
||||
'X-RateLimit-Limit' => $limit,
|
||||
'X-RateLimit-Remaining' => RateLimiter::remaining($key, $limit),
|
||||
'X-RateLimit-Reset' => now()->addSeconds($retryAfter)->getTimestampMs(),
|
||||
]);
|
||||
}
|
||||
|
||||
RateLimiter::increment($key, amount: $hits);
|
||||
|
||||
return $next($request)
|
||||
->withHeaders([
|
||||
'X-RateLimit-Limit' => $limit,
|
||||
'X-RateLimit-Remaining' => RateLimiter::remaining($key, $limit),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ use App\GraphQL\Schema\Types\Base\PaginationInfoType;
|
||||
return [
|
||||
'domain' => env('GRAPHQL_URL', env('APP_URL')),
|
||||
|
||||
'rate_limit' => (int) env('GRAPHQL_RATE_LIMIT', 90),
|
||||
'rate_limit' => (int) env('GRAPHQL_RATE_LIMIT', 135),
|
||||
|
||||
'route' => [
|
||||
// The prefix for routes; do NOT use a leading slash!
|
||||
|
||||
Reference in New Issue
Block a user