Search by

    Terakhir diperbaharui: Jan 21, 2021

    GraphQL

    Apa itu GraphQL?

    GraphQL adalah bahasa yang digunakan untuk query API.

    Sebagian bilang GraphQL bisa menjadi pengganti REST API, tetapi prakteknya GraphQL sering digunakan bersamaan dengan REST API dan bahkan saling melengkapi.

    Ada juga yang bilang GraphQL adalah bahasa untuk query database, tetapi sebenarnya GraphQL tidak tahu cara query database karena konsepnya sangat berbeda dengan ORM.

    Untuk menggunakannya kita tidak butuh database tertentu. Bahkan kita bisa query dari sebuah file sekalipun.

    Yang kita butuhkan hanya mendefinisikan bentuk data yang akan diquery dari sebuah data source. Dan data source ini tidak harus berupa database.

    Kata Graph sendiri mewakili jenis struktur data Graph, yaitu jenis struktur data non-linier yang memiliki nodes & edges. Pada GraphQL kita juga akan menemukan nodes & edges.

    Data struktur graph adalah salah satu data struktur yang banyak digunakan dalam aplikasi media sosial.

    GraphQL diciptakan oleh team engineer Facebook pada tahun 2012 dan menjadi open source project di tahun 2015.

    Mungkin saja ini alasan kenapa Facebook menyebutnya GraphQL.

    GraphQL vs REST API

    Banyak dari kita lebih paham apa itu REST API daripada GraphQL, oleh karena itu di bagian ini kita akan bandingkan antara REST API dengan GraphQL.

    HTTP request method

    Jika pada REST API ada kita gunakan banyak HTTP request method seperti GET, POST, PUT & DELETE. Pada GraphQL kita hanya menggunakan POST, dengan nama operasi Query & Mutation.

    Berikut tabel perbandingan operasi pada REST dengan GraphQL.

    http vs graphql table

    Cara Query

    GraphQL

    query graphql

    Dari gambar di atas, kita bisa lihat bentuk data hasil query dari graphql adalah sesuai dengan field yang diminta.

    REST API

    query rest api

    Berbeda dengan REST API, dimana seringkali kita harus ‘menerima’ data hasil query meskipun ada banyak bagian data yang tidak dibutuhkan.

    Untuk mendapatkan data yang memang dibutuhkan dari sebuah REST API kita harus melakukan filtering di sisi client atau membuat endpoint baru.

    Dengan GraphQL kita juga bisa menghindari multiple API calls.

    Sering kita harus mengirim request ke banyak endpoint untuk mendapatkan data yang kita butuhkan. Pada GraphQL kita hanya perlu memanggil endpoint satu kali, bahkan GraphQL hanya memiliki satu endpoint.

    Meskipun tampak jauh lebih simple, tantangan GraphQL ada pada menentukan bentuk GraphQL schema, yaitu bentuk data yang diinginkan.

    Konsep Dasar

    GraphQL adalah salah satu stack yang akan kita gunakan pada saat membuat ulang apliklasi DinoTes, tetapi pada bagian ini kita akan buat sebuah aplikasi sederhana untuk menjelaskan konsep dasar yang ada pada GraphQL.

    Persiapan

    Pastikan tools berikut ini sudah terinstall:

    • Code Editor (VS Code)
    • Terminal
    • Node.js

    GraphQL mendukung banyak bahasa pemrograman, tidak hanya Node.js/JavaScript.

    GraphQL Server & GraphQL Client

    Pada REST API, posisi sebuah server adalah sebagai API producer dan client sebagai API consumer.

    Hal ini juga berlaku untuk GraphQL.

    GraphQL Server

    Terdapat banyak tool yang bisa digunakan untuk membuat sebuah GraphQL Server, pada tutorial ini kita akan gunakan package express-graphql.

    Package express-graphql memungkinkan kita menggunakan graphql pada sebuah aplikasi server express.js.

    Buat sebuah folder dengan nama graphql-server kemudian jalankan perintah berikut ini dari terminal untuk inisialisasi sebuah project Node.js

    1$ yarn init

    Kemudian install expressjs, express-graphql & graphql.

    1$ yarn add express express-graphql graphql

    Kemudian buat sebuah file dengan nama server.js.

    GraphQL Client

    Tools untuk client juga cukup banyak. Tapi pada bagian ini kita cukup menggunakan GraphQL in browser IDE bernama GraphiQL.

    Schema

    Hal pertama yang kita lakukan setelah membuat GraphQL server dan menentukan GraphQL client adalah membuat sebuah schema.

    Schema adalah bagaimana bentuk data yang diinginkan didefinisikan.

    Sebuah schema terdiri dari satu atau banyak Type. Jenis Type yang banyak digunakan di GraphQL:

    • Object Type
    • Scalar Type
    • Query Type
    • Mutation Type
    • Input Type

    Selain yang disebutkan di atas masih ada Enum Type, Interface & Union Type.

    Selanjutnya kita buat sebuah schema dengan type Query:

    1type Query {
    2 id: ID!,
    3 name: String!,
    4 email: String!,
    5}

    Query adalah type khusus pada GraphQL yang mewakili data yang bisa diquery. Jika menggunakan selain Query, data tidak akan bisa diquery.

    Sehingga pada contoh di atas kita bisa query data id, name & email.

    String adalah Scalar type, mirip dengan primitive type pada bahasa pemrograman seperti JavaScript.

    Tambahan ! pada Scalar type menunjukan kalo data bersifat non-nullable atau tidak boleh kosong.

    Implementasi schema pada server.js:

    1const { buildSchema } = require('graphql');
    2
    3const schema = buildSchema(`
    4 type Query {
    5 id: ID!,
    6 name: String!,
    7 email: String!,
    8 }
    9`);

    Resolver

    Kita sudah menentukan schema, lalu bagaimana dengan datanya?

    Data source pada GraphQL bisa berupa sebuah database, file json atau primitive type (string, number dll).

    Untuk mengambil atau generate data kita gunakan function yang biasa disebut dengan resolver.

    Resolver adalah kumpulan function yang akan memberi response untuk setiap query GraphQL. Response ini dapat berasal dari database atau sebuah string.

    Kita buat sebuah resolver pada file server.js untuk generate data name & email:

    1...
    2const root = {
    3 name: () => {
    4 return "brachio";
    5 },
    6 email: () => {
    7 return "brachio@email.com";
    8 },
    9};

    Kita beri nama root karena ini akan menjadi root value / initial value / nilai awal. Tetapi kita bebas memilih nama resolver.

    Selanjutnya lengkapi code dari server.js menjadi seperti ini agar kita bisa menjalankan server:

    1const express = require('express');
    2const { graphqlHTTP } = require('express-graphql');
    3const { buildSchema } = require('graphql');
    4
    5const schema = buildSchema(`
    6 type Query {
    7 name: String!,
    8 email: String!,
    9 }
    10`);
    11
    12const root = {
    13 name: () => {
    14 return 'brachio';
    15 },
    16 email: () => {
    17 return 'brachio@email.com';
    18 }
    19};
    20
    21const app = express();
    22
    23app.use(
    24 '/graphql',
    25 graphqlHTTP({
    26 schema: schema,
    27 rootValue: root,
    28 graphiql: true
    29 })
    30);
    31
    32app.listen(5000);
    33
    34console.log('Running a GraphQL API server at http://localhost:5000/graphql');

    Jalankan server dengan perintah:

    1node server.js

    Setelah server aktif, akses alamat server yaitu http://localhost:5000/graphql.

    Kita akan mendapati tampilan GraphQL in browser IDE atau GraphiQL yang akan kita gunakan untuk membuat query.

    graphiql

    Query

    Untuk query data tulis query seperti ini pada GraphiQL:

    1{
    2 name
    3 email
    4}

    Kemudian klik pada icon Start / Run.

    Hasilnya:

    run graphiql

    Jika ingin query data email saja, kita tinggal update query menjadi seperti ini:

    single field query graphiql

    Mutation

    Pada GraphQL jika kita ingin menambah atau update data di server kita gunakan operasi Mutation.

    Langkah-langkahnya sebagai berikut…

    Kita buat Object type dengan nama User dan input type dengan nama UserInput:

    1type User {
    2 id: ID!,
    3 name: String!,
    4 email: String!
    5}
    6
    7input UserInput {
    8 name: String!,
    9 email: String!
    10}

    Kemudian update Query type:

    1type Query {
    2 getUser: User
    3}

    Field getUser digunakan untuk query semua data dalam bentuk User type.

    Tambahkan Mutation type:

    1type Mutation {
    2 createUser(input: UserInput): User
    3 updateUser(id: ID!, input: UserInput): User
    4}

    Untuk Mutation type kita buat dua field createUser & updateUser.

    • createUser, untuk menambahkan user baru.

    Menerima input (argument) dalam bentuk UserInput.

    • updateUser, untuk update data user.

    Menerima input (argument) dalam bentuk UserInput dan ID .

    Kita akan gunakan sebuah array untuk menyimpan data user.

    1let users = [{ id, name: 'brachio', email: 'brachio@email.com' }];

    Gunakan crypto, built-in module dari Node.js untuk generate id.

    1const id = require('crypto').randomBytes(10).toString('hex');
    2
    3let users = [{ id, name: 'brachio', email: 'brachio@email.com' }];

    Tambahkan resolver:

    • getUser
    1getUser: () => {
    2 return users;
    3 },
    • createUser
    1createUser: ({ input }) => {
    2 const id = require('crypto').randomBytes(10).toString('hex');
    3 users.push({ id, ...input });
    4 return { id, ...input };
    5};
    • updateUser
    1updateUser: ({ id, input }) => {
    2 const newUsers = users.map((user) => {
    3 if (user.id === id) {
    4 return { ...user, ...input };
    5 } else {
    6 return user;
    7 }
    8 });
    9 users = [...newUsers];
    10 return { id, ...input };
    11};

    Final Code:

    1const express = require('express');
    2const { graphqlHTTP } = require('express-graphql');
    3const { buildSchema } = require('graphql');
    4const schema = buildSchema(`
    5 type User {
    6 id: ID!,
    7 name: String!,
    8 email: String!,
    9 }
    10input UserInput {
    11 name: String!,
    12 email: String!
    13 }
    14type Query {
    15 getUser: [User!]!
    16 }
    17type Mutation {
    18 createUser(input: UserInput): User
    19 updateUser(id: ID!, input: UserInput): User
    20 }
    21`);
    22const id = require('crypto').randomBytes(10).toString('hex');
    23let users = [{ id, name: 'brachio', email: 'brachio@email.com' }];
    24const root = {
    25 getUser: () => {
    26 return users;
    27 },
    28 createUser: ({ input }) => {
    29 const id = require('crypto').randomBytes(10).toString('hex');
    30 users.push({ id, ...input });
    31 return { id, ...input };
    32 },
    33 updateUser: ({ id, input }) => {
    34 const newUsers = users.map((user) => {
    35 if (user.id === id) {
    36 return { ...user, ...input };
    37 } else {
    38 return user;
    39 }
    40 });
    41 users = [...newUsers];
    42 return { id, ...input };
    43 }
    44};
    45const app = express();
    46app.use(
    47 '/graphql',
    48 graphqlHTTP({
    49 schema: schema,
    50 rootValue: root,
    51 graphiql: true
    52 })
    53);
    54app.listen(5000);
    55console.log('Running a GraphQL API server at http://localhost:5000/graphql');

    Sekarang kita coba hasilnya menggunakan GraphiQL:

    • Menambah user

    graphiql add user

    • Cek data user setelah user baru ditambahkan

    graphiql query existing data

    • Update existing user

    graphiql update existing user

    graphiql update existing user 2

    Variables

    GraphQL mendukung penggunaan variable dalam query:

    graphiql variables

    Untuk membuat variable yang harus kita lakukan:

    • Deklarasi variable pada query
    1mutation addUser($input: UserInput) {
    2...
    • Tulis nilai variable dalam format JSON
    1{
    2 "input": {
    3 "name": "t-rex",
    4 "email": "t-rex@email.com"
    5 }
    6}

    Pada GraphiQL kita bisa gunakan opsi Query Variables, sedangkan pada client kita harus tulis secara terpisah di dalam sebuah variable atau file json.

    • Gunakan variable dalam query/mutation
    1...
    2 createUser(input: $input) {
    3 id
    4 }
    5...

    Selain variable, terdapat alias, fragment & directives yang bisa kita pakai untuk membuat query yang lebih kompleks.

    Untuk demonya kita perlu update Query type di server.js agar bisa menerima argument:

    1...
    2 type Query {
    3 getAllUser: [User!]!
    4 getUser(id: ID!): User
    5 }
    6...

    Kemudian update resolver:

    1...
    2 getAllUser: () => {
    3 return users;
    4 },
    5 getUser: ({id}) => {
    6 const found = users.find(user => user.id === id);
    7 if(!found) {
    8 throw new Error('please check the user id, we cannot find it');
    9 }
    10 return found;
    11 },
    12...

    Alias

    Dengan menggunakan alias kita bisa buat beberapa query dengan argument yang berbeda sekaligus:

    graphql alias

    Pada query di atas firstUser & secondUser adalah alias.

    Fragment

    Dengan fragment kita bisa menulis query sekali untuk digunakan berkali-kali.

    graphql fragment

    Directives

    Dengan directives kita bisa menambahkan kriteria pada query.

    Misalnya kita gunakan directives @include untuk memfilter data name saat query. Dimana jika nilainya true maka name dimunculkan dan sebaliknya.

    graphql directives 1

    graphql directives 2

    TL;DR

    • GraphQL adalah bahasa yang digunakan untuk query API.

    • GraphQL Schema adalah definisi dari bentuk data yang diinginkan. Yang berisi satu atau banyak Type.

    • Jenis type GraphQL yang sering digunakan: Object Type, Scalar Type, Query Type, Mutation Type, Input Type

    • Dua operasi yang ada di GraphQL: Query & Mutation, Query untuk mendapatkan data, sedangkan Mutation untuk mengubah data

    • Untuk bisa membuat query atau mutation yang kompleks kita bisa gunakan Argument, Variables, Alias, Fragment & Directives.