포스트맨에서는 정상적으로 오던 응답이,
앱에서 호출하니 SERVICE_KEY_IS_NOT_REGISTERED_ERROR
라는 응답을 받았다.
Response URL을 브라우저에 로드한 결과⬇️
(Parsing 실패 에러로 빠져서 이상한데서 삽질함...🤦♀️)
구글링을 해보니 APIkey 인코딩이 주된 원인이었다.
공공데이터포털에 올라와 있는 Q&A와 같이, 우선 APIKey는 URL 인코딩을 해야한다.
URL 인코딩...전송전에 URL 문자를 인코딩해아했다고 한 것 같은데...
잘 기억이 나지 않아 다시 찾아보았다.
URL 인코딩에서는 퍼센트 인코딩(percent encoding)이라는 방식을 사용한다.
퍼센트 인코딩은 RFC 3986에 정의되어있다.
퍼센트 인코딩 URL인코딩뿐만 아니라 URI, URN에도 사용할 수 있으므로 정확히는 '퍼센트 인코딩(Percent encoding)'이라는 용어가 더 적합하다고 한다.
퍼센트 인코딩을 하는 이유는 인터넷에서 주고 받을 수 있는 문자는 ASCII 문자뿐이기 때문이다.
따라서 ASCII가 아닌 문자는 전송 가능한 형태로 인코딩을 해야한다.
%XX
(XX는 16진수)로 변환하는 방법이다.한글
-> %ED%95%9C%EA%B8%80
/
(URL의 각 레벨을 구분) , &
(쿼리 파라미터를 구분) , =
(쿼리 파라미터 값 지정)A&B
라는 글자를 보내고 싶을 땐 → A%26B
’&’을 이스케이프 처리[Web] URL 인코딩/디코딩 (URL Encoding/Decoding) 글을 참고했다.
URL Encoding해주는 사이트도 존재한다.
URL Encode Decode - URL Percent Encoding and Decoding.
그런데 iOS에서 URL을 만들때 사용하는 URLComponent
타입은 자동으로 인코딩을 해준다.
https://developer.apple.com/documentation/foundation/urlcomponents
공공데이터 포털에서는 encodedKey, decodedKey 2타입을 제공한다.
따라서 decodedKey를 쿼리 파라미터에 넣으면 한번만 인코딩되니 정상적으로 될 것이라 생각했다.
근데 안됨...💩
스택오버플로우에서 힌트를 얻을 수 있었다.
이유는 URLComponent
가 +
는 인코딩하지 않기 때문이다. 따라서 +
는 수동으로 인코딩해야한다고한다.
공식문서에도 아래와 같은 내용이 Note로 제공되고 있다.
요약하자면
즉, 공공데이터포털에서 제공하는 apiKey는 'W3C recommendations for URI addressing'에 따라 +
를 %2B
로 변환하는데, URLComponents
에서는 그냥 +
그대로 뒀기 때문에 키가 틀리는 오류가 발생한 것이다.
인코딩과 디코딩키를 대조해보면 알 수 있다!
따라서 퍼센트 인코딩된 쿼리에 +
를 %2B
로 직접 변환해 줌으로써 해결했다.
percentEncodedQuery
: 퍼센트 인코딩된 쿼리var url: URL? {
var urlComponents = URLComponents(string: baseURLString + path)
urlComponents?.queryItems = query.map {
URLQueryItem(name: $0.key, value: "\($0.value)") }
// replacingOccurrences로 문자 변환
let encodedQuery = urlComponents?.percentEncodedQuery?.replacingOccurrences(of: "+", with: "%2B")
urlComponents?.percentEncodedQuery = encodedQuery
return urlComponents?.url
}
네트워크 규약들은 정말 많다는 것을 다시 한번 느끼게 되었다.
규약들의 호환성 때문에도 문제가 발생할 수 있다는 관점을 배우게 되었다!
api key error로 status 200을 받을 수 도 있다니...
그래서 xml을 JSON encoding 방식으로 파싱하려 하다보니 Parsing Fail로 빠져서 디버깅하는데 오랜 시간이 걸렸다.
서버사이드와 약속을 공유하는 건 매우 중요한 일이겠다..고 간접적으로 느낄 수 있던 사례였다.
✅ 개선: CountryCodeAPIService에서 data를 파싱하기전에 xml타입으로 데이터가 왔는지 체크하는 로직을 추가로 구현해야겠다.
좋은 정보 공유 감사합니다~^^
덕분에 해결한거 같아요!