RESTful services with jQuery, PHP and the Slim Framework, 2011 in JQuery, PHP, REST
NOTE: This is the PHP version of this article and its companion app. A Java version is available here.
I have been looking for a lightweight framework to build a RESTful API in PHP. There are a number of good options out there: Slim, Epiphany, Tonic, Recess, and Frapi to name a few. They all seem like good frameworks. In the end, I chose Slim for this project for two main reasons:
It’s very lightweight and focused on REST and nothing else.
It supports all the HTTP methods (GET, POST, PUT, DELETE), which was a key requirement for my application.
This article (and its companion app) provides an example of building a complete RESTful API using the different HTTP methods:
GET to retrieve and search data
POST to add data
PUT to update data
DELETE to delete data
The application used as an example for this article is a Wine Cellar app. You can search for wines, add a wine to your cellar, update and delete wines.
The REST API consists of the following methods:
Method URL Action
GET /api/wines Retrieve all wines
GET /api/wines/search/Chateau Search for wines with ‘Chateau’ in their name
GET /api/wines/10 Retrieve wine with id == 10
POST /api/wines Add a new wine
PUT /api/wines/10 Update wine with id == 10
DELETE /api/wines/10 Delete wine with id == 10
Implementing the API with Slim
Slim makes it easy to implement this API in PHP:
$app->get(‘/wines/:id’, ‘getWine’);
$app->get(‘/wines/search/:query’, ‘findByName’);
$app->post(‘/wines’, ‘addWine’);
$app->put(‘/wines/:id’, ‘updateWine’);
$app->delete(‘/wines/:id’, ‘deleteWine’);
$app->run();
function getWines() {
$sql = “select * FROM wine ORDER BY name”;
try {
$db = getConnection();
$stmt = $db->query($sql);
$wines = $stmt->fetchAll(PDO::FETCH_OBJ);
$db = null;
echo ‘{“wine”: ‘ . json_encode($wines) . ‘}’;
} catch(PDOException $e) {
echo ‘{“error”:{“text”:’. $e->getMessage() .’}}’;
}
}
function getWine($id) {
$sql = “SELECT * FROM wine WHERE id=:id”;
try {
$db = getConnection();
$stmt = $db->prepare($sql);
$stmt->bindParam(“id”, $id);
$stmt->execute();
$wine = $stmt->fetchObject();
$db = null;
echo json_encode($wine);
} catch(PDOException $e) {
echo ‘{“error”:{“text”:’. $e->getMessage() .’}}’;
}
}
function addWine() {
$request = Slim::getInstance()->request();
$wine = json_decode($request->getBody());
$sql = “INSERT INTO wine (name, grapes, country, region, year, description) VALUES (:name, :grapes, :country, :region, :year, :description)”;
try {
$db = getConnection();
$stmt = $db->prepare($sql);
$stmt->bindParam(“name”, $wine->name);
$stmt->bindParam(“grapes”, $wine->grapes);
$stmt->bindParam(“country”, $wine->country);
$stmt->bindParam(“region”, $wine->region);
$stmt->bindParam(“year”, $wine->year);
$stmt->bindParam(“description”, $wine->description);
$stmt->execute();
$wine->id = $db->lastInsertId();
$db = null;
echo json_encode($wine);
} catch(PDOException $e) {
echo ‘{“error”:{“text”:’. $e->getMessage() .’}}’;
}
}
function updateWine($id) {
$request = Slim::getInstance()->request();
$body = $request->getBody();
$wine = json_decode($body);
$sql = “UPDATE wine SET name=:name, grapes=:grapes, country=:country, region=:region, year=:year, description=:description WHERE id=:id”;
try {
$db = getConnection();
$stmt = $db->prepare($sql);
$stmt->bindParam(“name”, $wine->name);
$stmt->bindParam(“grapes”, $wine->grapes);
$stmt->bindParam(“country”, $wine->country);
$stmt->bindParam(“region”, $wine->region);
$stmt->bindParam(“year”, $wine->year);
$stmt->bindParam(“description”, $wine->description);
$stmt->bindParam(“id”, $id);
$stmt->execute();
$db = null;
echo json_encode($wine);
} catch(PDOException $e) {
echo ‘{“error”:{“text”:’. $e->getMessage() .’}}’;
}
}
function deleteWine($id) {
$sql = “DELETE FROM wine WHERE id=:id”;
try {
$db = getConnection();
$stmt = $db->prepare($sql);
$stmt->bindParam(“id”, $id);
$stmt->execute();
$db = null;
} catch(PDOException $e) {
echo ‘{“error”:{“text”:’. $e->getMessage() .’}}’;
}
}
function findByName($query) {
$sql = “SELECT * FROM wine WHERE UPPER(name) LIKE :query ORDER BY name”;
try {
$db = getConnection();
$stmt = $db->prepare($sql);
$query = “%”.$query.”%”;
$stmt->bindParam(“query”, $query);
$stmt->execute();
$wines = $stmt->fetchAll(PDO::FETCH_OBJ);
$db = null;
echo ‘{“wine”: ‘ . json_encode($wines) . ‘}’;
} catch(PDOException $e) {
echo ‘{“error”:{“text”:’. $e->getMessage() .’}}’;
}
}
function getConnection() {
$dbhost=”127.0.0.1″;
$dbuser=”root”;
$dbpass=””;
$dbname=”cellar”;
$dbh = new PDO(“mysql:host=$dbhost;dbname=$dbname”, $dbuser, $dbpass);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $dbh;
}
?>
function
findAll() {
$.ajax({
type:
'GET'
,
url: rootURL,
dataType:
"json"
,
// data type of response
success: renderList
});
}
function
findByName(searchKey) {
$.ajax({
type:
'GET'
,
url: rootURL +
'/search/'
+ searchKey,
dataType:
"json"
,
success: renderList
});
}
function
findById(id) {
$.ajax({
type:
'GET'
,
url: rootURL +
'/'
+ id,
dataType:
"json"
,
success:
function
(data){
$(
'#btnDelete'
).show();
renderDetails(data);
}
});
}
function
addWine() {
console.log(
'addWine'
);
$.ajax({
type:
'POST'
,
contentType:
'application/json'
,
url: rootURL,
dataType:
"json"
,
data: formToJSON(),
success:
function
(data, textStatus, jqXHR){
alert(
'Wine created successfully'
);
$(
'#btnDelete'
).show();
$(
'#wineId'
).val(data.id);
},
error:
function
(jqXHR, textStatus, errorThrown){
alert(
'addWine error: '
+ textStatus);
}
});
}
function
updateWine() {
$.ajax({
type:
'PUT'
,
contentType:
'application/json'
,
url: rootURL +
'/'
+ $(
'#wineId'
).val(),
dataType:
"json"
,
data: formToJSON(),
success:
function
(data, textStatus, jqXHR){
alert(
'Wine updated successfully'
);
},
error:
function
(jqXHR, textStatus, errorThrown){
alert(
'updateWine error: '
+ textStatus);
}
});
}
function
deleteWine() {
console.log(
'deleteWine'
);
$.ajax({
type:
'DELETE'
,
url: rootURL +
'/'
+ $(
'#wineId'
).val(),
success:
function
(data, textStatus, jqXHR){
alert(
'Wine deleted successfully'
);
},
error:
function
(jqXHR, textStatus, errorThrown){
alert(
'deleteWine error'
);
}
});
}
// Helper function to serialize all the form fields into a JSON string
function
formToJSON() {
return
JSON.stringify({
"id"
: $(
'#id'
).val(),
"name"
: $(
'#name'
).val(),
"grapes"
: $(
'#grapes'
).val(),
"country"
: $(
'#country'
).val(),
"region"
: $(
'#region'
).val(),
"year"
: $(
'#year'
).val(),
"description"
: $(
'#description'
).val()
});
}