Research
Security News
Quasar RAT Disguised as an npm Package for Detecting Vulnerabilities in Ethereum Smart Contracts
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
A library for normalizing and denormalizing GraphQL responses
When working with GraphQL, caching on the client side can be very important in order to achieve good performance. One of the most popular approaches is to use a normalized cache. Frameworks such as Relay and Apollo do a good job of providing a normalized cache without exposing the client application to the details of normalization or denormalization. For some applications, abtracting away the cache like this is a good fit. For other applications you may want more control over the cache. Using the gql-cache library you will have full control over the cache and you can make the cache a first class citizen in your appliction. For more information also read the motivation and normalization and denormalization sections.
npm install gql-cache --save
Here is a small example:
import { normalize, denormalize, merge } from "gql-cache";
import { request } from "graphql-request";
// Our cache is a plain JS object
let cache = {};
// Make a request to fetch the data
const response = request("{ ...Your graphql query here... }");
// Normalize the response
const normalizedResponse = normalize(query, response);
// Merge the normalized response into the cache
cache = merge(cache, normalizedResponse);
// Later when we want to read a query from the cache
const cachedResponse = denormalize(query, cache);
// cachedResponse now has the response for the query and we can return it without a server request
The normalize() function takes a GraphQL query with associated variables, and a GraphQL JSON response. From those inputs it produces a normalized cache which is returned as a plain JS object.
normalize(
query: GraphQL.DocumentNode,
variables: { [key: string]: any } | undefined,
response: { data: any },
getObjectId: (entity: any) => string
): { [key: string]: any }
The denormalize() function takes a GraphQL query with associated variables, and a cache object (as returned by normalize()). From those inputs it produces a GraphQL JSON response.
export function denormalize(
query: GraphQL.DocumentNode,
variables: { [key: string]: any } | undefined,
cache: { [key: string]: any },
staleEntities: { [field: string]: true | undefined } | undefined
): {
response: { data: any } | undefined;
partial: boolean;
stale: boolean;
};
When you normalize the response of a query you probably want to merge the resulting cache object into a another, large cache object that is held by your application. Since a cache is just a JS object you can do this merge any way you want but the merge() function is provided an optimized convenience to do the merging of caches.
Since gql-cache is a library rather than a framework, it just provides functions for normalization and denormalization that your application can call when it so chooses. This enables some scenarios that are hard to do with the framework approaches that abstract away the cache. For example, your application has full control over the storage and upate of the cache (the cache is just a plain JS object). So you can store the cache in Redux and update it with Actions, or store it somehwere else and use a different update mechnaism. It is entirely up to your application. Also, for performance critical applications, your application is free to make optimizations based on assumptions that are specific to your application. Such optimization can be hard to achieve in frameworks that have to cater to many different kind of applications. So for some applications this library-based approach might be better than the aformentioned framework approaches, but of course it comes with the tradeoff that your application will have to know more about the cahce and do more work itself. You can of course write your own components to abstract the cache in any way you want in your application.
In order to understand this library, it is important to understand the process of normalization and denormalization. A basic description of normalization (in the context of graphql-cache) is that it takes a tree and flattens it to a map where each object will be assigned an unique ID which is used as the key in the map. Any references that an object holds to other objects will be exhanged to an ID instead of an object reference. The process of denormalizaton goes the other way around, starting with a map and producing a tree. The popular normalizr library does a good job of explaining this. In fact, gql-cache is very similar to normalizr, but it was specifically designed to work with GraphQL so it does not require hand-coded normalization schemas. Instead it uses GraphQL queries to determine how to normalize and denormalize the data.
Here is an example with comments that show how the data gets normalized:
import { normalize, denormalize, mergeCache } from "gql-cache";
import { request } from "graphql-request";
// Our cache is a simple JS object
let cache = {};
// Define our GraphQL query
const query = gql`
query TestQuery {
posts {
id
__typename
title
author {
id
__typename
name
}
comments {
id
__typename
commenter {
id
__typename
name
}
}
}
}
`;
// Make a request to fetch the data
const response = request(query);
/*
The response now looks like this:
data: {
posts: [
{
id: "123",
__typename: "Post",
author: {
id: "1",
__typename: "Author",
name: "Paul"
},
title: "My awesome blog post",
comments: [
{
id: "324",
__typename: "Comment",
commenter: {
id: "2",
__typename: "Author",
name: "Nicole"
}
}
]
}
];
}
*/
// Normalize the response
const normalizedResponse = normalize(query, resopnse);
/*
The normalized data now looks like this:
{
ROOT_QUERY: {
posts: ["Post;123"]
},
"Post;123": {
id: "123",
__typename: "Post",
author: "Author;1",
title: "My awesome blog post",
comments: ["Comment;324"]
},
"Author;1": { id: "1", __typename: "Author", name: "Paul" },
"Comment;324": {
id: "324",
__typename: "Comment",
commenter: "Author;2"
},
"Author;2": { id: "2", __typename: "Author", name: "Nicole" }
}
As we can see in the normalized response above, an ID was assigned to each object.
References between objects are now using these IDs.
*/
// Merge into the cache
cache = merge(cache, normalizedResponse);
// Later when we want to read a query from the cache
const cachedResponse = denormalize(query, cache);
// cachedResponse now has the response for the query and we can return it without a server request
FAQs
A library for normalizing and denormalizing GraphQL responses
The npm package gql-cache receives a total of 40 weekly downloads. As such, gql-cache popularity was classified as not popular.
We found that gql-cache demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 7 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.