author Ahmad Muhardian

Tutorial Membuat REST API dengan Express, Typescript, dan PostgreSQL


Membuat REST API dengan Express, Typescript, dan PostgreSQL

Gara-gara merasa insecure coding pakai Javascript, saya jadi tertarik mencoba Typescript. šŸ˜

Apa kamu juga merasa demikian?

Oke lah, kalau begitu mari kita pelajari gimana cara membuat REST API dengan Express dan Typescript.

Tidak hanya itu..

Kamu juga akan mempelajari gimana cara menggunakan Prisma ORM untuk akses database PostgreSQL. Serta setup Docker untuk service PostgreSQL.

Mari kita mulai!

Step 1 – Persiapan dan Setup Project

Oke, mari kita suapkan project-nya dari nol.

Membuat Project Baru

Pertama, buat folder baru dengan nama microblog.

Buka Terminal atau CMD, lalu ketik perintah ini:

mkdir microblog

Setelah itu, masuk ke folder tersebut dengan cd dan lakukan inisialisasi project Nodejs.

Ketik perintah ini:

cd microblog
npm init -y

Perintah ini akan membuat file baru dengan nama package.json yang merupakan file untuk menyimpan data project dan dependency yang dibutuhkan.

Isinya akan seperti ini:

Wrote to /.../microblog/package.json:

