Hi, selamat datang di artikel kami. Untuk kali ini kita akan sharing dan belajar bareng terkait Strapi. Namun, sebelum kita mulai, ada beberapa hal yang mesti temen-temen pahami.
Pertama, Strapi adalah Headless Content Management System atau Headless CMS yang dimana sangat membantu untuk mempercepet waktu developer untuk membuat sebuah aplikasi.
Lalu apa itu Headless Content Management System atau Headless CMS? Headless CMS adalah sebuah CMS tanpa Frontend yang dimana content-nya dapat diakses melalui API. Sehingga dengan sebuah Headless CMS membantu temen-temen developer membuat backend aplikasi lebih cepat dan mudah.
API memungkinan dua aplikasi untuk saling berkomunikasi melalui sebuah protocol dengan message contract tertentu. Untuk pembahasan kali ini, kita akan menggunakan HTTP dan JSON
Strapi biasanya digunakan para developer untuk mengembangkan Static Websites, Mobile Apps, e-Commerce, Editorial, dan Corporate websites. Namun, tidak menutup kemungkinan untuk mengembangankan aplikasi lebih dari itu. Untuk di artikel kami kali ini, kami akan coba membuat aplikasi bank yang sederhana atau API Simple Bank App.
Kami merasa dengan mempelajari API Simple Bank App, dapat membantu kita untuk mempelajari sistem perbankan dalam scope kecil dan manfaat dari API terutama di era digital saat ini. Adapun yang akan kita pelajari di artikel ini antara lain:
- Business Requirements
- Design System
- Development
Business Requirements
API Simple Bank App melayani user dalam beberapa hal antara lain:
- User dapat mendaftarkan diri menjadi nasabah baru dan mendapatkan nomor Customer Identification File (CIF) dengan meng-input data antara lain:
- Nomor ID atau KTP
- Nama lengkap
- Nasabah dapat membuat nomor rekening baru dengan menginput data CIF
- Dapat melihat daftar nomor rekening dengan menginput data CIF
- Nasabah dapat men-topup uang ke nomor rekeningnya sendiri
- Nomor Rekening
- Amount
- Nasabah dapat menarik uang dari nomor rekeningnya sendiri dengan data antara lain:
- Nomor ID atau KTP
- Nomor Rekening
- Amount
Design system
Berdasarkan Business Requirement di sebelumnya, kami melihat bahwa ada beberapa service yang perlu kita bangun di dalam sistem kita antara lain:
Customer service: service yang melayani nasabah dalam CRUD customer.
Account service: service yang melayani nasabah dalam CRUD account.
Transaction service: service yang melayani nasabah dalam CRUD transaction.
Development
- Buka Terminal lalu jalankan perintah dibawah
npx create-strapi-app@latest app-simple-bank
- Masuk ke folder app-simple-bank dengan menjalankan code di bawah
cd app-simple-bank
Buat dua file yaitu app.Dockerfile, docker-compose.yml, dan Makefile
Untuk app.Dockerfile, ketik kode di bawah ini
FROM node:16-alpine
# Installing libvips-dev for sharp Compatibility
RUN apk update && apk add --no-cache build-base gcc autoconf automake zlib-dev libpng-dev nasm bash vips-dev
ARG NODE_ENV=development
ENV NODE_ENV=${NODE_ENV}
WORKDIR /opt/
COPY ./package.json ./yarn.lock ./
ENV PATH /opt/node_modules/.bin:$PATH
RUN yarn config set network-timeout 600000 -g && yarn install
WORKDIR /opt/app
COPY ./ .
RUN yarn build
EXPOSE 1337
CMD ["yarn", "develop"]
- Untuk compose-docker.yml. ketik kode di bawah ini
version: "3.7"
services:
app-simple-bank:
build:
context: .
dockerfile: ./app.Dockerfile
container_name: app-simple-bank
environment:
- DATABASE_HOST=db-simple-bank
- DATABASE_PORT=5432
- DATABASE_NAME=postgres
- DATABASE_USERNAME=postgres
- DATABASE_PASSWORD=password
- HOST=0.0.0.0
- PORT=1337
- APP_KEYS=mc68ZV26OzOPQ0A1ESUvNA==,b4sM7ksQE3eqfteYmqWzwA==,UUWwjcxNoDrGvSwnDDhwxA==,j7T57Bls1mSggOLIrsljkg==
- API_TOKEN_SALT=nagThNX7aJINn6oaOpMOyg==
- ADMIN_JWT_SECRET=9VrfUyP40Cqxy+6qNvucQQ==
- TRANSFER_TOKEN_SALT=ar4K31sLK7NONBhHQ6t2zw==
ports:
- "8000:1337"
depends_on:
- db-simple-bank
volumes:
- ./src:/opt/app/src
- ./config:/opt/app/config
- ./package.json:/opt/app/package.json
- ./public/uploads:/opt/app/public/uploads
networks:
app-net: {}
db-simple-bank:
image: postgres:alpine
container_name: db-simple-bank
environment:
- POSTGRES_PASSWORD=password
volumes:
- ./data/pg-data:/var/lib/postgresql/data
networks:
app-net: {}
networks:
app-net:
external: true
name: 'dev-to-network'
- Terakhir untuk Makefile, ketik kode di bawah ini
compose-up:
docker compose up -d --build
compose-down:
docker compose down
- Buka terminal di bawah, buat network baru di docker dengan menjalankan kode di bawah ini
docker network create dev-to-network
- Untuk menjalankan aplikasi nya, ketik kode di bawah ini di terminal
make compose-up
- Buka browser, ketik di address bar http://localhost:8000/admin, maka tampilan akan seperti di bawah ini
- Masukan data sesuai dengan yang diminta
- Setelah masuk ke halaman dashboard admin, pilih menu Content-Type builder
- Klik Create new collection type, lalu create Customer
- Create beberapa field seperti dibawah
- Klik Create new collection type, lalu create Account
- Create beberapa field seperti dibawah
- Klik Create new collection type, lalu create Transaction
- Create beberapa field seperti dibawah
- Create lifecycles.js file di src/api/content-types/customer/lifecycles.js, lalu ketikan kode di bawah ini
// src/api/content-types/customer/lifecycles.js
module.exports = {
beforeCreate: async (event) => {
const generate_cif = async (length) => {
let result = '';
const characters = '0123456789';
const charactersLength = characters.length;
let counter = 0;
while (counter < length) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
counter += 1;
}
return result;
}
const get_cif = async () => {
let cif = ""
let customer = []
do {
cif = await generate_cif(10)
customer = await strapi.entityService.findMany("api::customer.customer", {
filters: {
cif: cif
}
})
console.log(`customer: ${customer}`)
console.log(`cif: ${cif}`)
} while (customer.length != 0)
return cif
}
const { data } = event.params;
data.cif = await get_cif()
},
};
- Create lifecycles.js file di src/api/content-types/account/lifecycles.js, lalu ketikan kode di bawah ini
// src/api/content-types/account/lifecycles.js
const utils = require('@strapi/utils');
const { ApplicationError } = utils.errors;
module.exports = {
beforeCreate: async (event) => {
const generate_account_number = async (length) => {
let result = '';
const characters = '0123456789';
const charactersLength = characters.length;
let counter = 0;
while (counter < length) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
counter += 1;
}
return result;
}
const get_account_number = async () => {
let account_number = ""
let account = []
do {
account_number = await generate_account_number(10)
account = await strapi.entityService.findMany("api::account.account", {
filters: {
number: account_number
}
})
console.log(`account: ${account}`)
console.log(`account_number: ${account_number}`)
} while (account.length != 0)
return account_number
}
const { data } = event.params;
const customer = await strapi.entityService.findMany("api::customer.customer", {
filters: {
cif: data.cif_number
}
})
if(customer.length == 0)
{
throw new ApplicationError('Invalid cif number', { message: `can not find '${data.cif_number}' cif number` });
}
else
{
data.number = await get_account_number()
data.balance = 0
}
},
};
- Create file custom-transaction.js di src/api/transaction/controllers/custom-transaction.js, lalu ketikan kode di bawah ini
// src/api/transaction/controllers/custom-transaction.js
const utils = require('@strapi/utils');
const { ApplicationError } = utils.errors;
const get_account = async (account_number) => {
const accountResponse = await strapi.entityService.findMany("api::account.account",
{
filters: {
number: account_number
}
}
)
return accountResponse[0]
}
const generate_journal = async (length) => {
let result = '';
const characters = '0123456789';
const charactersLength = characters.length;
let counter = 0;
while (counter < length) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
counter += 1;
}
return result;
}
const get_journal = async () => {
let journal = ""
let transaction = []
do {
journal = await generate_journal(10)
transaction = await strapi.entityService.findMany("api::transaction.transaction", {
filters: {
journal: journal
}
})
console.log(`journal: ${journal}`)
} while (transaction.length != 0)
return journal
}
module.exports = {
async debit(ctx, next) {
const requestBody = ctx.request.body.data
const account = await get_account(requestBody.account_number)
if (account.length == 0) {
throw new ApplicationError('Invalid account number', { message: `Can not find ${requestBody.account_number} account number` });
}
else {
const new_balance = account.balance - requestBody.amount
const transaction = {
data: {
journal: await get_journal(),
account_number: requestBody.account_number,
type: requestBody.type,
status: "SUCCEED",
action: "DEBIT",
amount: requestBody.amount,
publishedAt: new Date()
}
}
await strapi.entityService.create("api::transaction.transaction", transaction)
await strapi.entityService.update("api::account.account", account.id, {
data: {
balance: new_balance
}
})
return transaction
}
},
async credit(ctx, next) {
const requestBody = ctx.request.body.data
const account = await get_account(requestBody.account_number)
console.log(account)
if (account.length == 0) {
throw new ApplicationError('Invalid account number', { message: `Can not find ${requestBody.account_number} account number` });
}
else {
const new_balance = account.balance + requestBody.amount
const transaction = {
data: {
journal: await get_journal(),
account_number: requestBody.account_number,
type: requestBody.type,
status: "SUCCEED",
action: "CREDIT",
amount: requestBody.amount,
publishedAt: new Date()
}
}
await strapi.entityService.create("api::transaction.transaction", transaction)
await strapi.entityService.update("api::account.account", account.id, {
data: {
balance: new_balance
}
})
return transaction
}
}
}
Ubah nama file transaction.js menjadi 01-transaction.js di folder src/api/transaction/routes/
Create file 02-transactions.js di folder src/api/transaction/routes/, lalu ketikan kode di bawah ini
module.exports = {
routes: [
{ // Path defined with an URL parameter
method: 'POST',
path: '/transactions/debit',
handler: 'custom-transaction.debit',
},
{ // Path defined with an URL parameter
method: 'POST',
path: '/transactions/credit',
handler: 'custom-transaction.credit',
},
]
}
- Re-run kembali aplikasi dengan menjalankan command ini di terminal
make compose-down; make compose-up
- Buka browser, lalu kembali ke http://localhost:8000/admin dan masuk ke menu Settings > Roles lalu pilih Authenticated
- Buka Permissions untuk Account dan Select All semua
- Buka Permissions untuk Customer dan Select All semua
- Buka Permissions untuk Transaction dan Select All semua
- Lalu masuk ke menu Content-Manager > User lalu klik Create new entry
- Input data sesuai form dan pastikan untuk mengingat username, email, dan password. Jangan lupa pilih confirmed-nya true dan role-nya Authenticated
- Pengembangan aplikasi sudah selesai, teman-teman bisa menjalankan test dengan Postman atau semacamnya. Disini kami menggunakan Rest Client VSCode extension dengan create file normal.http dan menjalankan kode di bawah ini
@host=http://localhost:8000
POST {{host}}/api/auth/local
Content-Type: application/json
{
"identifier" : "developer",
"password" : "password"
}
### create customer
POST {{host}}/api/customers
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaWF0IjoxNjgwNDE1MzI1LCJleHAiOjE2ODMwMDczMjV9.HaZpvrouMAjkvm51w0DkRwXjKOdVrInkYvcKfUE_teY
{
"data" : {
"id_number" : "3175023005912345",
"fullname" : "Wildan Anugrah"
}
}
### create account
POST {{host}}/api/accounts
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaWF0IjoxNjgwNDE1MzI1LCJleHAiOjE2ODMwMDczMjV9.HaZpvrouMAjkvm51w0DkRwXjKOdVrInkYvcKfUE_teY
{
"data" : {
"cif_number" : "5685265072",
"type" : "DEPOSIT"
}
}
### accounts
GET {{host}}/api/accounts
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaWF0IjoxNjgwNDE1MzI1LCJleHAiOjE2ODMwMDczMjV9.HaZpvrouMAjkvm51w0DkRwXjKOdVrInkYvcKfUE_teY
### credit
POST {{host}}/api/transactions/credit
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaWF0IjoxNjgwNDE1MzI1LCJleHAiOjE2ODMwMDczMjV9.HaZpvrouMAjkvm51w0DkRwXjKOdVrInkYvcKfUE_teY
{
"data" : {
"account_number" : "1473367796",
"payment_type" : "CREDIT",
"amount" : 10000
}
}
### debit
POST {{host}}/api/transactions/debit
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaWF0IjoxNjgwNDE1MzI1LCJleHAiOjE2ODMwMDczMjV9.HaZpvrouMAjkvm51w0DkRwXjKOdVrInkYvcKfUE_teY
{
"data" : {
"account_number" : "1473367796",
"payment_type" : "DEBIT",
"amount" : 2000
}
}
Cheers :)
Github: https://github.com/wildananugrah/simple-bank-with-strapi-v4











Top comments (0)