Comments (7)
Hello,
from my point of view, there should be support inside the library. May be I'm wrong, but I think it is quite common use-case to have different caching policies for different queries in combined query. I can ask in one query for both "static" and "dynamic" content. For example: Give me currently logged-in user (dynamic) and main menu items (static).
Caching inside controller is unable to cope with this. Could middleware be able to do this caching of one query and avoid caching of another?
from graphqlite.
Hey @pascalwacker ,
Indeed, a special annotation like @Cache is something that could be done.
We added the ability to add custom annotations in GraphQLite 4: https://graphqlite.thecodingmachine.io/docs/next/field-middlewares
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.
The main problem is that if your query returns objects, those objects must be cachable. If you put these objects in cache, you have to put the dependencies of the objects too (and the whole object graph that could be queried through GraphQL). I soon realized that serializing the objects to put in cache is the real hard part.
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?
from graphqlite.
@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?
from graphqlite.
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?
from graphqlite.
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.
I need a way to set caching policy (whether to cache or not, expiration time) based on parsed query - different queries have different expiration and caching. I'm unable to do this inside controller.
Maybe some caching middleware would be ideal for this task?
from graphqlite.
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;
}
}
}
from graphqlite.
@cuchac I think we should add a property to the Query
and Mutation
annotations, similar to Symfony's Route
annotation with stateless routes:
https://symfony.com/doc/current/routing.html#stateless-routes
from graphqlite.
Related Issues (20)
- First party support for `void` return type HOT 3
- Please, publish a new version HOT 1
- Extension packages are unmaintained or don't support latest features HOT 11
- doctrine/annotations should be upgraded to v2 HOT 2
- Mutability concerns HOT 5
- Cleanup and deprecate confusing annotations HOT 2
- New patch version HOT 3
- Mapping multiple php object representations for a single resource to one graphql ObjectType HOT 4
- Automatic query complexity HOT 1
- Empty request body parsing error for automatic persisted queries HOT 14
- prefetchMethod does not work HOT 12
- Arguments description in schema HOT 3
- Undocumented Error or posible dead code HOT 3
- ExtendType and Type with class argument don't work
- Defining fields in type by trait from different namespace ends with error for relative type declarations HOT 2
- Weird behaviour around __call HOT 1
- Cannot use custom naming on an Input type that's also a regular Type HOT 3
- How to debug errors? HOT 2
- Bizarre `Cannot query field "settings" on type "...".` error HOT 3
- Security attribute on extended type HOT 5
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from graphqlite.