{
  "name": "my-blog",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

Oke, lanjut!

Biar enak, silakan buka project ini dengan teks editor.

Bisa pakai teks editor apa aja, tapi saya sarankan pakai VS Code biar gampang.

Project di VS Code

Install Node Module yang dibutuhkan

Install node module untuk aplikasi:

npm install express @prisma/client @types/http-errors

Install node module untuk development aplikasi:

npm install --save-dev typescript ts-node @types/node @types/express prisma nodemon

Tunggulah sampai prosesnya selesai.

Sambil menunggu, mari kita pelajari fungsi-fungsi tiap modul:

  • express adalah modul untuk framework express;
  • @prisma/client ini ORM client dari Prisma buat akses database;
  • typescript modul yang berisi tools untuk bahasa Typescript seperti compiler;
  • ts-node dan @types/node ini runtime untuk menjalankan Typescript tanpa harus compile ke JavaScript;
  • @types/express modul ini membuat kita bisa gunakan Typescript di Express;
  • @types/http-errors modul ini membuat HTTP Error;
  • prisma ORM untuk akses database biar gak ribet nge-query manual;
  • nodemon untuk menjalankan dev server dan auto reload.

Membuat Config untuk Typescript

Berikutnya, buatlah file baru dengan nama tsconfig.json di root direktori project dengan isi seperti ini:

{
  "compilerOptions": {
    "sourceMap": true,
    "outDir": "dist",
    "strict": true,
    "lib": ["esnext"],
    "esModuleInterop": true
  }
}

Ini adalah konfigurasi yang akan digunakan Typescript untuk compile dan build project.

Ini adalah penampakan project kita saat ini.

Project setelah install node module

Karena saya pakai pnpm, saya jadi punya file pnpm-lock.yaml.

Tenang.. file ini sama seperti file package-lock.json untuk npm.

Oke, lanjut!

Membuat Config untuk Nodemon

Buat file baru dengan nama nodemon.json di root direktori project dengan isi seperti ini:

{
  "execMap": {
    "ts": "ts-node"
  }
}

Ini adalah konfigurasi agar nodemon menggunakan ts-node untuk menjalankan server.

Nodemon config

Konfigurasi Script di package.json

Terakhir, ubah package.json menjadi seperti ini:

{
  "name": "microblog",
  "version": "1.0.0",
  "description": "Micro Blogging Platform Backend",
  "main": "src/index.ts",
  "scripts": {
    "dev": "npx nodemon ./src/index.ts",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "Dian",
  "license": "ISC",
  "devDependencies": {
    "@types/express": "^4.17.14",
    "@types/http-errors": "^2.0.1",
    "@types/node": "^18.11.9",
    "nodemon": "^2.0.20",
    "prisma": "^4.6.1",
    "ts-node": "^10.9.1",
    "typescript": "^4.9.3"
  },
  "dependencies": {
    "@prisma/client": "^4.6.1",
    "express": "^4.18.2"
  }
}

Ini nanti agar kita bisa menjalankan dev server dengan perintah:

npm run dev

Tapi.. untuk saat ini, perintah belum bisa dijalankan.. karena kita belum membuat file index.ts.

Lanjut dulu ke step ke-2.

Step 2 – Setup Docker untuk Service PostgreSQL (Opsional)

Jika kamu sudah menginstall dan setup PostgreSQL di komputermu, maka step ini tidak perlu kamu ikuti.

Silakan lompat ke step berikutnya.

Tapi jika belum, mari kita setup service PostgreSQL dengan Docker.

O ya, pastikan kamu sudah install Docker juga.

Jika belum, saya sarankan untuk baca:

Oke lanjut!

Buatlah file baru di root direktori project dengan nama docker-compose.yml dan isi dengan kode berikut:

version: '3.8'
services:
  postgres:
    image: postgres:10.3
    restart: always
    environment:
      - POSTGRES_USER=microblogger
      - POSTGRES_PASSWORD=sip4lingR4hasia
    volumes:
      - postgres:/var/lib/postgresql/data
    ports:
      - '5432:5432'
volumes:
  postgres:

Ini adalah konfigurasi untuk menjalankan service PostgreSQL dengan Docker compose.

Perhatikan pada bagian POSTGRES_USER dan POSTGRES_PASSWORD, kamu bisa mengganti nilainya dengan yang kamu inginkan.

Tapi ingat, ini nanti akan dipakai untuk menyambungkan aplikasi dengan database PostgreSQL.

File docker compose

Setelah membuat docker-compose.yml, berikutnya silakan jalankan service Docker dengan perintah:

docker compose up -d

Kita memberikan parameter -d supaya service ini dijalankan secara background.

Hasil output di Terminal akan seperti ini:

Terminal Output
Pulling postgres (postgres:10.3)...
10.3: Pulling from library/postgres
f2aa67a397c4: Pull complete
6de83ca23e55: Pull complete
. . .
Status: Downloaded newer image for postgres:10.3
Creating microblog_postgres_1 ... done

Kita juga bisa ngecek prosesnya dengan perintah:

docker ps

Output:

Output
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
8547f8e007ba        postgres:10.3       "docker-entrypoint.sā€¦"   3 seconds ago       Up 2 seconds        0.0.0.0:5432->5432/tcp   microblog_postgres_1

Ini artinya service PostgreSQL sedang berjalan di port 5432 dengan nama container microblog_postgres_1.

docker ps

Sekarang kita bisa akses PostgreSQL di localhost dengan port 5432.

Step 3 – Membuat Model Data

Sebelum buat model data, kita harus melakukan inisialisasi Prisma dulu.

Buka terminal, lalu jalankan perintah ini:

npx prisma init

Jika berhasil, outputnya akan seperti ini:

Terminal Output
āœ” Your Prisma schema was created at prisma/schema.prisma.
  You can now open it in your favorite editor.

Perintah ini akan membuat folder prisma dan di dalamnya akan ada file schema.prisma.

Folder dan file prisma

Selain itu, perintah tadi juga akan membuat file .env.

Silakan ubah isi file .env menjadi seperti ini:

microblog/.env
DATABASE_URL="postgresql://microblogger:sip4lingR4hasia@localhost:5432/microblog?schema=public"

Ini adalah env variabel yang akan dipakai oleh Prisma untuk konek ke service PostgreSQL.

Perhatikan di bagian ini:

microblogger:sip4lingR4hasia

Ini šŸ‘† adalah username dan password database yang kita buat tadi di docker-compose.yml. Silakan sesuaikan dengan akun di server postgre-mu.

Lalu perhatikan juga di bagian ini:

5432/microblog

Ini šŸ‘† adalah nomor port dan nama data base yang akan dipakai.

Oke lanjut!

Sekarang kita bisa mulai membuat model data.

Silakan buka file prisma/schema.prisma, lalu ubah menjadi seperti ini:

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model User {
  id        Int     @default(autoincrement()) @id
  email     String  @unique
  username  String  @unique
  name      String?
  posts     Post[]
}

model Post {
  id        Int       @default(autoincrement()) @id
  content   String
  author    User?     @relation(fields: [authorId], references: [id])
  authorId  Int?
  createdAt DateTime  @default(now())
}

Setelah itu, lakukan migrasi untuk membuat tabel baru di PostgreSQL.

Jalankan perintah ini:

npx prisma migrate dev --name init

Perintah ini akan membuat folder migrations di dalam folder prisma dan akan berisi migration.sql.

Hasilnya:

Terminal Output
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource "db": PostgreSQL database "microblog", schema "public" at "localhost:5432"

PostgreSQL database my-blog created at localhost:5432

The following migration(s) have been created and applied from new schema changes:

migrations/
  ā””ā”€ 20201209084626_init/
    ā””ā”€ migration.sql

Running generate... (Use --skip-generate to skip the generators)

āœ” Generated Prisma Client (2.13.0) to ./node_modules/@prisma/client in 75ms

Folder migrations akan menyimpan semua perubahan migrasi database yang kita lakukan.

Migrasi DB dengan prisma

Jika kamu belum paham konsep migrasi database, saya sarankan untuk baca:

Unuk mengecek hasil migrasi, kita bisa pakai Beekeeper Studio.

Buat koneksi baru di BeeKeeper Studio, masukan username dan password database PostgreSQL kita.

Lalu klik Connect.

Konek ke database dengan beekeeper studio

Hasilnya, akan ada tabel baru dengan sekema yang sama seperti yang kita definisikan di Model Data.

tabel di beekeper

Jika ada migrasi atau perubahan data baru, nanti tabelnya akan di-update.

Tinggal jalankan saja perintah migrasi tadi dan tentukan nama migrasi barunya.

Kamu bisa baca di dokumentasi Prisma.

Oke, semua setup sudah siap.

Selanjutnya kita akan mulai coding.

Step 4 – Membuat REST API

Buat folder baru dengan nama src kemudian di dalamnya buat file index.ts dengan isi seperti ini:

microblog/src/index.ts
import { PrismaClient } from "@prisma/client";
import express, { Request, Response } from "express";
import createError from "http-errors"

const prisma = new PrismaClient()
const app = express()

app.use(express.json())


// TODO: Routing aplikasi akan kita tulis di sini


// handle 404 error
app.use((req: Request, res: Response, next: Function) => {
  next(createError(404))
})

app.listen(3000, () =>
  console.log(`āš”ļø[server]: Server is running at https://localhost:3000`)
)

Sekarang kita bisa jalankan dev server dengan perintah:

npm run dev

Hasilnya:

Running dev server

Server berhasil dijalankan pada localhost:3000.

Kalau kita buka di browser, maka hasilnya:

Hasil test dev server

Yap, hasilnya akan error 404.

Ini karena kita belum mendefinisikan route endpoint-nya.

Sekarang folder project kita sudah menjadi seperti ini.

Folder src

Berikutnya, kita akan buat route endpoint.

Namun..

Sebelum kita menulis route endpoint, kita harus tentukan dulu route apa saja yang akan dibuat.

Ini penting!

Supaya kita tidak bingung nantinya.

Berikut ini adalah route yang akan kita buat di tutorial ini.

EndpointMethodKeterangan
/feedGETList semua post
/postPOSTBuat create post baru
/post/:idGETBuat ambil 1 post berdasarkan id
/post/:idPUTBuat update post
/post/:idDELETEBuat hapus post
/user/POSTBuat create user baru
/:usernameGETBuat ambil user berdasarkan username

Sisanya yang belum ada, nanti kamu bisa buat sendiri ya..

Oke, mari kita buat satu per satu.

Membuat route /feed

Tambahkan kode route ini di bawah // TODO pada index.ts.

app.get('/feed', async (req: Request, res: Response) => {
  const posts = await prisma.post.findMany({
    include: { author: true }
  })
  res.json(posts)
})

Pada route ini, kita coba mengakses data pada tabel post dengan Prisma.

Kita menggunakan method findMany() untuk mengambil banyak data.

Jika kita coba akses route ini dari browser, maka kita akan mendapatkan array kosong.

hasil akses route

Ini karena kita belum punya data untuk ditampilkan.

Karena itu, mari kita lanjut membuat route yang lainnya.

Membuat route /post

Tambahkan route ini di dalam index.ts, tepat di bawah route yang baru saja kita buat.

app.post('/post', async (req: Request, res: Response) => {
  const { content, authorEmail } = req.body
  const result = await prisma.post.create({
    data: {
      content,
      author: { connect: { email: authorEmail } }
    }
  })
  res.json(result)
})

app.get('/post/:id', async (req: Request, res: Response) => {
  const { id } = req.params
  const post = await prisma.post.findUnique({
    where: { id: Number(id) },
  })
  res.json(post)
})

app.put('/post/:id', async (req: Request, res: Response) => {
  const { id } = req.params
  const post = await prisma.post.update({
    where: { id: Number(id) },
    data: {
      ...req.body
    }
  })

  res.json(post)
})


app.delete(`/post/:id`, async (req: Request, res: Response) => {
  const { id } = req.params
  const post = await prisma.post.delete({
    where: { id: Number(id) },
  })
  res.json(post)
})

Kita sudah menambahkan empat route untuk melakukan CRUD (Create, Read, Update, dan Delete) post.

Berikutnya, tambahkan juga route untuk user.

Membuat route /user

Tambahkan route ini di dalam index.ts tepat di bawah route yang adi kita buat.

app.post('/user', async (req: Request, res: Response) => {
  const result = await prisma.user.create({
    data: { ...req.body }
  })
  res.json(result)
})

app.get('/:username', async (req: Request, res: Response) => {
  const { username } = req.params
  const user = await prisma.user.findUnique({
    where: { username: String(username) }
  })
  res.json(user)
})

Step 5 – Uji Coba REST API

Pertama kita coba tambahkan data user dulu ya.

Karena skenarionya, user harus bikin akun atau daftar dulu baru bisa membuat post.

Percobaan endpoint /user

Silakan buka postman, lalu coba lakukan request baru ke endpoint /user dengan method POST.

Isi datanya seperti ini:

Coba tambah data user

Setelah itu, klik Send untuk mengirim request.

Kemudian, coba cek dari BeeKeeper.

Hasilnya:

Data user di beekeper

Data user baru sudah berhasil dibuat.

Sekarang kita bisa coba akses endpoint /:username.

Karena tadi saya membuat username dian, maka saya bisa buka /dian.

Hasilnya:

Coba endpoint username

Percobaan endpoint /post

Berikutnya kita akan membuat post berdasarkan email user.

Buat request ke endpoint /post dengan method POST.

Lalu pada body, isi dengan data JSON seperti ini.

coba add post

Maka hasilnya di Beekeeper studio:

Data post di beekeper

Data post atau tweet berhasil di tambahkan.

Mantap! 👍

Sekarang jika kita coba buka endpoint /feed, maka akan ada 1 post di sana.

coba endpoint /feed

Selanjutnya coba untuk melakukan update dan hapus post.

Percobaan update dan hapus post

Kita coba untuk mengubah data dulu.

Silakan buat request ke /post/1 di Postman dengan method PUT dan isi data baru seperti ini.

Coba update post

Setelah itu, coba buka /post/1 dari browser.

Maka hasilnya:

Coba buka dari browser

Mantap 👍 data berhasil kita ubah.

Terakhir, coba hapus data.

Buat request ke /post/1 dengan method DELETE di Postman.

Coba hapus data

Hasilnya data akan terhapus.

Kita bisa cek dengan membuka endpoint /feed, di sana pasti isinya akan kosong.

hasil akses route

Apa Selanjutnya?

Sejauh ini kita sudah berhasil membuat REST API dengan Express, Typescript, dan PostgreSQL.

Tentu saja ini masih belum cukup.

Karena itu, selanjutnya silakan:

  • Rapikan struktur direktori;
  • Tambahkan validasi data sebelum disimpan ke database;
  • Buat endpoint untuk auth;
  • Buat endpoint untuk upload avatar;
  • Lengkapi endpoint yang belum lengkap;
  • dan sebagainya.

Selamat belajar.