Lewati ke konten

Services

Service di GamanJS adalah tempat untuk business logic aplikasi. Service dibuat dengan composeService dan tidak bergantung pada HTTP layer — murni logic.

Pola yang direkomendasikan adalah meng-export instance service sebagai konstanta dan meng-export tipe kembaliannya (return type) untuk memudahkan dependency injection di controller.

src/modules/app/services/AppService.ts
import { composeService } from 'gaman/compose';
import type { RT } from 'gaman/types';
export const AppService = composeService(() => {
/**
* Kamu bisa meletakkan logika private, state, atau koneksi database di sini
*/
return {
WelcomeMessage() {
return '❤️ Welcome to GamanJS';
},
};
});
// Export tipe kembalian dari service
export type AppService = RT<typeof AppService>;
src/modules/app/services/UserService.ts
import { composeService } from 'gaman/compose';
import type { RT } from 'gaman/types';
interface User {
id: number;
name: string;
email: string;
}
const users: User[] = [
{ id: 1, name: 'Angga', email: 'angga@example.com' },
];
export const UserService = composeService(() => {
return {
findAll(): User[] {
return users;
},
findById(id: number): User | undefined {
return users.find((u) => u.id === id);
},
create(data: Omit<User, 'id'>): User {
const newUser = { ...data, id: users.length + 1 };
users.push(newUser);
return newUser;
},
};
});
export type UserService = RT<typeof UserService>;

Service juga bisa menerima dependency dari service lain:

src/modules/app/services/AuthService.ts
import { composeService } from 'gaman/compose';
import type { RT } from 'gaman/types';
import { EmailService } from './EmailService';
export const AuthService = composeService(
(emailService: RT<typeof EmailService> = EmailService()) => {
return {
register(name: string, email: string) {
// ... logika pendaftaran
emailService.sendWelcome(email);
return { name, email };
},
};
}
);
export type AuthService = RT<typeof AuthService>;

Saat menggunakan service di controller, gunakan pola destrukturisasi yang direkomendasikan dengan tipe Deps.

import { composeController } from 'gaman/compose';
import { UserService } from '../services/UserService';
export type Deps = {
userService: UserService;
};
export default composeController(({ userService }: Deps) => ({
GetAll(ctx) {
const users = userService.findAll();
return ctx.send(users).ok();
},
}));
  • Service tidak memiliki akses ke ctx — ini disengaja agar logic tidak bergantung pada HTTP.
  • Satu service bisa dipakai oleh banyak controller.
  • Service bisa saling bergantung satu sama lain.
  • Gunakan export type Name = RT<typeof Name> agar DI menjadi bersih dan type-safe.
  • Pisahkan concern: Service = business logic, Controller = HTTP handling.