Ema Suriano
Software Engineer during the day, cook at night 👨🍳 Traveller and Foodie 🧳 Whenever I can I like to write and speak 🤓 Berlin 📍
My App
FTP
HTTP
REST
HTTP
SOAP
const myService = await params => {
const requestParams = adaptParamsForRequest(params);
const response = fetch(MY_SERVICE_URL, {
headers: SERVICE_HEADERS,
body: requestParams,
...more
});
return parseResponse(response);
}
GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.
Query language refers to any computer programming language that requests and retrieves data from database and information systems by sending queries.
Specifies the capabilities of the API and defines how clients interact with the data
The contract between the client and the server.
The syntax for writing schemas.
It has 2 components:
type Car {
patent: String!
color: String!
}
Used by the client to request the data it needs from the server.
The Client decides what it really wants! 💪
{
allCars {
patent
}
}
{
"data": {
"allCars": [
{
"patent": "ABC 123"
},
{
"patent": "BQK 893"
},
{
"patent": "POI 098"
}
]
}
}
{
allCars {
patent,
owner {
name,
}
}
}
{
"data": {
"allCars": [
{
"patent": "ABC 123",
"owner": {
"name": "Pepe",
}
},
{
"patent": "BQK 893",
"owner": {
"name": "Juan",
}
},
]
}
}
Allows the client to make changes to data stored on the server.
These changes could be:
mutation {
createCar(
patent: “QWE 112”,
color: “red”,
) {
patent
color
}
}
{
"data": {
"createCar": {
"id": 12312301923
}
}
}
Clients get notified when an event happened inside the server.
subscription {
createCar {
patent
}
}
{
"data": {
"createCar": {
"id": 12312301923,
"patent": "ABC123",
}
}
}
{
allCars {
patent,
owner {
name,
}
}
}
{ "data": { "allCars": [ { "patent": "ABC 123", "owner": { "name": "Pepe", } }, ] } }
Legacy System
3rd Party API
getCars()
[...cars]
getOwner(car)
owner
storeRequest()
Each of the fields inside my schema corresponds to a function called resolver.
const CarResolver = {
patent: async ({ id }) => {
const patent = await getPatentFromDb(id);
return patent;
},
owner: async ({ id }) => {
const owner = await fetch(getOwnerInformatioById(id));
return owner;
}
};
The sole purpose of a resolver function is to fetch the data for its field 👌
❤️
Depending on the server you want to run GraphQL, you will have to install a dependency for your specific technology.
express → express-graphql
hapi → hapi-graphql
micro → micro-graphql
...
{
"Brastlewark": [
{
"id": 0,
"name": "Tobus Quickwhistle",
"thumbnail": "http://www.publicdomainpictures.net/pictures/10000/nahled/thinking-monkey-11282237747K8xB.jpg",
"age": 306,
"weight": 39.065952,
"height": 107.75835,
"hair_color": "Pink",
"professions": [
"Metalworker",
"Woodcarver",
"Stonecarver",
" Tinker",
"Tailor",
"Potter"
],
"friends": ["Cogwitz Chillwidget", "Tinadette Chillbuster"]
},
{
"id": 1
}
]
}
{
"Brastlewark": [
{
"id": 0,
"name": "Tobus Quickwhistle",
"thumbnail": "http://www.publicdomainpictures.net/pictures/10000/nahled/thinking-monkey-11282237747K8xB.jpg",
"age": 306,
"weight": 39.065952,
"height": 107.75835,
"hair_color": "Pink",
"professions": [
"Metalworker",
"Woodcarver",
"Stonecarver",
" Tinker",
"Tailor",
"Potter"
],
"friends": ["Cogwitz Chillwidget", "Tinadette Chillbuster"]
},
{
"id": 1
}
]
}
const getGnomes = () => fetch('gnomeURL'); //will return the whole list of gnomes
const getGnomeById = (id, loadFriends = true) => {
const gnome = getGnomes().then(gnomes => {
const result = gnomes.filter(gnome => gnome.id === id);
if (loadFriends) {
const friendsId = gnomes
.filter(({ name }) => result.friends.includes(name))
.map(gnome => gnome.id);
result.friends = Promise.all(
friendsId.map(id => getGnomeById(id, false))
);
}
return result;
});
};
export const GET_GNOME_BY_ID = gql`
query getGnomeById($id: ID!) {
gnome(id: $id) {
name
thumbnail
age
weight
height
hair_color
professions
friends {
id
name
thumbnail
professions
}
}
}
`;
Micro by Zeit
Apollo Server by Apollo
const typeDefs = `
type Query {
allGnomes(name: String, professions: [String]): [Gnome],
gnome(id: ID!): Gnome,
}
type Gnome {
id: ID!,
name: String,
thumbnail: String,
age: Int,
weight: Float,
height: Float,
hair_color: String,
professions: [String],
friends: [Gnome],
createdAt: Int,
}
`;
import { makeExecutableSchema } from 'graphql-tools';
import { getGnomes, getGnomeById } from './query';
const resolvers = {
Query: { allGnomes: getGnomes, gnome: getGnomeById },
Gnome: {
friends: async ({ friends }) => {
const gnomes = await getGnomes();
return gnomes.filter(({ name }) => friends.includes(name));
}
}
};
export default makeExecutableSchema({
typeDefs,
resolvers
});
import fetch from 'node-fetch';
import memoize from 'fast-memoize';
import BASE_URL from './constants';
const fetchGnomes = memoize(async () => {
const rawData = await fetch(BASE_URL);
const jsonData = await rawData.json();
return jsonData.Brastlewark;
});
const getGnomes = async (_, args) => {
const gnomes = await fetchGnomes();
if (!args) return gnomes;
const { name = '', professions = [] } = args;
return gnomes.filter(
gnome =>
(!name || new RegExp(name, 'i').test(gnome.name)) &&
(!professions.length ||
professions.every(prof => gnome.professions.includes(prof)))
);
};
const getGnomeById = async (_, { id }) => {
const gnomes = await fetchGnomes();
return gnomes.find(gnome => gnome.id == id);
};
export { getGnomes, getGnomeById };
REST API is dead. Long live GraphQL
By Ema Suriano
Talk about the advantages of using GraphQL as your service layers.
Software Engineer during the day, cook at night 👨🍳 Traveller and Foodie 🧳 Whenever I can I like to write and speak 🤓 Berlin 📍