REST API’ler, modern web geliştirmenin bel kemiğidir. Günümüzde çoğu web uygulaması, çeşitli dillerde yazılmış backbone API‘lerine bağlı frontend single-page uygulamalar geliştirilmektedir. REST API’lerini hızlı bir şekilde oluşturmanıza yardımcı olabilecek birçok harika framework vardır.
Laravel/Lumen ve Symfony’nin API platformu, PHP ekosisteminde en sık kullanılan örneklerdir. İstekleri işlemek ve doğru HTTP durum kodlarıyla JSON yanıtları oluşturmak için harika araçlar sağlarlar. Ayrıca kimlik doğrulama/yetkilendirme, istek doğrulama, veri dönüştürme, sayfalandırma, filtreler, hız azaltma, alt kaynaklara sahip karmaşık uç noktalar ve API belgeleri gibi yaygın sorunları ele almayı da kolaylaştırırlar.
REST API için PHP Proje İskeleti Oluşturma
calisma klasöründe /src dizini ve bağımlılıkları oluşturmak için composer.json dosyasını oluşturarak başlıyoruz.
1 2 3 4 | /src composer.json |
composer.json
1 2 3 4 5 6 7 8 9 10 11 12 | { "require": { "vlucas/phpdotenv": "^5.4.1" }, "autoload": { "psr-4": { "Src\\": "src/" } } } |
Ayrıca /src dizininde otomatik olarak PHP sınıflarını arayacak bir PSR-4 otomatik yükleyici yapılandırdık.
Artık bağımlılıklarımızı kurabiliriz:
Terminali açıp composer bağımlılıklarını yükleyin
1 2 3 | composer install |
Bir /vendor dizini oluşturacak ve DotEnv bağımlılığı yüklenecek (otomatik yükleyici /src’den include() çağrıları olmadan sınıfları yükleyecektir).
Projeniz için içinde iki satır bulunan bir .gitignore dosyası oluşturun, böylece /vendor dizini ve yerel .env dosyası yok sayılacaktır:
.gitignore
1 2 3 4 | vendor/ .env |
Ardından, Gizli değişkenler için bir .env.example dosyası oluşturun:
.env
1 2 3 4 5 6 7 | DB_HOST=localhost DB_PORT=3306 DB_DATABASE= DB_USERNAME= DB_PASSWORD= |
ve gerçek ayrıntılarınızı daha sonra dolduracağınız bir .env dosyası (Git tarafından yok sayılır, bu nedenle deponuzda kalmaz).
Ortam değişkenlerini yükleyen bir start.php dosyası oluşturun.
start.php
1 2 3 4 5 6 7 8 9 10 11 | <?php require 'vendor/autoload.php'; use Dotenv\Dotenv; $dotenv = Dotenv::createImmutable(__DIR__); $dotenv->safeLoad(); echo $_ENV['DB_HOST']; |
PHP REST API’niz için Veritabanını Yapılandırma
Basit API‘mizi güçlendirmek için MySQL kullanacağız. Uygulamamız için yeni bir veritabanı ve kullanıcı oluşturun:
1 2 3 | http://localhost/phpmyadmin/ |
Kullanıcı Hesapları / Kullanıcı Hesabı Ekle ile aşağıdaki gibi yeni kullanıcı ekleyin.
1 2 3 4 | Kullanıcı adı : rest_api_user Şifre : Sifre123456+ |

