[WEB] PHP - cURL 이용한 API 사용 feat. Ajax

Profile-exe·2021년 8월 24일
0

web

목록 보기
10/11
post-thumbnail

요즘 공모전을 보면 공공데이터를 활용하는 것들이 많다. 이 공공데이터는 데이터 자체를 이용할 수도 있지만, API를 이용하여 데이터를 서버에서 얻어올 수 있다.

PHP에서는 JavaScriptfetch API와 유사한 기능을 가진 cURL(Client URL Library)가 존재한다.

이번 포스트에서는 식품의약품안전처 데이터활용서비스식품영양성분DB(NEW) APIPHP에서 사용해보도록 하겠다.


API 사용 준비

식품 안전 나라 홈페이지에서 식품영양성분DB(NEW)를 검색하면 해당 API를 사용할 수 있다. OPEN-API란의 API 인증키를 요청하는 버튼 OpenAPI 이용 신청 이 있다. 회원가입 및 로그인 후 이 버튼을 클릭해서 API 인증키를 발급받을 수 있다.

식품영양성분DB(NEW) API

API 인증키는 홈페이지 상단의 인증키 관리 -> 인증키 신청 현황에서 인증키 발급 정보 및 API 신청 목록 조회가 가능하다.

인증키 신청 현황

여기서 발급된 인증키를 복사해서 코드에서 사용할 것이다.

데이터활용 서비스 이미지

API 요청 인자 목록

해당 API에 대해 알아보면, URL형식으로만 불러오므로 GET 요청으로 데이터를 받아올 수 있다.

🚨주의🚨

Client Side에서 JavaScript 코드로 API를 사용하는 경우 CORS 때문에 요청이 불가능할 수 있다. 그렇기 때문에 PHP를 사용해 Server Side에서 API를 사용하는 것이다.

요청인자keyId요청주소의 샘플에 나온 I2790이다.


fetch API를 이용한 Ajax

클라이언트에서 데이터 요청을 하면 PHPfetch API를 이용해서 비동기적으로 요청을 한다(Ajax).

위에 첨부한 이미지를 잘 보면,
필수 요청인자들은 /인자/인자/... 이런식으로 URL에 붙이고, 선택 요청인자들은 Query String으로 매개변수를 넣어주는 식으로 되어있다.

요청인자들은 객체에 담아서 이용하기 편하게 했다.

const essential_params = {	// 필수 요청 인자들
    keyId: '자신의 API 인증키 입력',
    serviceId: 'I2790',		// 샘플에 나와있음
    dataType: 'json',		// 중요!! 받은 데이터 object로 파싱하기
    startIdx: 1,
    endIdx: 15
};

// 필수 인자들 "/../../.." 형식으로 url에 붙여주기
let url = `http://openapi.foodsafetykorea.go.kr/api/`
for (const key in essential_params) {
    url += `${essential_params[key]}/`
}

// 선택 요청 인자들
const params = {
    DESC_KOR: '',
    RESEARCH_YEAR: '',
    MAKER_NAME: '',
    FOOD_CD: '',
}

// fetch API에서 사용할 request body
// PHP에서 $객체->url, $객체->params 형태로 사용된다.
const request_body = {
    url: url,
    params: params
}

// fetch API에 넣을 init 객체
const init = {
    method: 'POST',
    mode: 'cors',	// 기본값이 cors이다.
    headers: {          // json 형식과 인코딩 명시
        'Content-type': 'application/json; charset=utf-8',
    },
    body: JSON.stringify(request_body),	// json으로 파싱!!
}

fetch('api.php', init)
    .then((res) => res.json()) // json을 돌려주므로 json()을 이용해 객체로 파싱
    .then((data) => {	       // 이 내용은 바로 아래에서 설명
        const res_obj = data.I2790;
        console.log(res_obj.RESULT);
        console.log(res_obj.row);
    });

Postman을 이용한 API 테스트

Postman 홈페이지

이 프로그램을 이용하면 아주 간편하게 API를 테스트할 수 있다.

