Motivácia
Nemôžeme našu aplikáciu odizolovať od zvyšku sveta. Potrebujeme komunikovať s cudzími službami. Spôsoby akými sme to umožnili v minulosti sú rôzne (Twitter API, Github API). GraphQL to zjednocuje a berie o úroveň vyššie.
Dokument o vzniku GraphQL: GraphQL: The Documentary
Získavanie informácií z cudzích GraphQL APIs
Existujú APIs vytvorené priamo len na GraphQL, ale existujú aj “proxies”, ktoré obaľujú existujúce APIs. Vyhneme sa uzatvoreným a pozrieme sa na niektoré z otvorených: APIs-guru/graphql-apis
Na hranie použijeme GraphQL Hub Playground.
Skúsime získať informácie o používateľovi redditu:
{
reddit {
user(username: "GovSchwarzenegger") {
username
commentKarma
createdISO
}
}
… a môžeme nick skúsiť zameniť za “Here_Comes_The_King”.
My máme ale veľmi VEĽMI radi mapy a spolu s ďalšími ich hľadáme a zbierame a preto ideme nájsť niečo o nich.
{
reddit {
subreddit(name: "MapPorn"){
hotListings(limit: 5) {
title
url
score
comments(limit: 3) {
body
author {
username
commentKarma
}
}
}
}
}
}
A môžeme sa ešte pohrať s niečím iným.
Získavanie informácií do Reactu z cudzích GraphQL APIs
Appka s mapami je TOP a naposledy sme robili React.
npx create-react-app hot-maps
cd hot-maps
npm start
Potrebujeme ešte knižnicu na prácu so serverom: npm install urql graphql
.
Môžeme si vytvoriť klienta čo nás “napojí na server” vo všetký komponentoch nižšie.
const client = createClient({
url: 'https://www.graphqlhub.com/graphql',
});
function App() {
return (
<Provider value={client}>
<div className="App">
<header className="App-header">
<h1>These are the hottest maps</h1>
<Maps />
</header>
</div>
</Provider>
);
}
A vytvoríme nový komponent Maps
, ktorý bude robiť výber dát a zobrazí ich:
import React from 'react';
import { useQuery } from 'urql';
export default function Maps () {
const [result] = useQuery({
query: `{
reddit {
subreddit(name: "MapPorn"){
hotListings(limit: 5) {
title
url
score
comments(limit: 3) {
body
author {
username
commentKarma
}
}
}
}
}
}`,
});
const { fetching, data } = result;
const maps =
data
? data.reddit.subreddit.hotListings
: [];
const mapsList = maps.map(map => (
<div>
<h3>{map.title}</h3>
<img src={map.url} alt={map.title} width="50%" />
<p>Score: {map.score}</p>
<hr />
</div>
));
return (
<div>
{fetching ? 'loading...' : mapsList}
</div>
);
}
Vlastné GraphQL API
GraphQL API nemusíme len konzumovať ale môžeme aj vytvoriť pre naše potreby (alebo druhých). Môžeme zostať v priečinku s react aplikáciou a vytvoríme v ňom aj server.
Na to potrebujeme zopár balíkov: npm install graphql express express-graphql cors
.
Základ servera je:
const express = require('express');
const express_graphql = require('express-graphql');
const { buildSchema } = require('graphql');
const cors = require('cors');
const schema = buildSchema(`
type Query {
message: String
}
`);
const root = {
message: () => 'Hello World!'
};
const app = express();
app.use(cors());
app.use('/graphql', express_graphql({
schema: schema,
rootValue: root,
graphiql: true
}));
app.listen(
4000,
() => console.log('Express GraphQL Server Now Running On localhost:4000/graphql'),
);
A spustíme ho pomocou node server.js
. Môžeme otvoriť localhost:4000/graphql.
Na našom serveri sa možeme dostať k hodnotám rôzne, napr. aj získaním z iného GraphQL servera. Na to chceme vytvoriť klienta s balíčkom, ktorý si nainštalujeme: npm install graphql-request
.
Na server pridáme type Map a resolver na maps.
const schema = buildSchema(`
type Map {
title: String!
url: String!
score: Int!
}
type Query {
message: String
maps: [Map!]!
}
`);
maps: async () => {
const query = `{
reddit {
subreddit(name: "MapPorn") {
hotListings(limit: 5) {
title
url
score
}
}
}
}`;
const data = await request('https://www.graphqlhub.com/graphql', query);
return data.reddit.subreddit.hotListings;
},
A klienta upravíme podľa toho. Finálny kód v repozitári.
Ďalšie úlohy (na doma?)
- Skúste iné API zo zoznamu, ktoré vás zaujíma a má možnosť odkskúšania v prehliadači a napíšte zopár queries na čítanie dát.
- Doplnte na server do schémy a resolvera komentáre.
- Pridajte zobrazovanie komentárov na klienta.