【AWS Amplify 노하우 시리즈】 2. enum 타입 필드는 Search API 에서 사용할 수 없어요

Amplify 노하우 시리즈 두번째 글입니다! Search API 를 사용할 때 enum 타입에 대한 제약사항과 이 제약사항을 벗어나기 위한 간접적인 해결책(workaround)를 제시합니다.
2020.07.24

안녕하세요!ㅎㅎ Classmethod 컨설팅부 소속 김태우입니다.

지난번 글에 이어 Amplify 시리즈 두번째 글입니다! 이번 글도 역시나 입문자를 대상으로 하는 글이 아니라서 Amplify 의 기초부분은 다루지 않고 있고, Amplify 를 직접 프로젝트에 활용할 때의 팁에 대해 적어보려고 합니다.

이번 글에서는 특히, Search API 를 사용할 때 enum 타입에 대한 제약사항과 이 제약사항을 벗어나기 위한 간접적인 해결책(workaround)를 제시합니다. 어찌보면 굉장히 간단한 글이 될 것 같지만, 미리 읽어두고 알아놓으면 수고로움을 덜어준다는거!ㅎㅎ

그럼 시작하겠습니다! :)

응?? 뭐가 안된다구??

Amplify 의 API 를 GraphQL (실제로는 AppSync 가 사용됨) 타입으로 선택하여 @searchable 디렉티브를 스키마에 추가하면 자동으로 Search 관련 API 를 생성해줍니다. 좀 더 구체적으로,

type Post @model @searchable {
  id: ID!
  title: String!
  content: String!
  createdAt: AWSDateTime
  updatedAt: AWSDateTime
}

와 같이, Post 타입의 스키마에 @searchable 디렉티브를 추가하고 amplify push 해주면 AppSync 에 등록할 수 있는 훨씬 더 상세한 스키마파일로 변환해주는 과정을 거치게 됩니다. amplify/backend/api/${API명}/build/schema.graphql 파일을 열어보면 amplify/backend/api/${API명}/schema.graphql 보다 훨씬 상세한 스키마 파일을 확인하실 수 있습니다.

이 때, Query 타입을 보면,

...

type Query {
  getPost(id: ID!): Post
  listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection
  searchPosts(filter: SearchablePostFilterInput, sort: SearchablePostSortInput, limit: Int, nextToken: String): SearchablePostConnection
}

...

와 같이 searchPosts() 가 자동으로 생성되었음을 확인할 수 있습니다. SearchablePostFilterInput 타입의 filter 파라미터를 인풋으로 받는데요, 이때 SearchablePostFilterInput 를 찾아서 확인해보면,

...

input SearchablePostFilterInput {
  id: SearchableIDFilterInput
  title: SearchableStringFilterInput
  content: SearchableStringFilterInput
  createdAt: SearchableStringFilterInput
  updatedAt: SearchableStringFilterInput
  and: [SearchablePostFilterInput]
  or: [SearchablePostFilterInput]
  not: SearchablePostFilterInput
}
  
...

와 같이, Post 타입에 선언해두었던 모든 id, title, content, createdAt, updatedAt 필드가 모두 searchable filter 로 등록된 것을 확인할 수가 있습니다.

자, 이제 처음의 Post 타입을 한번 아래와 같이 변경한 후에 amplify push 를 실행해보겠습니다.

type Post @model @searchable {
  id: ID!
  title: String!
  content: String!
  
  hit: Int! # 조회수
  postType: PostTypeEnum! # 글 종류
  authorEmail: AWSEmail! # 작성자 이메일주소
  postUrl: AWSURL! # 본문 URL
  
  createdAt: AWSDateTime
  updatedAt: AWSDateTime
}

enum PostTypeEnum {
  ANNOUNCEMENT # 공지사항
  NORMAL # 일반글
  ADVERTISEMENT # 광고
}
$ amplify push

그러면 아래와 같이 build/schema.graphqlSearchablePostFilterInput 은 아래와 같이 업데이트됩니다.