Workspaces -> 왼쪽의 Collections -> +를 눌러 새로운 Collection 생성 -> Collection 이름 옆의 ... 누르고 Add request

Postman request 생성 이미지

METHODDEFAULT값은 GET이다.
위의 첨부된 API 요청 주소 이미지를 참고해서 URL을 넣어서 Send하면 결과를 표시해준다.

Postman 사용해서 요청 및 데이터 확인

받은 데이터는 JSON형태로 값은 다음과 같다. 맨 밑줄 ...는 생략

{
    "I2790": {
        "RESULT": {
            "MSG": "정상처리되었습니다.",
            "CODE": "INFO-000"
        },
        "total_count": "59886",
        "row": [
            {
                "NUTR_CONT3": "33.5",
                "NUTR_CONT2": "39.7",
                "NUTR_CONT1": "368.8",
                "SERVING_SIZE": "500",
                "MAKER_NAME": "",
                "NUTR_CONT9": "0.1",
                "NUTR_CONT8": "1.9",
                "FOOD_CD": "D000006",
                "NUTR_CONT7": "106.18",
                "NUTR_CONT6": "1264.31",
                "NUTR_CONT5": "16.9",
                "NUTR_CONT4": "8.5",
                "DESC_KOR": "꿩불고기",
                "SAMPLING_MONTH_NAME": "평균",
                "SUB_REF_NAME": "식약처('16) 제4권",
                "SAMPLING_REGION_NAME": "충주",
                "GROUP_NAME": "",
                "RESEARCH_YEAR": "2019",
                "SAMPLING_REGION_CD": "94",
                "SAMPLING_MONTH_CD": "AVG",
                "NUM": "1"
            },
          ...

이것을 통해 JavaScript 코드의 하단에 있던 fetch API에서 다음과 같이 사용한 이유가 나온다.

fetch('api.php', init)
    .then((res) => res.json()) // json을 돌려주므로 json()을 이용해 객체로 파싱
    .then((data) => {	       // 이 내용은 바로 아래에서 설명
        const res_obj = data.I2790;
        console.log(res_obj.RESULT);
        console.log(res_obj.row);
    });

맨 처음 API 아이디(keyId)가 나오고 그 아래 RESULT, total_count, row가 있고, row안에 데이터가 들어있는 형태이다.

그래서 data.I2790res_obj에 저장한 후 RESULTrow를 출력한 것이다. 콘솔창을 확인해보면 다음과 같이 출력된다.

API 호출 후 Console 확인


cURL - Client URL Library

curl - PHP document

PHP는 Daniel Stenberg가 만든 라이브러리인 libcurl을 지원하므로 다양한 유형의 프로토콜을 사용하여 다양한 유형의 서버에 연결하고 통신할 수 있습니다. libcurl은 현재 http, https, ftp, gopher, telnet, dict, file 및 ldap 프로토콜을 지원합니다. libcurl은 또한 HTTPS 인증서, HTTP POST, HTTP PUT, FTP 업로드(PHP의 ftp 확장으로도 수행 가능), HTTP 양식 기반 업로드, 프록시, 쿠키 및 사용자+암호 인증을 지원합니다.

위에 서술된 여러 프로토콜로 데이터를 create, read, update, delete 할 수 있는 라이브러리다.

사용법

Basic curl example - PHP document

$ch = curl_init("http://www.example.com/");
$fp = fopen("example_homepage.txt", "w");

curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);

curl_exec($ch);
if(curl_error($ch)) {
    fwrite($fp, curl_error($ch));
}

curl_close($ch);
fclose($fp);
  • curl_init() : cURL session 초기화
  • curl_setopt() : 전송을 위한 옵션 지정
  • curl_exec() : session 실행
  • curl_close() : session 종료

cURL을 이용해 PHP에서 API 사용

앞의 JavaScript 코드로 AjaxPHP에 요청 시 해당 데이터를 가지고 API를 사용하는 코드이다.

여기서 http_build_query()함수가 사용되었는데, 객체의 내용을 Query String으로 변경해주는 함수이다. 특정 반복문 필요 없이 간단하게 이 함수만 호출하면 되므로 매우 유용하다.

이를 이용하기 위해서 JS에서 보낸 선택 요청 인자들을 객체로 저장해둔 것이다.

function empty_filter($obj) {	// 선택 인자의 값이 없으면("") 제거
    foreach ($obj as $key => $value) {
        if (empty($value)) {
            unset($obj->$key);
        }
    }
    return $obj;
}

// fetch API로 보낸 request_body는 json 형태이므로 파싱 해서 PHP 객체로 사용
$ajax_data = json_decode(file_get_contents('php://input'));

// 위의 필터링 함수를 사용해 불필요한 값 제거
$filtered_params = empty_filter(array($ajax_data->params)[0]);

// http_build_query() 함수로 객체를 QueryString으로 만들어준다.
$query = http_build_query($filtered_params);

// 선택 요청 인자가 존재하는 경우 붙여주기
// 존재하지 않는다면 url은 그대로이다.
$url = $ajax_data->url .= $query ? '?'.$query : '';

// curl에 적용할 옵션들을 저장
$options = array(
    CURLOPT_URL => $url,	// 최종 url도 이때 넣어준다.
    CURLOPT_RETURNTRANSFER => true,  // 반환된 값을 string으로 변환해 저장
    CURLOPT_SSL_VERIFYPEER => false, // true인 경우 https 통신이 불가한 경우 발생
);

// curl 세션 초기화
$ch = curl_init();

// 이것도 유용한 함수 array를 받아서 한번에 옵션을 지정
curl_setopt_array($ch, $options);

// 실행 -> API 서버에서 반환한 데이터를 $response 변수에 저장한다.
$response = curl_exec($ch);	

// 세션 종료
curl_close($ch);

echo $response;	// JSON 형태이므로 JavaScript에서 json()을 통해 파싱

🍯꿀팁

1. http_build_query()

URLQuery String을 넣어줄 때, 반복문이나 하드코딩 없이 http_build_query() 함수를 사용해서 매우 간편하게 넣어줄 수 있다.

key, value 쌍을 array객체에 저장하고 이것을 함수에 넣어주면 키=값&키=값&키=값&... 형태의 Query String으로 변환되는 것이다.

2. curl_setopt_array()

인터넷에서 여러 코드들을 보면 curl 옵션 지정 시 이렇게 사용한다.

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

깔끔해보이지 않고, 여러 옵션들을 한번에 적용하고 싶어서 알아보니 curl_setopt_array()가 존재했다.

이를 사용하면 설정할 옵션들을 한 변수에서 관리 가능하며, 옵션 적용도 한줄이면 되니 매우 간편하고 가독성도 증가했다.

// curl에 적용할 옵션들을 저장
$options = array(
    CURLOPT_URL => $url,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_SSL_VERIFYPEER => false,
);

$ch = curl_init();

// array를 받아서 한번에 옵션을 지정
curl_setopt_array($ch, $options);

이렇게 말이다.

유지보수와 가독성을 위해서 간단하고 명확한 코드 사용은 중요하다 생각한다. 비록 이건 큰 차이점이 없어보이지만 다음 상황에서는 큰 차이를 보일 수 있다.

  • 옵션 추가 및 삭제를 자주 하는 경우

  • 옵션에 대한 데이터를 객체로 받아오는 경우

    데이터를 포함한 객체의 key, valuearray객체에 저장하고 curl_setopt_array()array객체 넣기

  • 코드의 길이가 증가하는 경우 가독성을 유지하기 위해


정리

  • CORS 때문에 API 사용(호출)은 서버쪽에서 진행 (여기서는 PHP)

  • API 사용 시 필요한 데이터는 객체로 저장하여 보내기 (코드 간결 & 가독성 증가)

  • 쿼리 스트링은 http_build_query() 사용하기

  • cURL의 옵션 설정은 옵션들을 array에 저장 후 curl_setopt_array() 사용하기


API 예제 repository

Profile-exe/API Test Example - Github

profile
컴퓨터공학과 학부생

0개의 댓글