라이브러리 없이 API 연결하기

1 답변 글타래를 보이고 있습니다
  • 글쓴이
    • 은지짱
      참가자
      • 글작성 : 13
      • 답글작성 : 7

      라이브러리 없이 API 연결하기

      선수환경 : 한국 환경 공단 대기 오염 정보 사이트에서 API KEY 발급받기 (승인까지 1시간 소요)

      라이브러리 사용 없이 외부 API 와 연결해 보자 ❗️

      위 API 에서 시도별 미세먼지 측정 정보를 조회할 것이다.

      1. Setting Info.plist

      기본 설정은 전송 보안이 안전하지 않기 때문에 일반 텍스트 HTTP 리소스 로드를 차단한다.
      따라서 info.plist<dict> 안에 아래 코드를 추가한다.

      <key>NSAppTransportSecurity</key>
      <dict>
      <key>NSAllowsArbitraryLoads</key>
      <true/>
      </dict>
      

      위 코드는 HTTP 모드를 활성화 해준다.

       

      2. Encode URL

      http://openapi.airkorea.or.kr/openapi/services/rest/ArpltnInforInqireSvc/getCtprvnRltmMesureDnsty?sidoName=서울&pageNo=1&numOfRows=10&ServiceKey=[발급받은 API KEY]&_returnType=json
      

      호출해야 하는 URL 에 한글이 있을 경우 반드시 encode 를 해야 한다.
      전체 URL을 encode 하면 에러가 발생한다. url 주소는 이미 한 번 encode 되어 있는 상태이기 때문이다.

      func makeStringKoreanEncoded(_ string: String) -> String {
      return string.addingPercentEncoding(withAllowedCharacters: .urlFragmentAllowed) ?? string
      }
      
      let region = "서울"
      let encodeRegion = makeStringKoreanEncoded(region)
      let encodeURL = urlString + encodeRegion + urlString2
      let url = URL(string: encodeURL)!
      

      따라서 위와 같이 한글인 부분만 encode를 해준다.

       

      3. Response Struct

      위 API 를 호출하면 리턴되는 json 구조가 (좀 많이) 복잡하다…❗️

      {
      "list": [
      {
      "_returnType": "json",
      "coGrade": "1",
      "coValue": "0.2",
      "dataTerm": "",
      "dataTime": "2020-05-02 02:00",
      "khaiGrade": "2",
      "khaiValue": "79",
      "mangName": "도시대기",
      "no2Grade": "1",
      "no2Value": "0.008",
      "numOfRows": "10",
      "o3Grade": "2",
      "o3Value": "0.054",
      "pageNo": "1",
      "pm10Grade": "2",
      "pm10Grade1h": "2",
      "pm10Value": "50",
      "pm10Value24": "48",
      "pm25Grade": "2",
      "pm25Grade1h": "2",
      "pm25Value": "33",
      "pm25Value24": "27",
      "resultCode": "",
      "resultMsg": "",
      "rnum": 0,
      "serviceKey": "",
      "sidoName": "",
      "so2Grade": "1",
      "so2Value": "0.002",
      "stationCode": "",
      "stationName": "영등포구",
      "totalCount": "",
      "ver": ""
      },
      ... (생략)
      ],
      "ArpltnInforInqireSvcVo": {
      "_returnType": "json",
      "coGrade": "",
      "coValue": "",
      "dataTerm": "",
      "dataTime": "",
      "khaiGrade": "",
      "khaiValue": "",
      "mangName": "",
      "no2Grade": "",
      "no2Value": "",
      "numOfRows": "10",
      "o3Grade": "",
      "o3Value": "",
      "pageNo": "1",
      "pm10Grade": "",
      "pm10Grade1h": "",
      "pm10Value": "",
      "pm10Value24": "",
      "pm25Grade": "",
      "pm25Grade1h": "",
      "pm25Value": "",
      "pm25Value24": "",
      "resultCode": "",
      "resultMsg": "",
      "rnum": 0,
      "serviceKey": "g5wuVXrLzJMBI9kR2gmdXm6ltsn0zYEicoOG7g2xNHZnGZVp9v7znsIO45M2l7R6rlE5wiD/jtIZupMYvyN2Pg==",
      "sidoName": "군산",
      "so2Grade": "",
      "so2Value": "",
      "stationCode": "",
      "stationName": "",
      "totalCount": "",
      "ver": "1.3"
      },
      "totalCount": 40
      }
      

      리턴 값이 많이 복잡하고 빈 값도 많이 리턴한다.
      구조를 만들 때 initializer 를 붙여주고 optional을 붙여주어야 한다. (안하면 오류남)

      struct AqiResponseString: Codable {
      let list: [ArpltnInforInqireSVCVo]?
      let parm, arpltnInforInqireSVCVo: ArpltnInforInqireSVCVo?
      let totalCount: Int?
      
      enum CodingKeys: String, CodingKey {
      case list, parm
      case arpltnInforInqireSVCVo
      case totalCount
      }
      }
      
      extension AqiResponseString {
      ...
      }
      
      struct ArpltnInforInqireSVCVo: Codable {
      ...
      }
      
      extension ArpltnInforInqireSVCVo {
      ..
      }
      

      이 사이트 를 많이 참고해 만들었다.

      일부 enum 값을 String 으로 모두 변환해주었다. (그대로 쓸 수 없었다)
      생각보다 까다롭고 복잡해서 여기에 시간을 가장 많이 쏟았다 ,, 아무튼 좋은 API 는 아닌 것 같다

       

      4. Connect to API

      API 와 연결할 준비를 모두 마쳤으니 이제 연결해보자

      do {
      let responseString = try String(contentsOf: url)
      guard let data = responseString.data(using: .utf8) else { return }
      
      do {
      ..
      } catch (let err) {
      ..
      }
      
      } catch let e as NSError {
      print(e.localizedDescription)
      }
      

      의외로 연결 코드는 간단하다.
      먼저 string 형태로 리턴값을 저장한 후 utf8 로 인코딩 시켜준다.

      do {
      let decoder = JSONDecoder()
      
      let object = try decoder.decode(AqiResponseString.self, from: data)
      
      } catch (let err) {
      print(err.localizedDescription)
      }
      

      그리고 다시 JSONDecoder로 decode 해준다.

      var aqiDataSet = [AqiResponseString]()
      
      self.aqiDataSet = [object] as! [AqiResponseString]
      
      self.misaeLabel.text = self.aqiDataSet[0].list![0].pm25Value
      self.dateLabel.text = self.aqiDataSet[0].list![0].dataTime
      

      decode 한 데이터를 배열 aqiDataSet 에 넣어준 후 원하는 값을 가져온다.

      연결 성공 ‼️

       

      실행 화면

       

    • 야곰
      키 마스터
      • 글작성 : 37
      • 답글작성 : 579

      좋은 글 열심히 쓰셨는데 왜 들여쓰기가 안될까요? 들여쓰기 잘 동작하도록 사이트 수정 해뒀는데 글 쓸 때 문제가 있나요? ㅠㅠ 좋은 글이 보기 어렵게 되어있어 속상하고 아쉽네요ㅠ
      글을 작성하는데 어떤 문제가 있는지, 어떤 과정으로 글을 쓰는데 들여쓰기도 안되고 특수문자가 HTML 태그로 나오는지 원인을 알고 싶은데, 혹시 그 과정에 대해 간략히 알려줄 수 있나요?
      좀 더 나은 환경을 만들 수 있게 노력해볼게요.

      Array의 첫 번째 요소를 가져오는 방법은 aqiDataSet[0] 보다는 aqiDataSet.first를 사용하는 것이 훨씬 안전합니다. 배열에 요소가 한개도 없으면 aqiDataSet[0]은 런타임 오류가 발생하거든요.
      그래서 aqiDataSet.first?.list?.first?.pm25Value가 훨씬 안전한 코드가 되겠습니다.

      또, 옵셔널 추출을 위해 느낌표(!)를 많이 사용하고 있는데, 최대한 느낌표를 지양하는 것이 좋겠습니다.
      자꾸 느낌표 찍는 습관을 들이면 나중에 아주 크게 힘든 날이 오게 됩니다…
      대학교 과제만 하고 스위프트 안쓸거면 괜찮은데, 계속 스위프트 사용할 것이라면 느낌표보다는 물음표를 찍는 습관을 들이는 것이 좋습니다.
      스위프트 뿐만 아니라 최근에 나온 언어는 대부분 옵셔널 개념을 갖고 있으므로 잘 알아둬야 합니다.
      옵셔널 값 추출 레슨을 한 번 다시 보면 좋습니다. 5분이라 분량도 길지 않아요~

      [object] as! [AqiResponseString]
      

      guard let aqiDataSet: [AqiResponseString] = [object] as? [AqiResponseString] else { return }
      

      정도로 바꿔보면 어떨까요?

      • 이 답변은 야곰에 의해 4 years, 6 months 전에 수정됐습니다.
1 답변 글타래를 보이고 있습니다
  • 답변은 로그인 후 가능합니다.

logo landscape small

사업자번호 : 743-81-02195
통신판매업 신고번호 : 제 2022-충북청주-1278 호
고객센터 : 카카오톡채널 @yagom