와탭랩스 블로그 오픈 이벤트 😃
자세히 보기
테크
2025-07-16
비즈니스 설계에 맞춘 API 설계 왜 중요할까?

이번 콘텐츠에서 소개드릴 내용은 비즈니스 설계에서 부터 소스단에서 패키지 설계와 컨트롤러 설계 부분까지 해서 비즈니스 관점으로 소개를 하려고 합니다.

현재 APM에 새롭게 개발된 “비즈니스 대시보드”에 대해서 설명하기 앞서서 IT 전반적으로 어떤식으로 설계하고 개발하면 이후에 관리가 편해질까에 대해서 자세히 설명을 해보겠습니다. 비즈니스 설계시 RESTful API 설계를 어떻게 하면 좋은지, 그리고 왜 이렇게 설계해야 되는지, 이렇게 설계를 하면 어떤 장점이 있는지에 대해서 설명드리도록 할께요.

비즈니스 설계 시 URL의 1~2 depth를 기준으로 구조화하는 것실무에서도 널리 사용되는 합리적인 방식입니다. 특히 RESTful API를 설계할 때 이 방식이 자연스럽게 비즈니스 도메인 중심의 구조로 이어지는 경우가 상당히 많습니다. 특히 개발자, 운영자 입장에서는 특정 URL만 봐도 어떤 업무인지 구분이 되는 경우가 많기 때문에 거래 분석을 하거나 장애 분석을 할때 문제에 대해서 빠른 대처가 가능하게 됩니다.

👍 URL depth 기반으로 설계할 때의 장점


비즈니스 도메인 중심 설계

아래는 비즈니스 중심으로 설계할때 도메인에 어떤 리소스가 있는지 잘 보이는 구조입니다.

GET    /account                    → 내 계좌 목록 조회
GET    /account/{accountId}        → 특정 계좌 상세
POST   /account                    → 계좌 개설
DELETE /account/{accountId}        → 계좌 해지

POST   /auth/login                 → 로그인
POST   /auth/logout                → 로그아웃
POST   /auth/register              → 회원 가입

GET    /cards                      → 고객 카드 목록
POST   /cards                      → 카드 신청
PUT    /cards/{cardId}/activate    → 카드 활성화
DELETE /cards/{cardId}             → 카드 해지


아래는 비즈니스와 도메인이 연결되지 못하는 구조입니다.

GET    /search/account                    → 내 계좌 목록 조회
GET    /account/detail/{accountId}        → 특정 계좌 상세
POST   /save/account                      → 계좌 개설
DELETE /account/drop/{accountId}          → 계좌 해지

POST   /auth/login                        → 로그인
POST   /logout                            → 로그아웃
POST   /register                          → 회원 가입

GET    /list/cards                        → 고객 카드 목록
POST   /order/cards                       → 카드 신청
PUT    /card/{cardId}/activate            → 카드 활성화
DELETE /drop/card/{cardId}                → 카드 해지 


위에 2개의 예시를 보고 어떤 생각이 드시나요?

저는 위에 두개를 보고 있는데 확실히 위에 부분이 명확하게 잘 보이는거 같습니다. 아래는 이게 account 로직인지 auth에 대한 부분인지가 명확하게 잘 보이지 않습니다. 사실상 제가 사회 생활을 하면서 제품을 개발하기 위해 설계를 할때 시간에 쫓겨서 막 개발한 경험이 있지만 지금 생각해보면 이후에 문제를 찾기 위해 소요되는 공수가 많이 들어 사실상 빠르게 개발 한거에 비해 유지보수가 힘든적이 많았던거 같습니다.

이글을 보시는 분들은 저 처럼 막 개발 하지 않으셨으면 좋겠습니다. 그리고 설계에 대한 중요함을 조금이라도 생각하고 개발을 하시길 권해드립니다^^

⚠️ 주의할 점 - 기능 중심으로 섞지 말 것

위에 좋지 않은 예시를 보면 제가 기능과 도메인을 마구 섞어서 만들었습니다. API를 설계할때는 명확하게 해야 합니다. 어떤 건 기능이 먼저 나오고, 도메인이 뒤에 나오고, 어떤건 도메인이 우선이고 이런식으로 하면 유지 보수도 힘들어 집니다.

/createOrder     → 기능 : create / 도메인 : order
/deleteOrder     → 기능 : delete / 도메인 : order
/orderDelete     → 도메인 : order / 기능 : delete

/order/create    → 도메인 : order / 기능 : create
/order/delete    → 도메인 : order / 기능 : delete
/order/order     → 도메인 : order / 기능 : order


