오늘 팁은 자료가 정말 없어서 오랜 삽질 끝에 얻은 결과라 귀하다. 하스켈로 realworld api를 만들고 있다. realworld api는 스펙이 정리되어 있어 그대로 보고 만들면 된다. 그 중 Update User라는 것을 만들고 있는데, 요청 본문에 User 필드 값을 넣어 사용자 정보를 업데이트하게 되어 있다. 요청 본문에 필드가 있는 값만 업데이트하게 설계한 것 같다. 예를 들어 요청 본문에 email, bio 만 있으면 두 값을 업데이트하면 되고 image 만 있으면 사용자 정보에서 image 만 바꿔주면 된다. 다른 필드는 모르겠지만 image 필드는 null을 허용하는 것 같다.
문제는 하스켈에서 JSON 옵셔널 필드를 어떻게 표현할 것이다. 뭐 여러가지 멋진 방법이 있지만 그것은 큰 문제는 아니다. 그냥 Maybe a로 해두고 요청 필드가 없으면 Nothing으로 하고 있으면 Just a로 하면 된다. 그럼 null 인 경우와 필드가 없는 경우는 어떻게 구분하는가? 그것도 더 멋진 방법이 있지만 그냥 Maybe (Maybe a)로 중첩해서 처리하면 된다. 최상위 Maybe는 필드가 있냐 없냐고 안 쪽에 값은 nullable이냐 아니냐를 나타내면 된다. 그래서 null 값이면 Just Nothing, 필드가 없으면 Nothing으로 하면된다.
하스켈은 JSON 변환할 때 Aeson 패키지를 쓴다. Aeson에도 옵셔널 필드를 지원한다. (.:?)와 (.:!) 로 parseJSON 할 때 JSON 객체에서 값을 조회해 볼 수 있다. nullable한 옵셔널 필드를 처리하기 위해서 (.:!)를 쓰면 된다. (.:!)이고 결과 타입이 Maybe (Maybe a)라면 필드가 없을 때 Nothing, 값이 null일 때는 Just Nothing, 값이 있을 때는 Just (Just a) 값을 준다.
data UpdateUserInput = UpdateUserInput
{ email :: Maybe Text,
username :: Maybe Text,
password :: Maybe Text,
bio :: Maybe Text,
image :: Maybe (Maybe Text)
}
deriving (Show, Generic)
instance FromJSON UpdateUserInput where
parseJSON = withObject "UpdateUserInput" $ \value -> do
UpdateUserInput
<$> value
.:! "email"
<*> value
.:! "username"
<*> value
.:! "password"
<*> value
.:! "bio"
<*> value
.:! "image"
문제 해결에 도움을 주신 장준영님께 감사드립니다.