Slim Framework로 RESTful API 서버 구축하기 🚀
안녕하세요, 코딩 열정 가득한 여러분! 오늘은 정말 흥미진진한 주제로 여러분과 함께 시간을 보내려고 해요. 바로 Slim Framework를 사용해 RESTful API 서버를 구축하는 방법에 대해 알아볼 거예요. 🎉
여러분, 혹시 요리를 좋아하시나요? API 서버 구축을 요리에 비유해볼게요. 우리가 맛있는 요리를 만들 때 재료와 레시피가 필요하듯이, API 서버를 만들 때도 좋은 도구와 방법이 필요해요. 그리고 오늘 우리의 주방장 도구는 바로 Slim Framework랍니다! 🍳👨🍳
재능넷 팁: API 개발 능력은 현대 웹 개발에서 매우 중요한 스킬이에요. 재능넷에서 API 개발 관련 강의를 들어보는 것은 어떨까요? 여러분의 개발 실력 향상에 큰 도움이 될 거예요! 💡
자, 이제 우리의 요리... 아니, 개발 여정을 시작해볼까요? 앞치마를 매고, 코딩 에디터를 켜세요. 우리는 지금부터 아주 맛있는 API 서버를 만들어볼 거예요! 🥘➡️💻
1. Slim Framework 소개: 우리의 주방장 도구 🔧
Slim Framework는 PHP로 작성된 강력하고 가벼운 마이크로 프레임워크예요. 마치 요리사의 날카로운 칼처럼, Slim은 우리가 RESTful API를 빠르고 효율적으로 만들 수 있게 도와주죠. 🔪✨
1.1 Slim Framework의 특징
- 가볍고 빠름: 필요한 기능만 담겨 있어 가볍고 빠른 성능을 자랑해요.
- 유연성: 다양한 미들웨어와 확장 기능을 지원해 개발자의 필요에 맞게 커스터마이징이 가능해요.
- PSR-7 호환: HTTP 메시지 인터페이스 표준을 준수해 다른 라이브러리와의 호환성이 뛰어나요.
- 강력한 라우팅: URL 패턴 매칭, HTTP 메소드 제한 등 다양한 라우팅 기능을 제공해요.
Slim Framework는 마치 요리사의 믿음직한 조수처럼 우리의 API 개발을 도와줄 거예요. 복잡한 대형 프레임워크의 무거움 없이, 필요한 기능만 쏙쏙 골라 사용할 수 있답니다. 👨🍳👩🍳
재능넷 활용 팁: Slim Framework를 배우면서 어려움을 겪고 계신가요? 재능넷에서 PHP 전문가들의 도움을 받아보세요. 1:1 코칭이나 프로젝트 리뷰 서비스를 통해 더 빠르게 성장할 수 있어요! 🌱
1.2 Slim Framework vs 다른 PHP 프레임워크
Slim을 다른 유명한 PHP 프레임워크들과 비교해볼까요? 마치 다양한 요리 도구를 비교하는 것처럼 재미있을 거예요! 🍽️
이 비교를 통해 우리는 Slim Framework가 얼마나 가볍고 효율적인지 알 수 있어요. 마치 요리사가 간단한 요리를 빠르게 만들 때 사용하는 작고 날렵한 칼과 같죠. 🔪
하지만 기억하세요, 모든 도구가 그렇듯 각 프레임워크는 자신만의 장단점이 있어요. Slim은 특히 API 개발에 최적화되어 있고, 빠른 프로토타이핑에 적합하답니다. 마치 요리 대회에서 신속하게 요리를 선보여야 할 때 사용하는 도구와 같아요! 🏆
1.3 Slim Framework의 역사와 발전
Slim Framework의 역사를 살펴보는 것은 마치 유명 레스토랑의 성공 스토리를 듣는 것과 같아요. 흥미진진하고 영감을 주는 이야기죠! 📚✨
- 2009년: Josh Lockhart에 의해 개발 시작
- 2010년: Slim 1.0 버전 출시
- 2012년: Slim 2.0 버전 출시, 미들웨어 지원 추가
- 2015년: Slim 3.0 버전 출시, PSR-7 지원
- 2019년: Slim 4.0 버전 출시, PHP 7.1 이상 지원
Slim Framework는 계속해서 진화하고 있어요. 마치 요리사가 새로운 조리법을 개발하고 더 나은 맛을 추구하는 것처럼, Slim도 더 나은 개발 경험을 제공하기 위해 노력하고 있답니다. 🚀
🌟 흥미로운 사실: Slim Framework의 이름은 그 특성을 잘 반영하고 있어요. '날씬하다(Slim)'는 뜻처럼, 필요한 기능만을 가볍게 담고 있죠. 마치 요리사가 꼭 필요한 도구만 모아놓은 작은 주방 세트와 같아요!
자, 이제 우리의 주방장 도구인 Slim Framework에 대해 알아봤어요. 이 강력하고 유연한 도구로 우리는 정말 맛있는 API를 요리해낼 수 있을 거예요. 다음 섹션에서는 실제로 Slim을 설치하고 기본 설정을 해보도록 할게요. 요리... 아니, 코딩을 시작할 준비 되셨나요? Let's go! 🚀👩💻👨💻
2. Slim Framework 설치 및 기본 설정: 주방 준비하기 🍳
자, 이제 우리의 주방... 아니, 개발 환경을 준비할 시간이에요! Slim Framework를 설치하고 기본 설정을 하는 과정은 마치 요리를 시작하기 전 주방을 정리하고 필요한 도구들을 꺼내놓는 것과 같아요. 깔끔하고 체계적으로 준비해야 맛있는 요리... 음, 훌륭한 API가 나올 수 있겠죠? 😉
2.1 개발 환경 준비
먼저, 우리의 주방... 아니 개발 환경을 준비해볼까요? 🏗️
- PHP 7.3 이상: Slim 4는 PHP 7.3 이상의 버전을 요구해요. 최신 버전의 PHP를 사용하는 것이 좋아요.
- Composer: PHP의 의존성 관리 도구예요. 마치 요리 재료를 관리하는 냉장고 같죠!
- 웹 서버: Apache나 Nginx를 사용할 수 있어요. 로컬 개발 환경이라면 PHP의 내장 웹 서버도 좋아요.
- 텍스트 에디터 또는 IDE: VS Code, PHPStorm 등 편한 것을 사용하세요. 요리사의 칼처럼 중요한 도구예요!
🚨 주의사항: PHP 버전이 7.3 미만이라면 꼭 업그레이드하세요! 오래된 재료로는 맛있는 요리를 할 수 없듯이, 오래된 PHP 버전으로는 최신 Slim을 사용할 수 없어요.
2.2 Composer를 이용한 Slim Framework 설치
자, 이제 실제로 Slim을 설치해볼까요? Composer를 사용하면 정말 쉽게 설치할 수 있어요. 마치 요리 재료를 배달 시키는 것처럼 간편하답니다! 🚚💨
터미널을 열고 프로젝트 디렉토리로 이동한 후, 다음 명령어를 입력해주세요:
composer require slim/slim:"4.*"
이 명령어는 Slim 4 버전을 설치해요. 그리고 Slim과 함께 사용할 PSR-7 구현체도 필요해요. 우리는 Slim-PSR7을 사용할 거예요:
composer require slim/psr7
와우! 이제 우리의 주방에 핵심 도구들이 준비되었어요. 🎉
2.3 프로젝트 구조 설정
이제 우리의 프로젝트 구조를 만들어볼까요? 깔끔한 주방이 좋은 요리의 기본이듯, 잘 정리된 프로젝트 구조는 효율적인 개발의 기본이에요. 🏠
다음과 같은 구조를 만들어보세요:
project_root/
│
├── public/
│ └── index.php
│
├── src/
│ ├── controllers/
│ ├── models/
│ └── middleware/
│
├── config/
│
├── logs/
│
└── vendor/
- public/: 웹 서버의 문서 루트가 될 디렉토리예요. index.php가 여기 있어요.
- src/: 애플리케이션의 소스 코드가 위치할 곳이에요.
- config/: 설정 파일들을 저장할 디렉토리예요.
- logs/: 로그 파일을 저장할 곳이에요.
- vendor/: Composer가 의존성 패키지들을 설치하는 곳이에요.
이렇게 구조를 잡으면 프로젝트가 커져도 관리하기 쉬워요. 마치 잘 정리된 주방에서 요리하는 것처럼 편안하게 개발할 수 있을 거예요! 😊
2.4 기본 설정 파일 만들기
이제 우리 애플리케이션의 기본 설정을 해볼까요? 설정 파일은 마치 요리의 레시피와 같아요. 어떤 재료를 어떻게 사용할지 정해주는 거죠. 📝
config/settings.php
파일을 만들고 다음과 같이 작성해보세요:
<?php
return [
'displayErrorDetails' => true, // 개발 환경에서만 true로 설정하세요!
'addContentLengthHeader' => false, // 알림: 특정 서버 설정에 필요할 수 있어요
'db' => [
'host' => 'localhost',
'user' => 'database_user',
'pass' => 'database_password',
'dbname' => 'database_name',
],
];
이 설정 파일은 우리 애플리케이션의 전반적인 동작을 제어해요. 개발 중에는 에러를 상세히 보여주도록 설정했지만, 실제 서비스할 때는 보안을 위해 displayErrorDetails
를 false
로 바꿔야 해요!
💡 프로 팁: 설정 파일의 값들은 환경 변수를 통해 관리하는 것이 좋아요. 이렇게 하면 개발 환경, 테스트 환경, 실제 서비스 환경에서 각각 다른 설정을 쉽게 적용할 수 있어요!
2.5 index.php 파일 설정
마지막으로, 우리 애플리케이션의 진입점인 public/index.php
파일을 설정해볼까요? 이 파일은 마치 레스토랑의 입구와 같아요. 모든 요청이 여기서 시작되죠! 🚪
<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
require __DIR__ . '/../vendor/autoload.php';
$settings = require __DIR__ . '/../config/settings.php';
$app = AppFactory::create();
// 미들웨어 추가
$app->addErrorMiddleware(true, true, true);
// 라우트 정의
$app->get('/', function (Request $request, Response $response) {
$response->getBody()->write("Hello, World!");
return $response;
});
$app->run();
이 파일에서 우리는:
- 필요한 클래스들을 use 문으로 가져왔어요.
- Composer의 autoloader를 로드했어요.
- 설정 파일을 불러왔어요.
- Slim 애플리케이션 인스턴스를 생성했어요.
- 에러 처리 미들웨어를 추가했어요.
- 간단한 "Hello, World!" 라우트를 정의했어요.
- 애플리케이션을 실행했어요.
와! 이제 우리의 Slim Framework 주방이 완벽하게 준비되었어요. 🎊
🌟 재능넷 활용 팁: Slim Framework 설정에 어려움을 겪고 계신가요? 재능넷에서 PHP 전문가의 도움을 받아보세요. 1:1 코칭을 통해 여러분의 개발 환경을 완벽하게 설정할 수 있을 거예요!
자, 이제 우리의 주방... 아니, 개발 환경이 완벽하게 준비되었어요! 다음 섹션에서는 실제로 RESTful API를 만들어보면서 Slim Framework의 강력한 기능들을 하나씩 살펴볼 거예요. 요리... 아니, 코딩의 세계로 더 깊이 들어가볼 준비 되셨나요? Let's code! 💻🚀
3. RESTful API 기본 개념: 요리의 기본 원칙 🍽️
자, 이제 우리의 주방(개발 환경)이 완벽하게 준비되었으니, 본격적으로 요리... 아니, API 개발을 시작해볼까요? 하지만 그전에, RESTful API가 정확히 무엇인지, 그리고 왜 중요한지 알아볼 필요가 있어요. 마치 요리를 시작하기 전에 기본적인 조리 원칙을 이해하는 것과 같죠! 🧑🍳
3.1 REST란 무엇인가?
REST는 "Representational State Transfer"의 약자로, 웹 서비스를 디자인하는 아키텍처 스타일이에요. 음... 조금 어렵게 들리나요? 쉽게 설명해볼게요! 🤔
REST는 마치 레스토랑의 주문 시스템과 같아요. 손님(클라이언트)이 메뉴(리소스)를 보고 주문(요청)을 하면, 주방(서버)에서 요리를 만들어 제공(응답)하는 거죠. 이 과정에서 손님과 주방은 정해진 규칙(HTTP 메소드)에 따라 소통해요.
🍔 맛있는 비유: REST를 햄버거 가게로 생각해보세요. 메뉴(API 엔드포인트)에서 햄버거(리소스)를 선택하고, 주문 방식(HTTP 메소드)을 정해 주문합니다. 가게(서버)는 주문에 따라 햄버거를 만들어 제공(응답)하죠. 간단하죠? 😋
3.2 RESTful API의 주요 특징
RESTful API는 다음과 같은 특징을 가지고 있어요:
- 클라이언트-서버 구조: 주방과 손님이 분리되어 있듯이, 서버와 클라이언트의 역할이 명확히 구분돼요.
- 무상태(Stateless): 각 요청은 독립적이에요. 마치 매번 새로운 손님이 주문하는 것처럼요.
- 캐시 가능: 자주 주문되는 메뉴를 미리 준비해두는 것처럼, 응답을 캐시할 수 있어요.
- 계층화 시스템: 주방, 서빙, 캐셔 등이 역할을 나누듯 시스템을 계층화할 수 있어요.
- 균일한 인터페이스: 모든 주문은 동일한 방식으로 이루어지듯, API 사용 방식이 일관적이에요.
3.3 HTTP 메소드: API의 주문 방식
RESTful API에서는 HTTP 메소드를 사용해 리소스에 대한 행동을 정의해요. 이는 마치 레스토랑에서 주문하는 방식과 비슷해요:
- GET: 리소스를 조회해요. 메뉴를 보는 것과 같죠.
- POST: 새로운 리소스를 생성해요. 새로운 주문을 하는 거예요.
- PUT: 리소스를 완전히 대체해요. 주문을 완전히 바꾸는 거죠.
- PATCH: 리소스를 부분적으로 수정해요. 주문의 일부를 변경하는 것과 같아요.
- DELETE: 리소스를 삭제해요. 주문을 취소하는 것과 비슷하죠.
이러한 HTTP 메소드를 사용하면, API의 의도를 명확하게 표현할 수 있어요. 마치 레스토랑에서 "주문이요", "변경이요", "취소요" 라고 말하는 것처럼 말이죠! 😄
3.4 RESTful API의 장점
RESTful API를 사용하면 여러 가지 이점이 있어요:
- 확장성: 클라이언트와 서버가 독립적이어서 각각 확장하기 쉬워요.
- 유연성: 다양한 형식(JSON, XML 등)으로 데이터를 주고받을 수 있어요.
- 독립성: 플랫폼이나 언어에 종속되지 않아요.
- 가시성: HTTP 프로토콜을 사용하므로 모니터링과 로깅이 쉬워요.
🌟 재능넷 활용 팁: RESTful API 설계에 대해 더 깊이 알고 싶으신가요? 재능넷에서 제공하는 'RESTful API 디자인 마스터 클래스'를 들어보는 건 어떨까요? 전문가의 노하우를 직접 배울 수 있답니다!
3.5 RESTful API 설계 원칙
좋은 RESTful API를 설계하기 위해서는 몇 가지 원칙을 따라야 해요. 마치 맛있는 요리를 만들기 위한 황금률과 같죠! 🏆
- 리소스 중심 설계: URL은 리소스를 나타내야 해요. 동사보다는 명사를 사용하세요.
- 적절한 HTTP 메소드 사용: 각 작업의 의도에 맞는 HTTP 메소드를 사용하세요.
- 계층 구조로 설계: 리소스 간의 관계를 URL 구조에 반영하세요.
- 버전 관리: API의 큰 변경이 있을 때는 버전을 명시하세요.
- 에러 처리: 명확하고 일관된 에러 메시지를 제공하세요.
이러한 원칙을 따르면, 사용하기 쉽고 이해하기 쉬운 API를 만들 수 있어요. 마치 잘 정리된 메뉴판으로 손님들이 쉽게 주문할 수 있게 하는 것과 같죠! 📜✨
3.6 실제 RESTful API 예시
자, 이제 실제 RESTful API가 어떻게 생겼는지 살펴볼까요? 음식점 메뉴 관리 시스템을 예로 들어볼게요:
# 모든 메뉴 조회
GET /api/menus
# 새 메뉴 추가
POST /api/menus
# 특정 메뉴 조회
GET /api/menus/{id}
# 특정 메뉴 수정
PUT /api/menus/{id}
# 특정 메뉴 부분 수정
PATCH /api/menus/{id}
# 특정 메뉴 삭제
DELETE /api/menus/{id}
이렇게 설계하면 API의 의도가 명확히 드러나고, 사용하기도 쉬워져요. 마치 잘 정리된 주문서를 보는 것 같지 않나요? 😊
💡 실전 팁: API를 설계할 때는 항상 사용자의 입장에서 생각해보세요. "이 API를 사용하는 개발자가 쉽게 이해하고 사용할 수 있을까?"라고 자문해보는 것이 좋아요!
자, 이제 RESTful API의 기본 개념에 대해 알아봤어요. 이것은 마치 요리의 기본 원칙을 배운 것과 같아요. 이제 이 지식을 바탕으로 Slim Framework를 사용해 실제로 맛있는 API를 요리... 아니, 개발해볼 준비가 되었나요? 다음 섹션에서는 Slim Framework로 실제 RESTful API를 구현하는 방법을 자세히 알아볼 거예요. 요리사 모자를 단단히 쓰고, 앞치마를 매세요. 본격적인 코딩의 시간이 다가오고 있어요! 👨🍳👩🍳💻
4. Slim Framework로 RESTful API 구현하기: 요리 시작! 🍳
자, 이제 우리의 주방(개발 환경)도 준비되었고, 레시피(RESTful 원칙)도 익혔으니 본격적으로 요리... 아니, API 개발을 시작해볼까요? Slim Framework를 사용해 실제로 동작하는 RESTful API를 만들어보겠습니다. 앞치마 단단히 매시고, 코딩의 세계로 뛰어들어봐요! 🏊♂️💻
4.1 기본 라우팅 설정
먼저, 기본적인 라우팅을 설정해볼게요. 이는 마치 레스토랑에서 손님의 주문을 어떤 주방장에게 전달할지 정하는 것과 같아요. 🧑🍳
public/index.php
파일을 열고 다음과 같이 수정해주세요:
<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
require __DIR__ . '/../vendor/autoload.php';
$app = AppFactory::create();
$app->get('/api/menus', function (Request $request, Response $response) {
$response->getBody()->write("모든 메뉴를 가져옵니다.");
return $response;
});
$app->post('/api/menus', function (Request $request, Response $response) {
$response->getBody()->write("새 메뉴를 추가합니다.");
return $response;
});
$app->get('/api/menus/{id}', function (Request $request, Response $response, $args) {
$id = $args['id'];
$response->getBody()->write("메뉴 ID {$id}를 가져옵니다.");
return $response;
});
$app->run();
이렇게 하면 기본적인 GET과 POST 요청을 처리할 수 있는 라우트가 설정됩니다. 마치 주방에서 "모든 메뉴 보여주기", "새 메뉴 추가하기", "특정 메뉴 보여주기" 같은 기본 작업을 준비한 거죠! 🍽️
4.2 컨트롤러 분리하기
API가 복잡해지면 모든 로직을 index.php
에 넣는 것은 비효율적이에요. 컨트롤러를 분리해서 코드를 정리해봅시다. 이는 주방에서 각 요리사에게 특정 요리를 전담시키는 것과 비슷해요. 🧑🍳👩🍳
src/controllers/MenuController.php
파일을 만들고 다음과 같이 작성해주세요:
<?php
namespace App\Controllers;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
class MenuController
{
public function getAllMenus(Request $request, Response $response): Response
{
$response->getBody()->write("모든 메뉴를 가져옵니다.");
return $response;
}
public function addMenu(Request $request, Response $response): Response
{
$response->getBody()->write("새 메뉴를 추가합니다.");
return $response;
}
public function getMenu(Request $request, Response $response, $args): Response
{
$id = $args['id'];
$response->getBody()->write("메뉴 ID {$id}를 가져옵니다.");
return $response;
}
}
이제 index.php
를 수정해서 이 컨트롤러를 사용하도록 해볼까요?
<?php
use Slim\Factory\AppFactory;
use App\Controllers\MenuController;
require __DIR__ . '/../vendor/autoload.php';
$app = AppFactory::create();
$app->get('/api/menus', [MenuController::class, 'getAllMenus']);
$app->post('/api/menus', [MenuController::class, 'addMenu']);
$app->get('/api/menus/{id}', [MenuController::class, 'getMenu']);
$app->run();
와우! 이제 우리의 코드가 훨씬 깔끔해졌어요. 마치 주방이 잘 정리된 것 같지 않나요? 😊
4.3 미들웨어 추가하기
API에 미들웨어를 추가해볼까요? 미들웨어는 요청이 처리되기 전이나 후에 실행되는 코드예요. 이는 마치 요리가 손님에게 나가기 전에 마지막으로 점검하는 것과 같아요. 🕵️♂️
예를 들어, JSON 응답을 자동으로 처리하는 미들웨어를 만들어볼게요. src/middleware/JsonResponseMiddleware.php
파일을 만들고 다음과 같이 작성해주세요:
<?php
namespace App\Middleware;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
class JsonResponseMiddleware implements MiddlewareInterface
{
public function process(Request $request, RequestHandler $handler): Response
{
$response = $handler->handle($request);
return $response->withHeader('Content-Type', 'application/json');
}
}
이제 이 미들웨어를 index.php
에 추가해볼까요?
<?php
use Slim\Factory\AppFactory;
use App\Controllers\MenuController;
use App\Middleware\JsonResponseMiddleware;
require __DIR__ . '/../vendor/autoload.php';
$app = AppFactory::create();
$app->add(new JsonResponseMiddleware());
// 라우트 설정...
$app->run();
이렇게 하면 모든 응답이 자동으로 JSON 형식으로 변환됩니다. 손님에게 음식을 내기 전에 항상 예쁜 접시에 담아 내는 것과 같죠! 🍽️✨
4.4 데이터베이스 연동하기
실제 API는 대부분 데이터베이스와 연동되어 있어요. 데이터베이스를 연동하는 것은 마치 주방에 식재료 창고를 연결하는 것과 같아요. 🏬
여기서는 간단히 PDO를 사용해 MySQL 데이터베이스를 연결해볼게요. 먼저 config/database.php
파일을 만들고 다음과 같이 작성해주세요:
<?php
return [
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'restaurant_db',
'username' => 'root',
'password' => 'your_password',
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
];
이제 src/database/Database.php
파일을 만들어 데이터베이스 연결을 관리해볼까요?
<?php
namespace App\Database;
use PDO;
use PDOException;
class Database
{
private static $connection = null;
public static function getConnection(): PDO
{
if (self::$connection === null) {
$config = require __DIR__ . '/../../config/database.php';
$dsn = "{$config['driver']}:host={$config['host']};dbname={$config['database']};charset={$config['charset']}";
try {
self::$connection = new PDO($dsn, $config['username'], $config['password']);
self::$connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
self::$connection->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
} catch (PDOException $e) {
exit($e->getMessage());
}
}
return self::$connection;
}
}
이제 이 데이터베이스 연결을 사용해 실제 데이터를 다루는 MenuController를 수정해볼까요?
<?php
namespace App\Controllers;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use App\Database\Database;
class MenuController
{
private $db;
public function __construct()
{
$this->db = Database::getConnection();
}
public function getAllMenus(Request $request, Response $response): Response
{
$stmt = $this->db->query("SELECT * FROM menus");
$menus = $stmt->fetchAll();
$response->getBody()->write(json_encode($menus));
return $response;
}
public function addMenu(Request $request, Response $response): Response
{
$data = $request->getParsedBody();
$stmt = $this->db->prepare("INSERT INTO menus (name, price) VALUES (:name, :price)");
$stmt->execute([
'name' => $data['name'],
'price' => $data['price']
]);
$response->getBody()->write(json_encode(['message' => '메뉴가 추가되었습니다.']));
return $response->withStatus(201);
}
public function getMenu(Request $request, Response $response, $args): Response
{
$id = $args['id'];
$stmt = $this->db->prepare("SELECT * FROM menus WHERE id = :id");
$stmt->execute(['id' => $id]);
$menu = $stmt->fetch();
if ($menu) {
$response->getBody()->write(json_encode($menu));
} else {
$response->getBody()->write(json_encode(['message' => '메뉴를 찾을 수 없습니다.']));
return $response->withStatus(404);
}
return $response;
}
}
와우! 이제 우리의 API가 실제 데이터베이스와 연동되어 동작하고 있어요. 마치 진짜 레스토랑에서 주문을 받고, 요리를 만들어 내는 것 같지 않나요? 🍽️👨🍳
💡 보안 팁: 실제 프로덕션 환경에서는 데이터베이스 자격 증명을 환경 변수로 관리하는 것이 좋아요. 또한, 사용자 입력은 항상 검증하고 이스케이프 처리를 해야 SQL 인젝션 같은 보안 위협을 방지할 수 있어요!
4.5 에러 처리하기
마지막으로, API에 적절한 에러 처리를 추가해볼까요? 이는 마치 레스토랑에서 문제가 생겼을 때 손님에게 정중하게 설명하는 것과 같아요. 🙇♂️
src/handlers/HttpErrorHandler.php
파일을 만들고 다음과 같이 작성해주세요:
<?php
namespace App\Handlers;
use Psr\Http\Message\ResponseInterface;
use Slim\Exception\HttpException;
use Slim\Handlers\ErrorHandler;
class HttpErrorHandler extends ErrorHandler
{
protected function respond(): ResponseInterface
{
$exception = $this->exception;
$statusCode = 500;
$message = 'An internal error has occurred.';
if ($exception instanceof HttpException) {
$statusCode = $exception->getCode();
$message = $exception->getMessage();
}
$encodedPayload = json_encode([
'status' => 'error',
'message' => $message,
], JSON_PRETTY_PRINT);
$response = $this->responseFactory->createResponse($statusCode);
$response->getBody()->write($encodedPayload);
return $response->withHeader('Content-Type', 'application/json');
}
}
이제 이 에러 핸들러를 index.php
에 추가해볼까요?
<?php
use Slim\Factory\AppFactory;
use App\Controllers\MenuController;
use App\Middleware\JsonResponseMiddleware;
use App\Handlers\HttpErrorHandler;
require __DIR__ . '/../vendor/autoload.php';
$app = AppFactory::create();
$errorMiddleware = $app->addErrorMiddleware(true, true, true);
$errorHandler = new HttpErrorHandler($app->getCallableResolver(), $app->getResponseFactory());
$errorMiddleware->setDefaultErrorHandler($errorHandler);
$app->add(new JsonResponseMiddleware());
// 라우트 설정...
$app->run();
이렇게 하면 API에서 발생하는 모든 에러가 일관된 형식으로 처리됩니다. 손님에게 항상 정중하고 명확한 설명을 제공하는 것과 같죠! 👍
🌟 재능넷 활용 팁: API 개발에 어려움을 겪고 계신가요? 재능넷에서 'RESTful API 개발 마스터 클래스'를 수강해보세요. 실제 프로젝트 경험이 풍부한 전문가들이 여러분의 실력 향상을 도와드릴 거예요!
자, 이제 우리는 Slim Framework를 사용해 기본적인 RESTful API를 구현해봤어요. 라우팅, 컨트롤러, 미들웨어, 데이터베이스 연동, 에러 처리까지... 마치 완벽한 레스토랑을 차린 것 같지 않나요? 🍽️🎉
이제 여러분은 이 기본 구조를 바탕으로 더 다양하고 복잡한 API를 만들어낼 수 있을 거예요. 메뉴 업데이트, 삭제 기능을 추가하거나, 사용자 인증을 구현하거나, 더 복잡한 비즈니스 로직을 추가해볼 수 있겠죠.
API 개발의 세계는 정말 넓고 깊답니다. 계속해서 학습하고, 실험하고, 개선해나가세요. 여러분의 API 요리 실력이 날로 발전할 거예요! 👨🍳👩🍳💻
5. API 테스트 및 문서화: 맛보기와 메뉴판 만들기 🍴📜
자, 이제 우리의 맛있는 API 요리가 완성되었어요! 하지만 요리가 맛있다고 해서 끝난 게 아니죠. 손님들이 우리의 요리를 맛있게 먹을 수 있도록 시식해보고(테스트), 멋진 메뉴판(문서)도 만들어야 해요. 그래야 우리의 API 레스토랑이 대박날 수 있겠죠? 😉
5.1 API 테스트하기
API를 테스트하는 것은 요리사가 음식을 맛보는 것과 같아요. 우리가 의도한 대로 동작하는지, 맛있게(올바르게) 작동하는지 확인해야 해요. 🥄
API 테스트를 위해 우리는 Postman이라는 강력한 도구를 사용할 거예요. Postman은 마치 전문 시식가와 같아서, 우리의 API를 꼼꼼히 테스트해줄 수 있답니다. 🧑🍳
- Postman 설치: Postman 웹사이트에서 Postman을 다운로드하고 설치하세요.
- 새로운 요청 생성: Postman에서 새로운 요청을 만들고, URL을 입력하세요. (예: http://localhost:8000/api/menus)
- HTTP 메소드 선택: GET, POST, PUT, DELETE 등 적절한 HTTP 메소드를 선택하세요.
- 파라미터 및 헤더 설정: 필요한 경우 파라미터나 헤더를 추가하세요.
- 요청 전송 및 응답 확인: Send 버튼을 눌러 요청을 보내고, 응답을 확인하세요.
예를 들어, 모든 메뉴를 가져오는 API를 테스트하려면:
- HTTP 메소드: GET
- URL: http://localhost:8000/api/menus
- Send 버튼을 클릭!
그러면 JSON 형식의 메뉴 목록이 응답으로 오겠죠? 이렇게 모든 API 엔드포인트를 하나씩 테스트해보세요. 마치 모든 요리를 맛보는 것처럼요! 😋
💡 테스트 팁: 다양한 시나리오를 테스트해보세요. 정상적인 요청뿐만 아니라, 잘못된 데이터를 보내거나 권한이 없는 요청을 보내는 등의 예외 상황도 테스트해보는 것이 중요해요!
5.2 자동화된 테스트 작성하기
수동으로 테스트하는 것도 좋지만, 자동화된 테스트를 작성하면 더 효율적이에요. 이는 마치 요리 로봇을 만들어 자동으로 음식의 맛을 체크하는 것과 같죠! 🤖
PHP에서는 PHPUnit을 사용해 단위 테스트와 통합 테스트를 작성할 수 있어요. 먼저 PHPUnit을 설치해볼까요?
composer require --dev phpunit/phpunit
이제 tests/MenuTest.php
파일을 만들고 다음과 같이 작성해볼게요:
<?php
use PHPUnit\Framework\TestCase;
use GuzzleHttp\Client;
class MenuTest extends TestCase
{
private $client;
protected function setUp(): void
{
$this->client = new Client(['base _uri' => 'http://localhost:8000']);
}
public function testGetAllMenus()
{
$response = $this->client->get('/api/menus');
$this->assertEquals(200, $response->getStatusCode());
$data = json_decode($response->getBody(), true);
$this->assertIsArray($data);
}
public function testAddMenu()
{
$response = $this->client->post('/api/menus', [
'json' => ['name' => 'Test Menu', 'price' => 9.99]
]);
$this->assertEquals(201, $response->getStatusCode());
$data = json_decode($response->getBody(), true);
$this->assertArrayHasKey('message', $data);
}
public function testGetSpecificMenu()
{
$response = $this->client->get('/api/menus/1');
$this->assertEquals(200, $response->getStatusCode());
$data = json_decode($response->getBody(), true);
$this->assertArrayHasKey('id', $data);
$this->assertArrayHasKey('name', $data);
$this->assertArrayHasKey('price', $data);
}
}
이제 이 테스트를 실행하려면 터미널에서 다음 명령어를 입력하세요:
./vendor/bin/phpunit tests/MenuTest.php
이렇게 자동화된 테스트를 작성하면, API의 변경사항이 있을 때마다 빠르게 모든 기능을 테스트할 수 있어요. 마치 요리 품질 관리 시스템을 구축한 것과 같죠! 👨🔬👩🔬
5.3 API 문서화하기
API를 개발했다면, 이제 다른 개발자들이 쉽게 사용할 수 있도록 문서를 작성해야 해요. 이는 마치 레스토랑에서 멋진 메뉴판을 만드는 것과 같아요. 손님들이 어떤 요리가 있는지, 어떻게 주문해야 하는지 알 수 있게 해주는 거죠! 📜✨
API 문서화를 위해 우리는 Swagger(OpenAPI)를 사용할 거예요. Swagger는 API를 시각적으로 보여주고 테스트할 수 있게 해주는 강력한 도구예요.
먼저, Swagger UI를 설치해볼까요?
composer require swagger-api/swagger-ui
그리고 public/swagger.json
파일을 만들어 API 스펙을 정의해볼게요:
{
"openapi": "3.0.0",
"info": {
"title": "Restaurant Menu API",
"version": "1.0.0",
"description": "API for managing restaurant menus"
},
"paths": {
"/api/menus": {
"get": {
"summary": "Get all menus",
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Menu"
}
}
}
}
}
}
},
"post": {
"summary": "Add a new menu",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/NewMenu"
}
}
}
},
"responses": {
"201": {
"description": "Menu created"
}
}
}
},
"/api/menus/{id}": {
"get": {
"summary": "Get a specific menu",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "integer"
}
}
],
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Menu"
}
}
}
},
"404": {
"description": "Menu not found"
}
}
}
}
},
"components": {
"schemas": {
"Menu": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"price": {
"type": "number"
}
}
},
"NewMenu": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"price": {
"type": "number"
}
},
"required": ["name", "price"]
}
}
}
}
이제 Swagger UI를 표시할 HTML 페이지를 만들어볼게요. public/api-docs.html
파일을 만들고 다음과 같이 작성하세요:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>API Documentation</title>
<link rel="stylesheet" type="text/css" href="/vendor/swagger-api/swagger-ui/dist/swagger-ui.css">
</head>
<body>
<div id="swagger-ui"></div>
<script src="/vendor/swagger-api/swagger-ui/dist/swagger-ui-bundle.js"></script>
<script src="/vendor/swagger-api/swagger-ui/dist/swagger-ui-standalone-preset.js"></script>
<script>
window.onload = function() {
SwaggerUIBundle({
url: "/swagger.json",
dom_id: '#swagger-ui',
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
layout: "BaseLayout"
});
}
</script>
</body>
</html>
이제 브라우저에서 http://localhost:8000/api-docs.html
에 접속하면 멋진 API 문서를 볼 수 있어요! 🎉
💡 문서화 팁: API 문서는 항상 최신 상태로 유지해야 해요. API에 변경사항이 생길 때마다 문서도 함께 업데이트하는 습관을 들이세요. 그래야 다른 개발자들이 항상 정확한 정보를 얻을 수 있답니다!
5.4 API 버전 관리
API가 발전함에 따라 버전 관리가 필요할 수 있어요. 이는 마치 레스토랑에서 메뉴를 개선하면서도 단골손님들의 favorite 메뉴는 그대로 유지하는 것과 같아요. 🔄
API 버전 관리를 위해 URL에 버전 정보를 포함시킬 수 있어요. 예를 들면:
$app->group('/v1', function (Group $group) {
$group->get('/api/menus', [MenuController::class, 'getAllMenus']);
$group->post('/api/menus', [MenuController::class, 'addMenu']);
$group->get('/api/menus/{id}', [MenuController::class, 'getMenu']);
});
이렇게 하면 /v1/api/menus
와 같은 형식으로 API를 호출할 수 있어요. 새로운 버전의 API를 만들 때는 /v2
그룹을 추가하면 되죠.
자, 이제 우리의 API 레스토랑이 완성되었어요! 맛있는 요리(기능)도 있고, 품질 관리 시스템(테스트)도 있고, 멋진 메뉴판(문서)도 있네요. 이제 손님들(다른 개발자들)이 우리의 API를 맛있게 사용할 수 있을 거예요. 👨🍳👩🍳🍽️
API 개발의 세계는 정말 넓고 깊답니다. 계속해서 학습하고, 실험하고, 개선해나가세요. 여러분의 API 요리 실력이 날로 발전할 거예요! 🚀
🌟 재능넷 활용 팁: API 개발에 대해 더 깊이 있게 배우고 싶으신가요? 재능넷에서 'Advanced API Development' 강좌를 들어보세요. 실제 프로젝트 경험이 풍부한 전문가들이 더 고급 주제들을 다루고 있답니다. API 성능 최적화, 보안 강화, 대규모 트래픽 처리 등 실전에서 꼭 필요한 스킬을 배울 수 있어요!