어떠신가요? 저는 아래 부분이 맘에 드네요. 바로 order라는걸 알고, 그 뒤에 어떤걸 찾아야될지 보이는데 위에 부분을 보면 찬찬히 보면 알수는 있지만, 3번째 “orderDelete” 처럼 섞이게 되면 이건 뭐지 하며 또 머리를 굴려보겠네요.

✅ Package 구조 예시

com.whatap.api
├── account
│   ├── controller
│   │   └── AccountController.java
│   ├── service
│   │   └── AccountService.java
│   ├── dto
│   └── domain
├── customers
│   ├── controller
│   └── ...
├── cards
│   └── ...
├── auth
│   ├── controller
│   ├── service
│   ├── dto
│   └── security
└── common
    ├── exception
    ├── response
    └── util


상단에서 RESTful API 설계에 대해서 얘기를 했고 그 부분에 대한 패키지 구조입니다. 제가 간단하게 패키지를 구성해 봤습니다. 컨트롤러에서 API를 받아서 Service단에서 비즈니스 로직을 처리하는 일반적인 구조입니다.

account, customers, cards, auth 등은 도메인에 속합니다. 만약, /account/100 을 호출 했는데 500 에러가 발생된다고 하면 왜 그런지 빠르게 판단해야겠죠. 개발자는 아마도 자신이 사용하는 IDE(Integrated Development Environment)에서 검색을 통해서 /account 를 찾게 될 것입니다. 하지만, 만약 다른 Controller안에서도 account가 존재할 수 있고 Contoller만이 아니라 Service나 각종 Util에서도 사용이 되었다면 찾기가 쉽지 않게 될 것입니다.

하지만 위에 구조처럼 도메인아래 Controller를 둔다면 /account/ … 를 보자마자 바로 AccountController를 찾아 들어가서 보면 되기 때문에 빠른 유지보수가 가능하게 됩니다.

✅  1. Controller 예시

@RestController
@RequestMapping("/account")
public class AccountController {

    @GetMapping
    public ResponseEntity<List<AccountResponse>> getAccount() { ... }

    @GetMapping("/{accountId}")
    public ResponseEntity<AccountDetailResponse> getAccount(@PathVariable Long accountId) { ... }

    @PostMapping
    public ResponseEntity<Void> openAccount(@RequestBody AccountCreateRequest request) { ... }

    @DeleteMapping("/{accountId}")
    public ResponseEntity<Void> closeAccount(@PathVariable Long accountId) { ... }
}


✅ 2. Service 예시


@Service
@RequiredArgsConstructor
public class AccountService {

    private final AccountRepository accountRepository;

    public void createAccount(AccountCreateRequest request) {
        Account newAccount = Account.create(request.getCustomerId(), request.getInitialBalance());
        accountRepository.save(newAccount);
    }

    public List<AccountResponse> getAccounts() {
        return accountRepository.findAll().stream()
                .map(account -> new AccountResponse(account.getId(), account.getCustomerId(), account.getBalance()))
                .collect(Collectors.toList());
    }
}


✅ 3. DTO 예시

AccountResponse.java

@Getter
@AllArgsConstructor
public class AccountResponse {
    private Long accountId;
    private Long customerId;
    private BigDecimal balance;
}


✅ 4. Repository 예시

public interface AccountRepository extends JpaRepository<Account, Long> {
    List<Account> findAll();
}


✅ 정리: 호출 흐름

POST /account
AccountController.createAccount()
AccountService.createAccount()
AccountRepository.save()
Account Entity 생성


✅  마무리 정리

  • URL의 1~2 depth를 기준으로 설계하고, 그에 맞게 controller/class/package를 나누는 건 매우 좋은 설계 방식입니다.
  • 패키지를 설계할 때는 URL 구조와 1:1로 메핑 될 수 있도록 도메인 중심으로 설계합니다.
  • 실제로 DDD(도메인 주도 설계)RESTful API 설계에서도 많이 쓰입니다.
  • 다만, depth만으로 묶기보단 비즈니스 도메인의 응집성도 고려해서 적절히 쪼개는 게 핵심입니다.

제가 왜 비즈니스 설계 부터 개발까지 설명을 했을까요? 당연히 WhaTap에서 비즈니스 관점으로 모니터링이 되기 때문이겠죠!^^

이번에 WhaTap APM에서 “비즈니스 대시보드”라는 메뉴를 새롭게 오픈했습니다. 비즈니스 모니터링에 대한 상세한 부분은 다음 콘텐츠에서 자세히 안내드리겠습니다.

와탭 모니터링을 무료로 체험해보세요!