Package Exports
- ra-data-hasura-graphql
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (ra-data-hasura-graphql) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
ra-data-hasura-graphql
A GraphQL data provider for react-admin tailored to target Hasura GraphQL endpoints.
Example application demonstrating usage: react-admin-low-code
Benifits and Motivation
This utility is built on top of ra-data-graphql and is a custom data provider for the current Hasura graphql API format.
The existing ra-data-hasura provider communicates with Hasura V1, using standard REST and not GraphQL. The existing ra-data-graphql-simple provider, requires that your graphql endpoint implement a specific grammar for the objects and methods exposed, which is not an option available if you intend to use a Hasura API because the exposed objects and methods are generated to match their own specification.
This utility auto generates valid graphql queries based on the properties exposed by the Hasura API such as object_bool_exp
and object_set_input
.
Installation
Install with:
npm install --save graphql ra-data-hasura-graphql
Usage
The ra-data-hasura-graphql
package exposes a single function, which is a constructor for a dataProvider
based on a Hasura GraphQL endpoint. When executed, this function calls the endpoint, running an introspection query to learn about the specific data models exposed by your Hasura endpoint. It uses the result of this query (the GraphQL schema) to automatically configure the dataProvider
accordingly.
// in App.js
import React, { Component } from 'react';
import buildHasuraProvider from 'ra-data-hasura-graphql';
import { Admin, Resource } from 'react-admin';
import { PostCreate, PostEdit, PostList } from './posts';
class App extends Component {
constructor() {
super();
this.state = { dataProvider: null };
}
componentDidMount() {
buildHasuraProvider({ clientOptions: { uri: 'http://localhost:4000' }})
.then(dataProvider => this.setState({ dataProvider }));
}
render() {
const { dataProvider } = this.state;
if (!dataProvider) {
return <div>Loading</div>;
}
return (
<Admin dataProvider={dataProvider}>
<Resource name="Post" list={PostList} edit={PostEdit} create={PostCreate} />
</Admin>
);
}
}
export default App;
The adapter generates queries based on the standard API's and query arguments generated by Hasura.
For example, a GET_LIST
request for a person resource, with the parameters :
{
"pagination": {"page": 1, "perPage": 5},
"sort": {"field": "name", "order": "DESC"},
"filter": {"ids": [
"f10b7d4b-72a2-4cca-a978-55577e3ef35c",
"fe7470ae-2626-48c7-80dc-1726c066ce4d"
]}
}
Generates the following graphql request for Hasura :
query person($limit: Int, $offset: Int, $order_by: [person_order_by!]!, $where: person_bool_exp) {
items: person(limit: $limit, offset: $offset, order_by: $order_by, where: $where) {
address_id
id
name
}
total: person_aggregate(limit: $limit, offset: $offset, order_by: $order_by, where: $where) {
aggregate {
count
}
}
}
And generates the following variables to be passed along side the query:
{
limit: 5,
offset: 0,
order_by: { name: 'desc' },
where: {
_and: [
{
id: {
_in: ['f10b7d4b-72a2-4cca-a978-55577e3ef35c','fe7470ae-2626-48c7-80dc-1726c066ce4d']
}
}
]
}
}
Options
Customize the Apollo client
You can either supply the client options by calling buildGraphQLProvider
like this:
buildGraphQLProvider({ clientOptions: { uri: 'http://localhost:4000', ...otherApolloOptions } });
Or supply your client directly with:
buildGraphQLProvider({ client: myClient });
Customize the introspection
These are the default options for introspection:
const introspectionOptions = {
include: [], // Either an array of types to include or a function which will be called for every type discovered through introspection
exclude: [], // Either an array of types to exclude or a function which will be called for every type discovered through introspection
};
// Including types
const introspectionOptions = {
include: ['Post', 'Comment'],
};
// Excluding types
const introspectionOptions = {
exclude: ['CommandItem'],
};
// Including types with a function
const introspectionOptions = {
include: type => ['Post', 'Comment'].includes(type.name),
};
// Including types with a function
const introspectionOptions = {
exclude: type => !['Post', 'Comment'].includes(type.name),
};
Note: exclude
and include
are mutually exclusives and include
will take precendance.
Note: When using functions, the type
argument will be a type returned by the introspection query. Refer to the introspection documentation for more information.
Pass the introspection options to the buildApolloProvider
function:
buildApolloProvider({ introspection: introspectionOptions });