일단 진행시켜

[Java] Java로 강력한 REST API 구축 4가지 팁 본문

🗞️ 보안 동향 파악 및 나의 생각 정리

[Java] Java로 강력한 REST API 구축 4가지 팁

2024. 8. 25. 03:36

1. Four Essential Tips for Building a Robust REST API in Java

https://dzone.com/articles/four-tips-for-building-a-robust-rest-api-in-java

 

Four Tips for Building a Robust REST API in Java - DZone

Enhance your Java REST API with consistent resource naming, maintainable versioning, robust security, and proper exception handling.

dzone.com

 

 

[ 요약 ]

Java를 사용하여 강력한 REST API를 개발하기 위한 주요 전략을 제공한다.

 

1. 엔드포인트를 논리적으로 구조화하기 ➡️ 유용성 및 서치 개선

일관된 용어, 명명 규칙을 기반으로 구현해야 한다.

도메인 주도 설계(DDD) 원칙에 따라 주요 도메인으로 시작하여 다음 하위 도메인으로 세분화한다

 

예를 들어,

GET /expeditions - 모든 데이터 search

GET /expeditions/{id} - 특정 id를 가진 데이터를 search

 

@Path("expeditions")
public class ExpeditionResource {
    @GET
    public List<Expedition> list() {
        // implementation here
    }

    @GET
    @Path("/{id}")
    public Expedition get(@PathParam("id") String id) {
        // implementation here
    }
    
    @GET
    @Path("/search")
    public List<Expedition> mine() {
        // implementation here
    }
}

* 더 자세한 건 REST API 설계 규칙을 찾아봐야 한다.

 

2. 유지 보수성 ➡️ 확장성 및 문서화를 위해

2.1. 포괄적인 API 문서 추가

API가 성장함에 따라 유지 보수와 확장 가능성을 확보하는 것은 매우 중요하다.유지 보수성을 높이는 방법 중 하나로, 적절한 문서화를 제시하고 있다.많은 개발자들이 API 문서화를 선호하지 않지만, OpenAPI를 통해 문서 자동 생성 및 관리를 진행할 수 있다.

무엇보다 없어서는 안 될 중요한 작업이기도 하다.

 

2.2.버전 관리

또 다른 하나는 버전 관리다. 버전 관리는 이전 버전과의 호환성을 유지하며, 사용자가 편의에 따라 최신 버전으로 마이그레이션 할 수 있도록 지원한다.

Java에서 이를 구현하려면 버전마다 별도의 패키지를 구조화하고, 어댑터 레이어를 만들어 서로 다른 버전 간의 상호작용을 관리할 수 있다.

package os.expert.demo.expeditions.v1;
@Path("/api/v1/expeditions")
public class ExpeditionResource {
// implementation here
}


package os.expert.demo.expeditions.v2;
@Path("/api/v2/expeditions")
public class ExpeditionResource {
// implementation here
}

 

위 예시와 같이 각 버전에 대한 별도의 클래스 관리를 통해 API 이전 버전과 새 버전을 동시에 사용할 수 있어, 버전 간 전환이 더 원활해진다.

 

 

3. 사용자 검증 로직 ➡️ 데이터 무결성 보장

맨 처음 번역 돌렸을 때 "사용자를 절대 믿지 마세요" 라고 나와 놀랐다..ㅎㅎ

보안은 모든 API의 기본적인 측면으로서, 일반적으로 사용자를 절대 신뢰하지 말 것을 강조한다.

@GET
@Path("/my-expeditions")
public List<Expedition> myExpeditions() {
    // No need to request IDs since the user is authenticated
    // implementation here
}

 

사용자가 제공한 ID에는 의존하되, 입력을 절대 신뢰하지 말고 권한 인증을 필수적으로 진행해야 한다.

권한 검사를 항상 시행하여 권한을 갖고 있지 않은 자가 무단으로 작업하는 행위를 막아야 한다.

 

 

4. 적절한 예외 처리 ➡️ API 일관성을 유지 

잘 설계된 API는 적절한 HTTP 상태 코드에 매핑하는 강력한 예외 처리 기능을 갖추어야 한다.

@Provider
public class ExpeditionNotFoundExceptionMapper implements ExceptionMapper<ExpeditionNotFoundException> {
    @Override
    public Response toResponse(ExpeditionNotFoundException exception) {
        return Response.status(Response.Status.NOT_FOUND).entity(exception.getMessage()).build();
    }
}

 

위 예시와 같이, 사용자 정의 예외 매퍼로, 예외를 특정 HTTP 응답에 매핑한다.

ExceptionMapper<ExpeditionNotFoundException> 가 ExpeditionNotFoundException 에 throw 되면,

이 매퍼는 HTTP 404 Not Found 상태와 예외 메시지를 반환한다.

 

 

1. 일관된 용어 사용2. 유지보수와 문서화3. 보안을 최우선으로!4. 적절한 예외처리

 

이 4가지를 지키면 견고한 REST API를 개발하는데 큰 도움이 될 것이다.

 

 

 ➕

도메인 주도 설계(DDD)? 

  • 기본 비즈니스 도메인을 기반으로 sw 모델링에 초점을 맞춘 sw 설계 접근 방식
  • 도메인 모델: 코드 실제 도메인을 반영
  • 유비쿼터스 언어: 개발자와 도메인 전문가가 사용하는 공통 언어
  • 제한된 컨텍스트: 도메인 내에서 서로 다른 모델을 구분하는 명확한 경계 역할
  • DDD는 소프트웨어 아키텍처를 비즈니스 목표에 맞춰 조정하여 유지 관리 가능성과 확장성을 높이는 데 도움이 된다.

 

 


 

🤔 이에 대한 나의 생각

위 규칙중 '몇 가지를 제대로 준수하였는가?' 생각해 보게 되었다. 또한 오류 처리와 적절한 응답 코드 매핑이 필수적이라는 점에도 동의한다. 

그동안 문서화는 번거롭다고 생각해서  '필수'라기보다는 시간이 날 때 처리하면 좋을 '선택'이었다고 생각했는데, 오늘 글을 보고 생각이 달라졌다.

 

무엇보다, "사용자를 신뢰하지 말 것" 이 되게 신선하고 충격적이다.

사용자를 위해 존재하지만 무조건적으로 사용자를 신뢰할 수 없는 이유는 악의적인 목적을 가진 사용자가 많기 때문이라고 생각한다.(정확히 말하면 사용자보단 공격자에 가깝겠지..?)

이러한 관점의 변화 통해 향후 프로젝트에서 이러한 원칙들을 신경써서 구현해야겠다고 다짐하게 되었다!