-
Notifications
You must be signed in to change notification settings - Fork 100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature Request: Caching on the server #125
Comments
Hey @pascalwacker , Indeed, a special annotation like @Cache is something that could be done. It should therefore be relatively easy to cache the query (and compute automatically the cache key from the method's parameters as you suggest). That being said, there are a few caveats. In my project, I found out it was actually way easier to add caching at the HTTP middleware level. Basically, I'm parsing the GraphQL query before GraphQLite is even started and I'm caching the query and the result. The result if a JSON string so I'm 100% sure it is cachable. Of course, your mileage may vary though. I'd be curious to know what you think? Don't you think caching at the middleware level might be easier in your case? |
@moufmouf is this something that still needs to be considered? Are there any real advantages to adding this to GraphQLite over just manually handling your caching in your query logic? |
Hello, |
What's the overall object here for caching? I'm assuming it's mostly around eliminating unnecessary database queries? If so, this is something you should handle with your ORM. Is the building out of the output types/fields for a query really that intensive for you to need to cache those? |
OK I have another use-case. I have web app and want to load all data from GraphQL endpoint. With decent traffic I have to use some caching technique. To initialize graphqlite library, parse query and serialize let's say 50 objects in each request is too much work to handle the load. I can cache on controller, I can cache on CDN (my prefered solution) I can cache on proxy. |
Here is a request body parser that you can use. We use this for parsing requests in order to determine some of our authz. We use this as part of the middleware. But, you could use it in a controller via another service and the request object. /**
* Parses the request body JSON and populates the request object's parsedBody property
*
* We're checking to see if the body has already been pre-parsed, as is happening with the upload
* handler middleware. It needs to add the uploadedFiles to the request. The funny thing is that
* it's using an "operations" key. So, we're just getting rid of it essentially and using the "query"
* key, since that's all we really need out of this right now anyway.
*
* @see https://github.com/Ecodev/graphql-upload/issues/7
*/
public static function parseRequestBody(ServerRequestInterface $request): DocumentNode
{
$parsedBody = $request->getParsedBody();
if (!$parsedBody) {
$contents = $request->getBody()->getContents();
$parsedBody = json_decode($contents, true);
if ($parsedBody === false || json_last_error() !== \JSON_ERROR_NONE) {
throw new BadRequest(json_last_error_msg() . ' in body: "' . $contents . '"');
}
}
$operations = $parsedBody['operations'] ?? null;
if ($operations) {
$decoded = json_decode($operations, true);
$query = $decoded['query'] ?? null;
} else {
$query = $parsedBody['query'] ?? null;
}
if (!$operations && !$query) {
throw new UnprocessableEntity('GraphQL request must include query param');
}
try {
$document = GraphQLParser::parse($query, [
'noLocation' => true,
]);
} catch (\Throwable $e) {
throw ExceptionConverter::convert($e);
}
return $document;
}
$document = Helper::parseRequestBody($request);
// If any field is not in our nonSecuredOpreations array, require Auth
foreach ($document->definitions as $definition) {
if (strtolower($definition->kind) !== 'operationdefinition') {
continue;
}
foreach ($definition->selectionSet->selections as $field) {
if (!in_array($field->name->value, $this->nonSecuredOperations)) {
return true;
}
}
} |
@cuchac I think we should add a property to the https://symfony.com/doc/current/routing.html#stateless-routes |
So, I think a better approach here is persisted queries, which has been implemented: https://graphqlite.thecodingmachine.io/docs/automatic-persisted-queries |
Hi, I was wondering, if it would be possible to add caching on the server side using i.e. Redis.
As far as I can tell it should be possible to implement your own caching in a controller, that's tagged with a
@Query
annotation, however you'll have to be careful, to get all the parameters for the cache key.What I was thinking about, was to be able to register a cache pool with graphqlite and then telling it by a
@Cache
annotation, to cache the queries (or possible something like@Query(cache=true)
). If nothing else is specified, I'd suggest to simply use the request url along with all parameters as cache key and a default cache time of 1 hour.Through a config file you should be able to adjust the default cache time plus by setting a
@Cache(time="xxx")
parameter in the annotation. Additionally I'd add a parameter to that annotation to either include or exclude certain parameters from the cache key, as for example the preference for the UI (list view/table view) for a list gets sent along but doesn't influence the query results, so devs should be able to exclude these parameters.Do you think this is doable and if so do you see any gains from implementing such a system?
The text was updated successfully, but these errors were encountered: