32
loading...
This website collects cookies to deliver better user experience
Rest API require you to make request to many URLs while all GraphQL queries are actually post requests to a single url
Rest API by default require manually writing documentation unless you configure a tool like Swagger, GraphQL API are self-documenting by default
RestAPI typically give large amounts of information whether you need it or not, while GraphQL allows you to specify which data you need.
Head over to Hasura.io and create a new account and create a new project
Once the project is created launch the console
We need to attach a database to our project (under data), we can do so easily for free using our heroku account (get one if you don't have one).
Once the database is connected click on manage the database then click on create table.
property | type | ------- |
---|---|---|
id | integer (auto increment) | primary key |
habit | text | |
count | integer | default: 0 |
{
habits {
id
habit
count
}
}
mutation {
insert_habits(objects: {
habit: "Exercise",
count: 3
}){
affected_rows
returning {
id
habit
count
}
}
}
mutation {
update_habits_by_pk(pk_columns:{id: 3} _set: {count: 4}){
id
habit
count
}
}
mutation {
delete_habits_by_pk(id:3){
id
habit
count
}
}
fetch('https://your-app-name-here.hasura.app/v1/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
"x-hasura-admin-secret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
body: JSON.stringify({ query: '{
habits {
id
habit
count
}
}' }),
})
.then(res => res.json())
.then(res => console.log(res));
axios({
url: "https://your-app-name-here.hasura.app/v1/graphql"
method: 'POST',
headers: {
'Content-Type': 'application/json',
"x-hasura-admin-secret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
data: JSON.stringify({ query: '{
habits {
id
habit
count
}
}' }),
})
.then(res => console.log(res.data));
npm install @apollo/client graphql
REACT_APP_HASURA_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
REACT_APP_HASURA_URL=https://xxxxxxxxxxxx.hasura.app/v1/graphql
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { ApolloClient, InMemoryCache, ApolloProvider } from "@apollo/client";
// New Apollo Client with Settings
const client = new ApolloClient({
// URL to the GRAPHQL Endpoint
uri: process.env.REACT_APP_HASURA_URL,
// cache strategy, in this case, store in memory
cache: new InMemoryCache(),
// any custom headers that should go out with each request
headers: {
"x-hasura-admin-secret": process.env.REACT_APP_HASURA_SECRET,
},
});
ReactDOM.render(
<ApolloProvider client={client}>
<React.StrictMode>
<App />
</React.StrictMode>
</ApolloProvider>,
document.getElementById("root")
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
useQuery
and useMutation
hooks where needed!import {useQuery, useMutation, gql} from "@apollo/client"
function App() {
// GraphQL Query String
const QUERY_STRING = gql`{
habits {
id
habit
count
}
}`
// run query using the useQuery Hook
// refetch is a function to repeat the request when needed
const {data, loading, refetch, error} = useQuery(QUERY_STRING)
// return value if the request errors
if (error){
return <h1>There is an Error</h1>
}
// return value if the request is pending
if (loading) {
return <h1>The Data is Loading</h1>
}
// return value if the request is completed
if (data){
return <div>
{data.habits.map(h => <h1 key={h.id}>{h.habit} {h.count}</h1>)}
</div>
}
}
export default App;
make-graphql-query
is a small lightweight library I made for making graphQL queries easy and simple in a framework agnostic way. It's just a tiny abstraction to eliminate a lot of boilerplate in using fetch/axios. Here is how you would use it in React.npm install make-graphql-query
REACT_APP_HASURA_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
REACT_APP_HASURA_URL=https://xxxxxxxxxxxx.hasura.app/v1/graphql
import makeGraphQLQuery from "make-graphql-query";
export default makeGraphQLQuery({
url: process.env.REACT_APP_HASURA_URL,
headers: {
"x-hasura-admin-secret": process.env.REACT_APP_HASURA_SECRET,
},
});
import graphQLQuery from "./gqlFunc";
import { useState, useEffect } from "react";
function App() {
// state to hold query results
const [query, setQuery] = useState(null);
// useState to fetch data on load
useEffect(() => {
//making graphql query
graphQLQuery({
query: `{
habits {
id
habit
count
}
}`,
}).then((response) => setQuery(response));
}, []);
// pre-query completion jsx
if (!query){
return <h1>Loading</h1>
};
// post-query completion jsx
return <div>
{query.habits.map((h) => <h2 key={h.id}>{h.habit} - {h.count}</h2>)}
</div>
}
export default App;
mutation add_habit ($objects: [habits_insert_input!]!){
insert_habits(objects: $objects){
affected_rows
}
}
import {useQuery, useMutation, gql} from "@apollo/client"
import { useState } from "react"
function App() {
// GraphQL Query String
const QUERY_STRING = gql`{
habits {
id
habit
count
}
}`
const MUTATION_STRING = gql`mutation add_habit ($objects: [habits_insert_input!]!){
insert_habits(objects: $objects){
affected_rows
}
}`
// run query using the useQuery Hook
// refetch is a function to repeat the request when needed
const {data, loading, refetch, error} = useQuery(QUERY_STRING)
// create function to run mutation
const [add_habit, response] = useMutation(MUTATION_STRING)
// state to hold form data
const [form, setForm] = useState({habit: "", count: 0})
// handleChange function for form
const handleChange = (event) => setForm({...form, [event.target.name]: event.target.value})
// handleSubmit function for when form is submitted
const handleSubmit = async (event) => {
// prevent refresh
event.preventDefault()
// add habit, pass in variables
await add_habit({variables: {objects: [form]}})
// refetch query to get new data
refetch()
}
// check if mutation failed
if(response.error){
<h1>Failed to Add Habit</h1>
}
// return value if the request errors
if (error){
return <h1>There is an Error</h1>
}
// return value if the request is pending
if (loading) {
return <h1>The Data is Loading</h1>
}
// return value if the request is completed
if (data){
return <div>
<form onSubmit={handleSubmit}>
<input type="text" name="habit" value={form.habit} onChange={handleChange}/>
<input type="number" name="count" value={form.count} onChange={handleChange}/>
<input type="submit" value="track habit"/>
</form>
{data.habits.map(h => <h1 key={h.id}>{h.habit} {h.count}</h1>)}
</div>
}
}
export default App;
import graphQLQuery from "./gqlFunc";
import { useState, useEffect } from "react";
function App() {
// state to hold query results
const [query, setQuery] = useState(null);
// state to hold form data
const [form, setForm] = useState({habit: "", count: 0})
// function to get habits
const getHabits = async () => {
//making graphql query
const response = await graphQLQuery({
query: `{
habits {
id
habit
count
}
}`,
});
// assigning response to state
setQuery(response);
};
// function to add a habit
const addHabit = async (variables) => {
//define the query
const q = `mutation add_habit ($objects: [habits_insert_input!]!){
insert_habits(objects: $objects){
affected_rows
}
}`
// run query with variables
await graphQLQuery({query: q, variables})
// get updated list of habits
getHabits()
}
// useState to fetch data on load
useEffect(() => {
getHabits();
}, []);
// handleChange function for form
const handleChange = (event) => setForm({...form, [event.target.name]: event.target.value})
// handleSubmit function for when form is submitted
const handleSubmit = (event) => {
// prevent refresh
event.preventDefault()
// add habit, pass in variables
addHabit({objects: [form]})
}
// pre-query completion jsx
if (!query) {
return <h1>Loading</h1>;
}
// post-query completion jsx
return (
<div>
<form onSubmit={handleSubmit}>
<input type="text" name="habit" value={form.habit} onChange={handleChange}/>
<input type="number" name="count" value={form.count} onChange={handleChange}/>
<input type="submit" value="track habit"/>
</form>
{query.habits.map((h) => (
<h2 key={h.id}>
{h.habit} - {h.count}
</h2>
))}
</div>
);
}
export default App;