Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
A set of React hooks to work with GraphQL data. `magiql` stands on the shoulders of massive giants in the data-synchronization and state-management space, both conceputally and some as actual dependencies. It uses the amazing [`react-query`](https://githu
A set of React hooks to work with GraphQL data. magiql
stands on the shoulders of massive giants in the data-synchronization and state-management space, both conceputally and some as actual dependencies. It uses the amazing react-query
library as its data-fetching and synchronization layer which forms the foundation of this library. Seriously, without react-query
, this won't be any good. The API is also very similar to react-query
and will be familiar to the users. It's just slightly tweaked to make it easier to work with GraphQL. It then brings in the Relay compiler and recoil
to add normalized caching and the useFragment
hook to bring a delightful and highly productive authoring experience.
Most of the features that we are providing are thanks to react-query
and relay-compiler
. magiql
merely tries to be an orchestrator between these great tools.
Using the relay-compiler
(via magiql/babel
or magiql
cli) is required to unlock some more awesome features,
recoil
, react-query
)useFragment
hookNote: You don't need a Relay-compliant server to get all these features in magiql
. It will work with any GraphQL server. It also doesn't require you to commit to React Concurrent Mode which the new relay
hooks require.
There is an example for this: https://magiql.vercel.app. You can see the components and pages folder for example code.
Warning: This is still in alpha stage and docs and examples are in the works
import {
GraphQLClientProvider,
GraphQLClient,
useQuery,
graphql,
} from "magiql";
const client = new GraphQLClient({
endpoint: "https://swapi-graphql.netlify.app/.netlify/functions/index",
});
const People = () => {
const { data, status, error } = useQuery(
graphql`
query PeopleQuery($limit: Int) {
allPeople(first: $limit) {
edges {
node {
id
name
homeworld {
name
}
}
}
}
}
`,
{
variables: {
limit: 10,
},
}
);
if (status === "loading") {
return <div>Loading...</div>;
}
if (error) {
return <div>{error.message}</div>;
}
return (
<div>
{data
? data.allPeople?.edges?.map((edge) => (
<div key={edge.node.id}>
<b>{edge.node.name}</b> ({edge.node.homeworld?.name})
</div>
))
: null}
</div>
);
};
const App = () => {
return (
<GraphQLClientProvider client={client}>
<People />
</GraphQLClientProvider>
);
};
To install magiql
with all its features to your project, run the following commands based on if you use yarn
or npm
. The single dependency includes multiple entry points to code-split features and not require user to install more dependencies.
yarn add magiql graphql
# or
npm install magiql graphql --save
This is required to use fragments and normalized caching
To use the relay-compiler
, add magiql/babel
to your Babel config as a plugin, eg. in babel.config.js
. The magiql
Babel plugin is just a wrapper around babel-plugin-relay
to include everything in one dependency. It also runs the relay-compiler
in watch mode by default.
module.exports {
presets: [ ... ],
plugins: ["magiql/babel", ... ]
}
Or, you can run the compiler from cli using the magiql
command (use magiql --watch
for watch mode, recommended for development). This is also just a wrapper around the relay-compiler
. You still need to add the Babel plugin, but can disable running the compiler with Babel, but setting runWithBabel
to false
in magiql.config.js
.
magiql.config.js
If need to customize the Relay compiler away from the defaults (specified below), add a magiql.config.js
file in the root directory. It is very similar to relay.config.js
, but tailored a little for magiql
.
module.exports = {
schema: "./schema.graphql",
src: "./",
artifactDirectory: "generated",
extensions: ["ts", "tsx", "js", "jsx", "graphql"],
quiet: false,
watch: boolean,
runWithBabel: true,
language: "typescript",
include: ["**"],
exclude: [
"**/node_modules/**",
"**/__mocks__/**",
`**/generated/**`,
];
}
With GraphQL, the biggest game changer when used with React are fragments. The useFragment
hook introduced by relay
makes it delightful to declare the data needs of your components. These are some of the advantages:
relay-compiler
generated files)// Person.tsx
import React from "react";
import { useFragment, graphql } from "magiql";
import { Person_person } from "generated/Person_person.graphql";
export function Person({ person }: { person: Person_person }) {
const data = useFragment(
graphql`
fragment Person_person on Person {
name
homeworld {
name
}
}
`,
person
);
return (
<div>
<b>{data.name}</b> ({data.homeworld?.name})
</div>
);
}
// People.tsx
import React from "react";
import { useQuery, graphql } from "magiql";
import { PeopleQuery } from "generated/PeopleQuery.graphql";
import { Person } from "./Person";
export const People = () => {
const { data, status, error } = useQuery<PeopleQuery>(
graphql`
query PeopleQuery($limit: Int) {
allPeople(first: $limit) {
edges {
node {
id
...Person_person
}
}
}
}
`,
{
variables: {
limit: 10,
},
}
);
return (
<div>
{data
? data.allPeople?.edges?.map((edge) => <Person person={edge.node} />)
: null}
</div>
);
};
import { GraphQLClientProvider, GraphQLClient } from "magiql";
import { createRecoilStore } from "magiql/recoil-store";
import { People } from "./People";
const client = new GraphQLClient({
endpoint: "https://swapi-graphql.netlify.app/.netlify/functions/index",
useStore: createRecoilStore(),
});
const App = () => {
return (
<GraphQLClientProvider client={client}>
<People />
</GraphQLClientProvider>
);
};
These features and accompanying restrictions provide an excellent authoring experience that almost seems magical when it works.
Using the Relay compiler, magiql
can generate types for all your operations since it has access to your schema as well. These types are generated and updated by the compiler, so ensure that it's running in watch mode (either through Babel or the cli) when you are developing.
If the name of query is HomeQuery
, then import type as such:
import { HomeQuery } from "generated/HomeQuery.graphql";
import { useQuery } from "magiql";
const { data, error } = useQuery<HomeQuery>(graphql`
query HomeQuery {
currentHome {
name
}
}
`);
artifactDirectory
in magiql.config.js
(Default: generated
).language
to javascript
in magiql.config.js
.type HomeQuery = {
response: {
currentHome: {
name: string;
};
};
variables: {};
};
Coming soon
Coming soon
To fully unlock fragments, including optimistic responses and cache manipulation of entities, we needed a normalized cache of our data. We call this cache, the store
in magiql
.
GraphQLClient
via the useStore
option, we provide three implementations of our own (using recoil
and react-query
's QueryCache
)getDataID
to these stores to control how id's are determined and then let magiql
handle the rest for managing access.import { GraphQLClient } from "magiql";
import { createRecoilStore } from "magiql/recoil-store";
const client = new GraphQLClient({
endpoint: "...",
useStore: createRecoilStore({
// optional, by default it uses the `id` field if available otherwise falls back to an unnormalized id
// this is the default function
getDataID: (record, type) => (record.id ? `${type}:${record.id}` : null),
}),
});
createRecoilStore
id
for each entityQueryCache
as store createNormalizedQueryCacheStore
createRecoilStore
createQueryCacheStore
Relay allows us to use fragments in queries and mutations without importing them as modules. For this to work, the names must be globally unique. It is also good habit to name the fragments and queries based on the components and props that use them. Thus, relay enforces a few conventions when it comes to naming your operations. These conventions are quite helpful and make your lives easier:
query ${ModuleName}Query { ... }
, eg, a query in file Home.tsx
can be named HomeQuery
or HomeRoomsQuery
mutation ${ModuleName}Mutation { ... }
, eg, a mutation in file Home.tsx
can be named HomeMutation
or HomeDestroyMutation
fragment ${ModuleName}_${propName} on type { ... }
, eg, a fragment in file HomeDetails.tsx
where the prop for the fragment ref is home
can be named HomeDetails_home
You can use the magiql
Devtools which are inspired by react-query-devtools
as follows:
import React from "react";
import { GraphQLClient, GraphQLClientProvider } from "magiql";
import GraphQLDevtools from "magiql/devtools";
export default function App({ children }) {
return (
<GraphQLClientProvider client={client}>
{children}
<GraphQLDevtools defaultIsOpen defaultTab="store" />
</GraphQLClientProvider>
);
}
The following is the core API for magiql
. With the help of amazing libraries like react-query
, relay-compiler
and recoil
, we are able to provide the following features as a GraphQL client. The runtime is your familiar react-query
api. There is also an optional build time setup that unlocks fragments and normalized store.
useQuery
You can use the magiql
Devtools which are inspired by react-query-devtools
as follows:
import React from "react";
import { GraphQLClient, GraphQLClientProvider } from "magiql";
import GraphQLDevtools from "magiql/devtools";
export default function App({ children }) {
return (
<GraphQLClientProvider client={client}>
{children}
<GraphQLDevtools defaultIsOpen defaultTab="store" />
</GraphQLClientProvider>
);
}
useQuery(query, { variables, ...options })
, usePaginatedQuery
and useInfiniteQuery
: Data fetching patterns for GraphQL queries with numerous ways to customize them for refetching on different events
options
from react-query
are valid in the second argumentrelay-compiler
)useMutation
: a hook that provides a way to run GraphQL mutations (updates) on the server state conviniently with optmistic updates from your React app
useFragment
: a hook that allows you to properly encapsulate the date requirements of a component within it by subscribing to a GraphQL Fragment which resolves when provided a ref from the parent component via props
relay-compiler
with either the Babel plugin or the cli command.useGraphQLClient
: Access the underlying GraphQLClient
GraphQLClient
classGraphQLClientProvider
with an instance of a GraphQLClient
react-query
config by using `new GraphQLClient({ endpoint: "...", queryConfig: {...} })react-query
(must be enabled)expo
or wherever the react-native
package.json
property is resolvedHere are some of the big dependencies and inspirations for magiql
:
useFragment
hook (game changer!) to declaratively define data needs for components independent of the fetching of the datarelay-runtime
inspiration for (de)normalizating datamagiql
allows us to use the relay
hooks API without jumping to React Suspense (can't use the new relay hooks without that)recoil (opt-in)
urql (inspiration)
exchange
API to customize execution of graphql requestFAQs
Most of the features that we are providing are thanks to [`react-query`](https://github.com/tannerlinsley/react-query). Using inspiration from `relay` and `urql`, we are able to provide a bunch of additional awesome GraphQL-specific features that you can
We found that magiql demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer 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’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.