VERİ ve YAPI yetkilerini verip GİT komutunu uygulayın.
REST API, post tablosu için şu alanları içerecektir: id, baslik, icerik, yazar, yazar_resim,olusturma_tarih. Bu örnek kullanıcıların bloglarını Blog uygulamamızda yayınlamalarına olanak tanır.
MySQL’de veritabanı tablosunu oluşturun.
1 2 3 4 5 6 7 8 9 10 11 12 13 | use blog; CREATE TABLE `post` ( `id` int(11) NOT NULL AUTO_INCREMENT, `baslik` varchar(255) NOT NULL, `icerik` text NOT NULL, `yazar` varchar(255), `yazar_resim` varchar(255), `olusturma_tarih` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ); |
Veritabanı bağlantı değişkenlerini .env dosyanıza ekleyin:
1 2 3 4 5 6 7 | DB_HOST=localhost DB_PORT=3306 DB_DATABASE=blog DB_USERNAME=rest_api_user DB_PASSWORD=Sifre123456+ |
Veritabanı bağlantılarını tutmak için bir sınıf oluşturun ve bağlantının başlatılmasını start.php dosyasına ekleyin.
src/Database.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <?php namespace Src; class Database { private $dbConnection = null; public function __construct() { $host = $_ENV['DB_HOST']; $port = $_ENV['DB_PORT']; $db = $_ENV['DB_DATABASE']; $user = $_ENV['DB_USERNAME']; $pass = $_ENV['DB_PASSWORD']; try { $this->dbConnection = new \PDO( "mysql:host=$host;port=$port;dbname=$db", $user, $pass ); } catch (\PDOException $e) { exit($e->getMessage()); } } public function baglan() { return $this->dbConnection; } } |
start.php
1 2 3 4 5 6 7 8 9 10 11 | <?php require 'vendor/autoload.php'; use Src\Database; $dotenv = Dotenv\Dotenv::createImmutable(__DIR__); $dotenv->safeLoad(); $dbConnection = (new Database())->baglan(); |
Post Tablosu için bir Sınıf Ekleme ve PHP REST API’sini Uygulama
Veritabanıyla nesne yönelimli bir bağlamda etkileşim kurmanın birçok yolu vardır, ancak, tüm gönderileri döndürmek, belirli bir gönderiyi döndürmek ve bir gönderi eklemek/güncellemek/silmek için yöntemleri uygulayacağınız basit bir yöntemle gidelim.
Ayrıca, frontend api/index.php tarafından işlenecek olan API uç noktaları.
Aşağıdaki uç noktalara sahip REST API:
API’ler
API | CRUD | Tanım |
---|---|---|
GET /posts | READ | Tüm gönderileri okur |
GET /post/{id} | READ | Belirtilen gönderiyi alır. |
POST /post | CREATE | Gönderi oluşturur |
PUT /post/{id} | UPDATE | Gönderiyi günceller |
DELETE /post/{id} | DELETE | Gönderiyi siler |
api/index.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | <?php require "../start.php"; use Src\Post; header("Access-Control-Allow-Origin: *"); header("Content-Type: application/json; charset=UTF-8"); header("Access-Control-Allow-Methods: OPTIONS,GET,POST,PUT,DELETE"); header("Access-Control-Max-Age: 3600"); header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With"); $uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); $uri = explode( '/', $uri ); // GET için "/post" veya "/posts" ile başlayan uç noktalar tüm gönderileri gösterir // diğer her şey bir 404 Bulunamadı ile sonuçlanır if ($uri[1] !== 'post') { if($uri[1] !== 'posts'){ header("HTTP/1.1 404 Not Found"); exit(); } } // POST/PUT/DELETE için `/posts` ile başlayan uç noktalar 404 Bulunamadı ile sonuçlanırif ($uri[1] == 'posts' and isset($uri[2])) { if ($uri[1] == 'posts' and isset($uri[2])) { header("HTTP/1.1 404 Not Found"); exit(); } // gönderi kimliği elbette isteğe bağlıdır ve bir sayı olmalıdır $postId = null; if (isset($uri[2])) { $postId = (int) $uri[2]; } //$requestMethod = $_SERVER["REQUEST_METHOD"]; // istek yöntemini ve gönderi kimliğini Gönderiye iletin ve HTTP isteğini işleyin: $controller = new Post($dbConnection, $requestMethod, $postId); $controller->processRequest(); |
src/Post.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | <?php namespace Src; class Post { private $db; private $requestMethod; private $postId; public function __construct($db, $requestMethod, $postId) { $this->db = $db; $this->requestMethod = $requestMethod; $this->postId = $postId; } public function processRequest() { switch ($this->requestMethod) { case 'GET': if ($this->postId) { $response = $this->getPost($this->postId); } else { $response = $this->getAllPosts(); }; break; case 'POST': $response = $this->createPost(); break; case 'PUT': $response = $this->updatePost($this->postId); break; case 'DELETE': $response = $this->deletePost($this->postId); break; default: $response = $this->cevapYok(); break; } header($response['status_code_header']); if ($response['icerik']) { echo $response['icerik']; } } private function getAllPosts() { $query = " SELECT id, baslik, icerik, yazar, yazar_resim, olusturma_tarih FROM post; "; try { $statement = $this->db->query($query); $result = $statement->fetchAll(\PDO::FETCH_ASSOC); } catch (\PDOException $e) { exit($e->getMessage()); } $response['status_code_header'] = 'HTTP/1.1 200 OK'; $response['icerik'] = json_encode($result); return $response; } private function getPost($id) { $result = $this->bul($id); if (! $result) { return $this->cevapYok(); } $response['status_code_header'] = 'HTTP/1.1 200 OK'; $response['icerik'] = json_encode($result); return $response; } //Post Oluştur private function createPost() { $input = (array) json_decode(file_get_contents('php://input'), TRUE); //input kontrolü if( !isset($input['baslik']) || !isset($input['icerik']) || !isset($input['yazar']) ) return $this->gecersizCevap(); $query = " INSERT INTO post (baslik, icerik, yazar, yazar_resim) VALUES (:baslik, :icerik, :yazar, :yazar_resim); "; try { $statement = $this->db->prepare($query); $statement->execute(array( 'baslik' => $input['baslik'], 'icerik' => $input['icerik'], 'yazar' => $input['yazar'], 'yazar_resim' => 'https://secure.gravatar.com/avatar/'.md5(strtolower($input['yazar'])).'.png?s=200', )); $statement->rowCount(); } catch (\PDOException $e) { exit($e->getMessage()); } $response['status_code_header'] = 'HTTP/1.1 201'; $response['icerik'] = json_encode(array('mesaj' => 'Gönderi Oluşturuldu!!!')); return $response; } private function updatePost($id) { $result = $this->bul($id); if (! $result) { return $this->cevapYok(); } $input = (array) json_decode(file_get_contents('php://input'), TRUE); //input kontrolü if( !isset($input['baslik']) || !isset($input['icerik']) || !isset($input['yazar']) ) return $this->gecersizCevap(); $statement = " UPDATE post SET baslik = :baslik, icerik = :icerik, yazar = :yazar, yazar_resim = :yazar_resim WHERE id = :id; "; try { $statement = $this->db->prepare($statement); $statement->execute(array( 'id' => (int) $id, 'baslik' => $input['baslik'], 'icerik' => $input['icerik'], 'yazar' => $input['yazar'], 'yazar_resim' => 'https://secure.gravatar.com/avatar/'.md5($input['yazar']).'.png?s=200', )); $statement->rowCount(); } catch (\PDOException $e) { exit($e->getMessage()); } $response['status_code_header'] = 'HTTP/1.1 200 OK'; $response['icerik'] = json_encode(array('message' => 'Post Güncellendi!')); return $response; } private function deletePost($id) { $result = $this->bul($id); if (! $result) { return $this->cevapYok(); } $query = " DELETE FROM post WHERE id = :id; "; try { $statement = $this->db->prepare($query); $statement->execute(array('id' => $id)); $statement->rowCount(); } catch (\PDOException $e) { exit($e->getMessage()); } $response['status_code_header'] = 'HTTP/1.1 200 OK'; $response['icerik'] = json_encode(array('message' => 'Post Silindi!')); return $response; } public function bul($id) { $query = " SELECT id, baslik, icerik, yazar, yazar_resim, olusturma_tarih FROM post WHERE id = :id; "; try { $statement = $this->db->prepare($query); $statement->execute(array('id' => $id)); $result = $statement->fetch(\PDO::FETCH_ASSOC); return $result; } catch (\PDOException $e) { exit($e->getMessage()); } } private function gecersizCevap() { $response['status_code_header'] = 'HTTP/1.1 422 Unprocessable Entity'; $response['icerik'] = json_encode([ 'hata' => 'Geçersiz input' ]); return $response; } private function cevapYok() { $response['status_code_header'] = 'HTTP/1.1 404 Not Found'; $response['icerik'] = null; return $response; } } |
Nasıl Çalışıyor
PHP Sunucusunu başlatalım ve API’lerinizi Postman gibi bir araçla test edelim.
1 2 3 | php -S localhost:8000 -t api |
Postman çalıştırıp tüm post verileri için aşağıdaki sorguları çalıştırın.
Tüm post verilerini okuma

Tüm veriler aşağıdaki method ile getirildi.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | private function getAllPosts() { $query = " SELECT id, baslik, icerik, yazar, yazar_resim, olusturma_tarih FROM post; "; try { $statement = $this->db->query($query); $result = $statement->fetchAll(\PDO::FETCH_ASSOC); } catch (\PDOException $e) { exit($e->getMessage()); } $response['status_code_header'] = 'HTTP/1.1 200 OK'; $response['icerik'] = json_encode($result); return $response; } |
Post tablosunu kayıt ekleme:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | //Post Oluştur private function createPost() { $input = (array) json_decode(file_get_contents('php://input'), TRUE); //input kontrolü if( !isset($input['baslik']) || !isset($input['icerik']) || !isset($input['yazar']) ) return $this->gecersizCevap(); $query = " INSERT INTO post (baslik, icerik, yazar, yazar_resim) VALUES (:baslik, :icerik, :yazar, :yazar_resim); "; try { $statement = $this->db->prepare($query); $statement->execute(array( 'baslik' => $input['baslik'], 'icerik' => $input['icerik'], 'yazar' => $input['yazar'], 'yazar_resim' => 'https://secure.gravatar.com/avatar/'.md5(strtolower($input['yazar'])).'.png?s=200', )); $statement->rowCount(); } catch (\PDOException $e) { exit($e->getMessage()); } $response['status_code_header'] = 'HTTP/1.1 201'; $response['icerik'] = json_encode(array('mesaj' => 'Gönderi Oluşturuldu!!!')); return $response; } ...... private function gecersizCevap() { $response['status_code_header'] = 'HTTP/1.1 422 Unprocessable Entity'; $response['icerik'] = json_encode([ 'hata' => 'Geçersiz input' ]); return $response; } |
Post tablosundan Kayıt Okuma

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | private function getPost($id) { $result = $this->bul($id); if (! $result) { return $this->cevapYok(); } $response['status_code_header'] = 'HTTP/1.1 200 OK'; $response['icerik'] = json_encode($result); return $response; } ..... public function bul($id) { $query = " SELECT id, baslik, icerik, yazar, yazar_resim, olusturma_tarih FROM post WHERE id = :id; "; try { $statement = $this->db->prepare($query); $statement->execute(array('id' => $id)); $result = $statement->fetch(\PDO::FETCH_ASSOC); return $result; } catch (\PDOException $e) { exit($e->getMessage()); } } ..... private function cevapYok() { $response['status_code_header'] = 'HTTP/1.1 404 Not Found'; $response['icerik'] = null; return $response; } } |
Post güncelleme

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | private function updatePost($id) { $result = $this->bul($id); if (! $result) { return $this->cevapYok(); } $input = (array) json_decode(file_get_contents('php://input'), TRUE); //input kontrolü if( !isset($input['baslik']) || !isset($input['icerik']) || !isset($input['yazar']) ) return $this->gecersizCevap(); $statement = " UPDATE post SET baslik = :baslik, icerik = :icerik, yazar = :yazar, yazar_resim = :yazar_resim WHERE id = :id; "; try { $statement = $this->db->prepare($statement); $statement->execute(array( 'id' => (int) $id, 'baslik' => $input['baslik'], 'icerik' => $input['icerik'], 'yazar' => $input['yazar'], 'yazar_resim' => 'https://secure.gravatar.com/avatar/'.md5($input['yazar']).'.png?s=200', )); $statement->rowCount(); } catch (\PDOException $e) { exit($e->getMessage()); } $response['status_code_header'] = 'HTTP/1.1 200 OK'; $response['icerik'] = json_encode(array('message' => 'Post Güncellendi!')); return $response; } |
NOT: bul(), cevapYok() ve gecersizCevap() methodlarını önceki kodlarda ekledik.
Post Silme

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | private function deletePost($id) { $result = $this->bul($id); if (! $result) { return $this->cevapYok(); } $query = " DELETE FROM post WHERE id = :id; "; try { $statement = $this->db->prepare($query); $statement->execute(array('id' => $id)); $statement->rowCount(); } catch (\PDOException $e) { exit($e->getMessage()); } $response['status_code_header'] = 'HTTP/1.1 200 OK'; $response['icerik'] = json_encode(array('message' => 'Post Silindi!')); return $response; } |
Yorum Yap