...
input SearchablePostFilterInput {
  id: SearchableIDFilterInput
  title: SearchableStringFilterInput
  content: SearchableStringFilterInput
  hit: SearchableIntFilterInput
  authorEmail: SearchableStringFilterInput
  postUrl: SearchableStringFilterInput
  createdAt: SearchableStringFilterInput
  updatedAt: SearchableStringFilterInput
  and: [SearchablePostFilterInput]
  or: [SearchablePostFilterInput]
  not: SearchablePostFilterInput
}
...

어라? 잠깐...!? 여기서 이상한 점을 느끼셨나요?

PostTypeEnum 타입의 postType 필드에 대한 필터가 생성되지 않았습니다! Amplify 공식문서에서 찾아보면,

A complete list of searchable operations per GraphQL type supported as of today

enum 은 @searchable 에서 서포트 하지 않고 있는군요..

이 글을 작성하고 있는 불과 열흘전까지도 Amplify Github 의 Issues 에는 이 기능을 서포트 해달라고하는 요청이 넘쳐나고 있습니다.

Unable to search on enum field with @searchable #3248

어떻게 해결하는 게 좋을까요??

사실 저도 딱히 엄청한 노하우나 팁이 있는 것은 아닙니다. 다만, 이러한 이슈가 있다는 것을 널리 공유하고, 제가 어떻게 이러한 이슈를 회피해서 Amplify 를 활용하고 있는지에 대한 사소한 의견을 공유하고 싶어서 글을 작성하고 있습니다. 그러니 더 좋은 솔루션을 아시는 분은 AWSKRUG 의 #amplify 채널에서 @twkiiim 에게 멘션 걸어서 알려주세요!ㅋㅋ

같은 필드, 다른 타입을 사용하기

결론부터 말씀드리면, 저는 아래와 같이 String 타입의 필드를 하나더 추가해서 사용하고 있습니다.

type Post @model @searchable {
  id: ID!
  title: String!
  content: String!
  
  hit: Int! # 조회수
  postType: PostTypeEnum! # 글 종류
  authorEmail: AWSEmail! # 작성자 이메일주소
  postUrl: AWSURL! # 본문 URL
  
  createdAt: AWSDateTime
  updatedAt: AWSDateTime
  
  ## temporary searchable fields
  _postType: String! # postType 을 Searchable 필터로 사용하기 위한 임시 필드
  ...
}

enum PostTypeEnum {
  ANNOUNCEMENT # 공지사항
  NORMAL # 일반글
  ADVERTISEMENT # 광고
}

즉, 데이터를 생성할 때 PostTypeEnum 타입의 변수를 아래와 같이 어사인해서 데이터를 생성하는 것이죠!

...
postInput.postType = PostTypeEnum.NORMAL;
postInput._postType = PostTypeEnum.NORMAL;
...

실제로 javascript 에서는 enum 타입이 스트링과 동일하게 취급되기 때문에 이러한 어프로치가 동작합니다. 그리고, 검색시에는 String 타입으로 선언된 _postType 필드를 활용하여 postType 으로 필터링이 가능합니다.

이런 귀찮은 걸 하라고??

물론 postType 필드를 생성/수정 할 때마다 이러한 작업을 해줘야하는 번거로움이 있지만, Amplify 를 활용하게 될 주 타겟이 빠르게 MVP 를 만들어내고자하는 완전초기 스타트업이라는 점을 감안하면, 이정도 번거로움은 충분히 감수할 만 하다고 생각합니다. 스키마 선언만으로도 그 귀찮은 CRUD API 는 물론, Search API 까지 자동으로 생성해주니까요!

마치며

이번 글에서는 Search API 를 활용할 때 enum 타입으로 선언된 필드가 Searchable 필터에 포함되지 않는다는 점과, 이를 해결하기 위한 간단한 workaround 에 대해 공유하였습니다!

이상, 컨설팅부의 김태우였습니다! :D