47 Membuat Mutation Login dan Signup
47 Membuat Mutation Login dan Signup
Proses autentikasi user merupakan fondasi dari hampir semua aplikasi modern. Kemanan dan efisiensi dalam mengelola identitas pengguna sangat krusial, baik untuk aplikasi sederhana hingga yang kompleks. Pada artikel ke-47 dari serial ini, saya ingin membahas secara mendalam tentang bagaimana membangun mutation untuk Login dan Signup menggunakan GraphQL pada Node.js, lengkap dengan kode contoh, simulasi, dan diagram alur agar lebih mudah dipahami.
Mengapa Mutation?
Mutation dalam GraphQL digunakan untuk memodifikasi data di server, cocok untuk operasi seperti create (Signup) dan update (Login—biasanya untuk otentikasi). Dibandingkan REST API, pendekatan GraphQL membuat endpoint lebih elegan dan eksplisit. Ini sangat berguna saat aplikasi berkembang dan requirements bertambah kompleks.
Arsitektur Kasar
Sebelum masuk ke kode, mari kita pahami arsitekturnya secara garis besar:
- Frontend: Mengirim mutation
logindansignupke backend. - Backend: Menyediakan Schema dan Resolver untuk mutation tersebut.
- Database: Menyimpan data user yang telah terenkripsi (password).
Mari kita ilustrasikan prosesnya dengan diagram alur berikut.
graph TD A[User] -->|Signup| B[GraphQL Mutation - signup] B --> C[Resolver] C --> D[Hash Password] D --> E[Store to Database] A2[User] -->|Login| F[GraphQL Mutation - login] F --> G[Resolver] G --> H[Verify Password] H --> I[Return JWT Token]
Desain Schema GraphQL
Mari mulai dengan mendesain schema dasar untuk mutation Login dan Signup.
1type Mutation {
2 signup(username: String!, password: String!): AuthPayload!
3 login(username: String!, password: String!): AuthPayload!
4}
5
6type AuthPayload {
7 token: String
8 user: User
9}
10
11type User {
12 id: ID!
13 username: String!
14}Penjelasan:
signupdanloginmengembalikan objekAuthPayload.AuthPayloadberisi JWT token dan data user.- Mutation menerima username dan password secara eksplisit.
Kode Implementasi pada Node.js
Tech Stack:
- Node.js
- Express.js
- Apollo Server (GraphQL)
- bcrypt (untuk hash password)
- jsonwebtoken (untuk generate JWT)
Misal kita sudah punya connection ke database MongoDB.
1. Model User (MongoDB/Mongoose)
1// models/User.js
2const mongoose = require('mongoose');
3
4const userSchema = new mongoose.Schema({
5 username: { type: String, unique: true, required: true },
6 password: { type: String, required: true },
7});
8
9module.exports = mongoose.model('User', userSchema);2. Implementasi Resolver
Mari lihat code logic untuk signup dan login.
1// resolvers.js
2const bcrypt = require('bcryptjs');
3const jwt = require('jsonwebtoken');
4const User = require('./models/User');
5
6const SECRET = 'MY_SUPER_SECRET_KEY';
7
8const resolvers = {
9 Mutation: {
10 signup: async (_, { username, password }) => {
11 // Cek user sudah ada
12 const existingUser = await User.findOne({ username });
13 if (existingUser) {
14 throw new Error('Username has been taken');
15 }
16
17 // Hash password dengan bcrypt
18 const hashedPassword = await bcrypt.hash(password, 10);
19
20 // Create user baru
21 const user = new User({ username, password: hashedPassword });
22 await user.save();
23
24 // Generate JWT token
25 const token = jwt.sign(
26 { userId: user.id, username: user.username },
27 SECRET,
28 { expiresIn: '7d' }
29 );
30
31 return {
32 token,
33 user
34 };
35 },
36
37 login: async (_, { username, password }) => {
38 const user = await User.findOne({ username });
39 if (!user) {
40 throw new Error('User not found');
41 }
42
43 const valid = await bcrypt.compare(password, user.password);
44 if (!valid) {
45 throw new Error('Invalid password');
46 }
47
48 const token = jwt.sign(
49 { userId: user.id, username: user.username },
50 SECRET,
51 { expiresIn: '7d' }
52 );
53
54 return {
55 token,
56 user
57 };
58 }
59 }
60};
61
62module.exports = resolvers;Simulasi Request dan Response
Mari kita lihat contoh request dan response nyata pada mutation ini.
1. Signup
Query
1mutation {
2 signup(username: "johndoe", password: "supersecret") {
3 token
4 user {
5 id
6 username
7 }
8 }
9}Response
1{
2 "data": {
3 "signup": {
4 "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
5 "user": {
6 "id": "649c22ebd58be255b9a38212",
7 "username": "johndoe"
8 }
9 }
10 }
11}2. Login
Query
1mutation {
2 login(username: "johndoe", password: "supersecret") {
3 token
4 user {
5 id
6 username
7 }
8 }
9}Response
1{
2 "data": {
3 "login": {
4 "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
5 "user": {
6 "id": "649c22ebd58be255b9a38212",
7 "username": "johndoe"
8 }
9 }
10 }
11}Perbandingan Mutation vs REST
| Fitur | GraphQL Mutation | REST API |
|---|---|---|
| Endpoint | Satu endpoint “/graphql” | Banyak endpoint |
| Response Data | Sesuai permintaan client | Fixed/terbatas |
| Evolusi API | Mudah dikembangkan | Lebih rigid |
| Error Handling | Konsisten via response GraphQL | Tergantung implementasi |
Best Practices
- Hash Password: Selalu hash password dengan
bcryptsebelum disimpan di database. - JWT Expiry: Sertakan expired date pada JWT token untuk keamanan.
- Error Message: Jangan tampilkan error message sensitif.
- Validasi Input: Gunakan validasi di sisi backend untuk username dan password.
- Rate-Limit & Lockout: Implementasikan rate limit pada endpoint login untuk mencegah brute-force.
Potensi Perluasan
Mutation ini adalah pondasi utama. Ada berbagai kemungkinan pengembangan:
- Reset Password
- Verifikasi Email
- Social Login
- Multi-Factor Authentication
Penutup
Membuat mutation login dan signup dengan GraphQL memang memberi banyak keunggulan: efisiensi, kemudahan ekspansi, dan kemanan lebih terstruktur. Kode yang bersih serta arsitektur yang jelas sangat mendukung skalabilitas aplikasi.
Jika Anda ingin memperkuat sistem autentikasi aplikasi, memahami dan mengimplementasikan dua mutation dasar ini adalah investasi yang sangat tepat. Selamat bereksperimen, jangan lupa tambahkan proteksi tambahan dan validasi pada langkah berikutnya!
Resource lebih lanjut: