[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에 대해 알아보면, 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

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

받은 데이터는 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를 출력한 것이다. 콘솔창을 확인해보면 다음과 같이 출력된다.


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개의 댓글