DTO 에서 Date 형식 검증하기
현재 API문서에서 생년월일을 보낼 때 String타입이기는 하지만 YYYY-MM-DD 날짜 형식을 지켜서 보내지 않으면 바로 서버에서 에러를 보내주는 상태였다. 물론 Presentation Layer에서 텍스트필드에 정규식을 넣고 아예 입력값 자체를 형식에 맞는 것만 데이터 레이어로 보내는 방법도 있었지만 가장 확실한 방법은 DTO레벨에서 형식을 검증하는 것이라고 생각했다. 플러터에서 어떻게 DTO에서 형식을 검증할 수 있을까?
현재 나는 DTO를 JsonSerializable 패키지를 통해 직렬화/역직렬화 작업을 수행하고 있다. birthday 프로터피도 다른 프로퍼티와 마찬가지로 선언해주고 위 코드와 같이 함수선언과 프로퍼티 위에 코드 한줄을 더 넣어주면 된다. 위 코드의 의미를 구체적으로 살펴보자면..
@JsonKey란?
@JsonKey는 Flutter/Dart에서 JSON 직렬화(Serialization)와 역직렬화(Deserialization)를 커스텀 처리할 수 있도록 하는 메타데이터 어노테이션이다. 쉽게 말해 변환하는 과정에서 특정 규칙을 적용하고 싶을 때 쓰는 것이다.
사용방법은 간단한데 위 코드와 같이 검증하고 싶은 함수를 만든다. (이때 직렬화할 때 검증할 함수 하나, 역직렬화 할 때 검증할 함수 하나씩 만든다). 함수를 만들고 나면 검증할 DTO 프로퍼티에 JsonKey를 넣고 파라미터에 함수를 각각 넣어주면 된다. 이때 만약에 직렬화할 때만 검증하고 역직렬화 할 땐 따로 검증해주지 않아도 된다면 null을 넣거나 아예 파라미터 자체를 선언 안해도 된다!
RegExp(r'^\d{4}-\d{2}-\d{2}$')
날짜 형식 검증함수에서는 위 정규식을 쓰고 있다. 이부분을 뜯어보자면 아래 표로 확인할 수 있다.
^ | 문자열의 시작을 의미 |
\d{4} | 숫자 4개 (\d는 숫자 0-9) → YYYY |
- | 하이픈(-)을 그대로 포함 |
\d{2} | 숫자 2개 → MM (월) |
- | 다시 하이픈(-) 포함 |
\d{2} | 숫자 2개 → DD (일) |
$ | 문자열의 끝을 의미 |
"2024-02-25" | ✅ 매칭됨 | 올바른 YYYY-MM-DD 형식 |
"1990-12-01" | ✅ 매칭됨 | 올바른 형식 |
"23-02-25" | ❌ 매칭 안됨 | YYYY가 2자리밖에 없음 |
"2024-2-5" | ❌ 매칭 안됨 | MM과 DD가 1자리밖에 없음 |
"2024/02/25" | ❌ 매칭 안됨 | / 대신 - 사용해야 함 |
"2024-13-01" | ✅ 매칭됨 (BUT, 논리적 오류!) | 형식은 맞지만, 13월은 존재하지 않음 |
"2024-00-10" | ✅ 매칭됨 (BUT, 논리적 오류!) | 0월은 없음 |
하지만 위 정규식의 문제가 하나 있는데 바로 형식만 검사하기 때문에 "2024-13-01" 같은 존재하지 않는 날짜도 통과한다는 것이다. 이를 해결하기 위해 정규식 + 날짜 파싱 검증을 조합하여 더 엄격한 검증 로직을 수행시킬 수 있다.
기존 코드에 DateTime.parse함수를 사용하면 Dart에서 자동으로 유효하지 않은 날짜를 보정할 수 있다. parseData에는 "2024-02-30" 로 입력값이 들어오면 → "2024-03-01"로 변경되는 값을 얻을 수 있다.
그다음에 보정된 날짜와, 원래 입력한 값(YYYY-MM-DD) 날짜를 비교하면 존재하지 않는 날짜인지 판별하는 로직을 작성함으로써 날짜 존재여부까지 검증할 수 있다.