RESTful services with jQuery, PHP and the Slim Framework

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:

  1. It’s very lightweight and focused on REST and nothing else.
  2. 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.


You can run the application here. The create/update/delete features are disabled in this online version. Use the link at the bottom of this post to download a fully enabled version.

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:

<?php

require 'Slim/Slim.php';

$app = new Slim();

$app->get('/wines', 'getWines');
$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;
}

?>

Code Highlights

  1. Lines 7 to 12: Slim helps you route resource URIs to callback functions in response to specific HTTP request methods (e.g. GET, POST, PUT, DELETE).
  2. Lines 45 to 46 and 67 to 68: the request object makes it easy to access the request’s data: In this case the JSON representation of a wine object.
  3. The approach you use to actually retrieve the data is totally up to you. In this example, I use some simple PDO code, but you can of course use your own data access solution.

Testing the API using cURL

If you want to test your API before using it in a client application, you can invoke your REST services straight from a browser address bar. For example, you could try:

You will only be able to test your GET services that way, and even then, it doesn’t give you full control to test all the content types your API can return.

A more versatile solution to test RESTful services is to use cURL, a command line utility for transferring data with URL syntax.

For example, using cURL, you can test the Wine Cellar API with the following commands:

  • Get all wines:
    curl -i -X GET http://localhost/cellar/api/wines
    
  • Get all wines with ‘chateau’ in their name:
    curl -i -X GET http://localhost/cellar/api/wines/search/chateau
    
  • Get wine #5:
    curl -i -X GET http://localhost/cellar/api/wines/5
    
  • Delete wine #5:
    curl -i -X DELETE http://localhost/cellar/api/wines/5
    
  • Add a new wine:
    curl -i -X POST -H 'Content-Type: application/json' -d '{"name": "New Wine", "year": "2009"}' http://localhost/cellar/api/wines
    
  • Modify wine #27:
    curl -i -X PUT -H 'Content-Type: application/json' -d '{"id": "27", "name": "New Wine", "year": "2010"}' http://localhost/cellar/api/wines/27
    

The jQuery Client

Accessing your API through cURL is cool, but there is nothing like a real application to put your API to the test. So the source code (available for download at the end of this post) includes a simple jQuery client to manage your wine cellar.

Here is the jQuery code involved in calling the services:

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()
		});
}

 

Download the Source Code

The source code for this application is hosted on GitHub here. And here is a quick link to the source code download. It includes both the PHP and jQuery code for the application.

I’m interested in your feedback. Let me know what you think and what your experience has been building RESTful-based applications using PHP and jQuery

  • Pingback: RESTful services with jQuery and Java using JAX-RS and Jersey()

  • Pingback: http://links.soudev.com.br()

  • Hey man this is a great article very similar to my methods. But I got some great ideas from this! Thanks for writing this.

  • Pingback: Backbone.js Wine Cellar Tutorial — Part 1: Getting Started()

  • Christophe,
    This is excellent write up. I have been using the Slim framework for some time now but I remember stuggling with it a little bit at the begining – shame that your tutorial wasn’t there back in September/October;).
    L

  • Pingback: RESTful services with jQuery, PHP and the Slim Framework « lolososo()

  • Ian

    This is a *really* useful tutorial. I’ve only just started looking into using the Slim Framework and this really helps to break it down into a practical application. I didn’t even think it could be that useful for providing a full RESTful API.

    Doing a Backbone alternative version is even better. That’s another lightweight framework I’ve been learning and seeing both side-by-side on a practical example really helps to show the differences between the two and provides a lot of food for thought.

    Fantastic work! Thanks for the effort you’ve put in in putting together both tutorials. They’ve come at a good time for me.

  • Were you able to update the content-type headers to application/json for your api responses?

  • twangi

    Very useful, succinct example thank you for posting Christophe.
    I was using a newly installed Mac OS x Lion client to run this example.
    For the benefit of any other users in a similar position I had to:
    1- tell Apache to permit PHP file execution by uncommenting this line (remove hash symbol) in /private/etc/apache2/httpd.conf:
    LoadModule php5_module libexec/apache2/libphp5.so

    2- install MySql via 64bit DMG at http://www.mysql.com/downloads/mysql/ and start service

    3- add a .htaccess file to the cellar/api folder as follows
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.*)$ index.php [QSA,L]

    4- add cellar.conf to the /private/etc/apache2/other folder as follows:

    Options Indexes FollowSymLinks MultiViews
    AllowOverride All
    Order allow,deny
    Allow from all

    I initially started by trying to get the site working under my //Users/username/Sites directory following the “read me” instructions but eventually gave up and moved the project to the main WebServer/Documents folder after not being able to get rid of an error: ” File does not exist: /Library/WebServer/Documents/Users”, if anyone has any advice on that I’d be interested to hear it.

    • matt berwald

      twangi:

      complete noob to slim and i’m running my LAMP stack on windows… any idea where i would add the cellar.conf to my windows apache ? i do not have an other folder but i do have an extra folder. any pointers are appreciated. thanks!

    • Robert Adams

      Added this line to my .htaccess:

      RewriteBase /~adams/Cellar

      • Fany

        i just use wampserver. when open http://localhost/cellar/ it works well. While I click new wine, it alerts error.
        How to fix it? It can’t work to add RewriteBase /~adams/Cellar .
        I have other questions.
        First, when click ‘delete’,it can’t redirect.
        Second, when you modify name ,then save,it can’t display in the left at the same time.
        I have already read part3 and final, maybe I can rewrite it. But I really want to know the final version of php.

  • Ron

    What php server did you run on?

  • Well you online test application doesn’t seem to run!! shows no wines and when i deploy the source code over my sever results same. Help!

    • sachin tyagi

      if your app is not responding. Add the below line :
      var data =$.parseJSON(data);
      into renderList(data) function into main.js file

  • online testpage doesn’t seem to run it displays no content except the html part. and it results the same when i deploy the source code over my webserver

    • sachin tyagi

      if your app is not responding. Add the var data = JSON.parse(data); into renderList(data) function into main.js file

      • kinsay

        Hi! The Api works fine using curl, however, when tring to GET the info from the html it doesn´t work.

        I´ve tred adding var data = JSON.parse(data); or var data =$.parseJSON(data); and nothing worked. I have checked the rootURL in main.js and it´s ok…

        Any hints??

        • kinsay

          Solved: ‘www.’ was missing from the urlroot

    • Patrick

      Kishan, did you figure out how to fix this? I am having the same issue.

  • thank you so much. this was amazingly helpful :)

  • Pingback: Confluence: Mobile Devices Development()

  • captainaj

    Hi Christophe, I got the app *almost* running. After all settings, the database is imported but the wine data wouldn’t load (right on homepage). Any idea? Thanks for your help!

  • captainaj

    I figured out: pay attention to rootURL and JSON, firebug is your friend! Thanks for the useful tutorial Christophe!

    • the add function is not working any idea ?
      also the update function give me parser error any solution so far?

      • Sree

        @Amany:
        Please comment the line
        Line No. 46: error_log(‘addWine\n’, 3, ‘/var/tmp/php.log’); in addWine() function.
        I had the same problem. Now its working for me

    • Patrick

      AJ, Any way you would post a little more info on how you fixed your issue here. I know it was a little while ago but hope you remember!

  • Jason

    this is great script, just a question, how do i go about getting this to support chinese, i had it all going but the json return ?????? and it displays correctly in phpmyadmin, any help would be great cheers

    Jason

  • Hello,

    I’ve been struggling with Backbone and your example for 2 days now (no kidding… I’m getting crazy!) and still haven’t found a way to make it work. I’m sorry and I must agree I’m no real programmer, but I would really like to understand all this :
    – I’ve downloaded your app (part1) with the PHP back-end. I’ve installed it on my localhost, re-read the changes you mention in you readme file… and I still get a 404 error on …/…/api/wines (like file index.php doesn’t exists) in my Firebug console! Result : no wine in the list. I feel like the Slim framework doesn’t do its job. Isn’t it supposed to catch the call and redirect it to index.php which then looks in the database?
    – I’ve tried putting it on a web server (feeling my localhost might be wrong). I had a 500 internal error on a first server (on a free webserver). I had a 404 error again on my website server.

    Sorry for this long comment which is actually more a desperate call for help, but I did spend about 15 hours in 2 days on that and I am really getting crazy. I am actually totally unable to use Backbone with server side data saving (quite a shame…). Eventually I’d like to change your Slim usage by working on files instead of a Mysql database, (so my database is not set on my remote servers tests _although I set it on my localhost), but I don’t think this is the problem.
    If you (or anybody reading this) feel like helping me a little with that one, I’d greatly appreciate. I have the feeling I’m missing quite an important thing here…
    You can email me if you prefer.
    Thanks !

    Fred.

    • Well… After struggling with all those news things to me, I found out it was a mod_rewrite problem on the server…
      My bad….

      • Brian Kiefer

        Fred, what was the solution? I’ve gone through my httpd.conf and /private/etc/apache2/users/username.conf file and changed the AllowOverrride from None to All, restarted, and still nothing.

        • ragav
        • ragav

          http://rudyegenias.wordpress.com/2006/08/21/enabling-mod-rewrite-in-xampp/
          I am using xampp, the above link resolved my problem.

        • Rexi

          Brian, Hi Id really appreciate if you could share the response from Fred to your question. Im struggling with the same issue you described myself. Any help would prevent rapid stress related aging.

          • ouzza

            Check that you have the the apache rewrite module loaded.

            go to wamp_manager -> apache -> modules and look for rewrite_module in the list.

            If it does not have a TICK beside it click it. Apache will be bounced ( stop, start ). Try again.

            The rewite engine will not work without the required module loaded.

    • just put apiUrl:app/index.php instead app

    • Kingsley

      Hi Fred, Can you please explain what you did to fix this issue. In particular what needed change and how did you set mod_rewrite working again. This is my desperate call for help. Thanks in advance.

  • Francois

    i use xampp and the server refuses the http delete method.
    Does anyone know how to enable the delet method on xampp.

    • James

      I’m not using Slim framework yet. I assumed your function contain PDO code to manage database, could you check if your database account has “delete” privilege?

  • Ryan

    Fantastic example, thanks! There are lots of REST tutorials about, but few worked examples that really illustrate the concepts.

  • Thanks for this post. You have helped me get started with Slim!!

  • Titus

    Awesome tutorial.
    I am trying to adjust this to be able to upload an image, in the example you provided maybe like an image of a wine bottle, is this easy to add to the API?
    Thanks!!
    Titus

  • nice example but what about header for json and how to set http cache settings
    thanks

  • Very nice article, guy! :)

    Thank you for this powerfull REST+Ajax demonstration!

    []’s

    Silvio Clécio.

  • Pingback: Backbone.js酒窖教程 – 第2部分:CRUD操作 | Adobe CS6()

  • Francisc

    Hi Christophe,
    Why did you choose to use $db=getConnection(); instead of a global $db variable?
    Thanks for the insight.

  • Norman Rice

    Excellent tutorial! I was able to adapt this to a project I had already started. Thank you so much!

  • Pete

    Excellent tutorial. Really taught me a lot about AJAX and JSON. One question. Any idea why it won’t work in IE9? I get just a page of blank fields in that browser. I get this is probably intended as an iOS Web app etc, but I’m just curious as to what the offender is in IE. Works great in Chrome, Safari (for iOS) and Firefox. I tried implementing this script [ http://www.json.org/js.html ] with no results.

    Thanks!

  • Paul

    I’m trying to implement this on my webserver I keept gettinga 404 in my console when the system first loads trying to call the initial findAll() function. I’ve double checked the rootURL variable. I’ve tried enabling and disabling RewriteBase. No matter what I do I can’t seem to get it to load. You can see it at http://dev.lonewolfdigital.com/winecellar/
    Any help would be greatly appreciated.

  • Francisc

    Why have comments if you never answer them?

  • Great article! thanks!!

  • For the for the SlimPHP API to work on MacOS X 10.7 (Lion) I had to add Options +FollowSymlinks to my .htaccess file (and adjust the RewriteBase path accordingly). My .htaccess file:

    Options +FollowSymlinks
    RewriteEngine On

    # Some hosts may require you to use the `RewriteBase` directive.
    # If you need to use the `RewriteBase` directive, it should be the
    # absolute physical path to the directory that contains this htaccess file.
    #
    RewriteBase /api/

    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.*)$ index.php [QSA,L]

  • the add fun is not working in the demo and the same when i install it on my machine as it gives
    internal server error although the update and delete are working perfrectly
    any solution so far?

  • Excellent script work.Really its very useful.Thank u so much……….

  • Mike Garite

    You sir, are a bad ass.

  • its a great tutorial but when trying to add new wine i am getting error “addWine error:parsererror”. i am using the code from the sample code. but still getting error any body resolved the issue.

  • Eyal

    How can we also send with Post some parameters in the URL like xxxxx.com/5/?name=eyal

    so i want to transfer 5 as a URL parameter, and name=eyal as a query parameter

    how can i get those value

    • Arran

      Hi,
      Eyan I have the same problem…
      AddWine doesn’t work. Someone can tell us how he make it work ? only functions with GET work well.

      • Jefferson Salunga

        $request = $app->request()

        $request->get(‘name’) // to get the value of eyal

  • Eyal

    for add a new wine for example, how can i add query parameter like ?type=red&size=1.5

    ?

  • Faisal

    How can I deploy project in PHP into my server with using the Slim framework ? I tried to solve the problem but I can’t find any clear solution ?

  • Faisal

    hello, i have problem with post function. it doesn’t work very well. I don’t know why ? can you help me please ?

  • Bills

    Excellent tutorial!!!

    How does Slim framework handle load? Say 100 transactions/sec or more.

  • Pingback: Creating a REST API using Node.js, Express, and MongoDB()

  • Jefferson Salunga

    it works fine for me! thanks!

    my concern now is the security issue. because you can delete an item using command line.

  • Drew

    Great article. Are there any resources on how to best secure the API calls with Slim? I am not using user logins or OAuth, just need to generate secure keys to transfer the data on the backend.

  • Gun

    Hi, nice article. So far I’ve used only Tonic but I want to know about other PHP Restful frameworks. With Tonic we can setup our script to accept and provide certain mimetype. For example, a GET method to http://localhost/cellar/api/wines/5 which request ACCEPT array is set to contain image/png would give an image, text/html would give a html, application/pdf would give a pdf file, and so forth. Can Slim do this?

  • Arran

    Same problem : How can we also send with Post some parameters in the URL like xxxxx.com/5/?name=eyal

    so i want to transfer 5 as a URL parameter, and name=eyal as a query parameter

    how can i get those value

    Someone found a solution ?

    Thanks

  • Nice post, thank you! :)

  • Joe

    I really love this example. Clean, easy and the ajax makes it feel nice. The only problem I have is a massive hesitation when I click on a wine, even on localhost. How is it that with no latency it can take 2-3 seconds for the wine data to show up. I would think that it should load up in under a millisecond. Where is the bottleneck?

    • Joe

      So after a few hours of debugging and narrowing it down I discovered that the slowdown came from using “localhost” to connect to the db. By using “127.0.0.1” the hesitation is cleared up.

  • majun8cn

    I found that the ruby on rails based solution is also very simple and straightforward, the RESTful url looks slightly different.

    I create a similar solution by running a few commands. No single line of code.

    rails new wine_cellar
    rails generate scaffold Wine name:string grapes:string country:string region:stri
    ng year:number note:text imgsrc:string
    rake db:migrate
    rails server

    That is it.

    The RESTful interface looks like:
    curl -i -X GET http://localhost:3000/wines.json

  • Ice

    The tutorial is great. I successfully deployed the working files to my localhost server and it works perfectly fine after I comment line 45 on index.php. Hopefully I can integrate Slim framework to my knockout js & jquery mobile project.

    I have only one question, how api/index.php called in our app? Since index.php was not declared in js/main.js.

  • Wonderful tutorial …

  • spiros

    hello there! thanks for this nice post!

    for those having problem with the .htaccess file (http://localhost/cellar/api/wines 404 (Not Found) ), take a glance at httpd.conf file (you might have to change AllowOverride All)

    • Thank you Spiros! Appreciated!

    • ouzza

      Or check that you have the the apache rewrite module loaded.

      go to wamp_manager -> apache -> modules and look for rewrite_module in the list.

      If it does not have a TICK beside it click it. Apache will be bounced ( stop, start ). Try again.

      The rewite engine will not work without the required module loaded.

  • vaibhav

    Thanks for the post. I am very new to php, mysql and REST but I could create my first working app exclusively using this article alone.

  • Uwe

    Hi,

    thx this is great, but i’ve one question (maybe off-topic). How to secure the access? Is there any simply way to implement (simple) authentication?

    Any Ideas?

    UR

  • Hi! I’ve loved your article.

    I would like to leave two little suggestions.

    As other users has asked, you could set the encoding of the responses to json using this before your echo’s:

    $app = Slim::getInstance();
    $app->contentType(‘application/json’);

    And to get the correct response code you could use this in the catch block, just before your echo:

    $app = Slim::getInstance();
    $app->response()->status(500); //500 == internal server error or 400 == bad request

  • Bart

    Nice tutorial! Actually I just made my first (working) API with it. But now I want to hook my API up to a mobile app I am working on (phonegap etc). But it is not clear to me how I can load JSON data from the Slim Api. Do I actually need JSONP for this, and is Slim suited for that? It seems like quite a standard application, but I can’t find how to connect the API to my App.
    Thanks in advance for any help, tips & solutions!

  • hi this is is very useful to me . thanq for giving this information.

  • I tend not to leave a leave a response, but I browsed some remarks here RESTful
    services with jQuery, PHP and the Slim Framework |
    Christophe Coenraets. I do have a couple of
    questions for you if you do not mind. Is it just me or do a few of these comments look like they are left by brain
    dead people? :-P And, if you are posting at additional online sites,
    I’d like to keep up with you. Could you post a list of the complete urls of your shared sites like your Facebook page, twitter feed, or linkedin profile?

    • Jefferson Salunga

      i think they need to read also the Slim documentation.. i have many question too.. but after i read the documentation.. im very happy using slim now! and also some googling! =)

  • Matt Dance

    In using this code, I get Class ‘Slim” not found. Did I not install Slim right?

    • It appears so. I have installed and it worked fine. Though, upgraded to the latest Slim package. If you need any help with getting this up and running just shout (d aaattt my domain).

  • Many thanks for a great tutorial. I have touched Slim a bit but struggled with implementing authentication and rating. Therefore, ended up using Laravel instead although still think Slim is much more lightweight and probably better for my app. Oh well, I might go back one day and try again once have learned more about how frameworks work.

    For those looking for PHP RESTful frameworks I have put together a quick list with rather modest descriptions (will try to improve and add an objective view as I get into details for each of them). Also, there is a poll so feel free to vote.

    http://davss.com/tech/php-rest-api-frameworks/

    I hope it helps anyone with making decision.

  • Jan

    super bad, typical XSS-hole pattern:
    echo ‘{“error”:{“text”:’. $e->getMessage() .’}}’;

    secure:
    $data = array(‘error’=> array(‘text’=>$e->getMessage()));
    echo json_encode($data);

    bad:
    echo ‘{“wine”: ‘ . json_encode($wines) . ‘}’;

    better:
    $data = array(‘wine’ => $wines);
    echo json_encode($data);

    • myself

      Are you really, REALLY sure that the code fragments you quoted constitute XXS-holes?

      • myself

        of course, I meant “XSS” :)

  • darkhorn

    Why everything is in one single file? How we can separate them?

  • Ayaz

    Excellent, All doubts are cleared about (express, mongodb) with nodejs.

    Thanks :-)

  • Pablo Neutrino

    very helpful! thanks dude!!!!

  • Carles

    Greatttt!!!!!!! very useful!!! maravilloso amigo…
    Justo lo que necesitaba…
    Best regards, un abrazo from Barcelona

  • Nbaleli

    Great article, Well written and understandable even for a complete newbie, like me!
    Thank you.

  • Billy

    So, I’m still having problem. I put all the files on my localhost, and I made all the path changes and made the DB config changes.

    The errors that are being thrown have to do with the directory structure, i.e., when I try to search, I get a 404 because “localhost/search/query” doesn’t exist.

    Can someone explain the htaccess/write rules I need to implement?

    Thanks.

  • Thank you. Great article. I am looking article.

  • Kapil

    Thanks, for the good article.

    I am able to see all get services working for this example. However when I am tring for “POST” or “PUT” it gives me 500 error. Can please someone help me for a solution.

    Thank in advance.

    Regards,
    Kapil

  • luffy

    hi,
    Thanks for this article..Complete Noob question… i m using sencha touch which uses a similar ajax request like in jquery.. so thats fine but if i send parameters seperately as parameters using post method and suppose in php( call them $_post[params]) instead of sending them in a the URL is that not restful??..if it is not then what is that method called….thanks a lot

    regards

  • David

    Thanks, this was very clear and usefull

  • John Kuiper

    The tutorial is great and simple.
    But I can’t get it working.
    Firebug give me this error: [17:46:32.693] GET http://localhost/cellar/api/wines [HTTP/1.1 404 Not Found 8ms]

    I’ve changed the main.js (var rootURL = “http://localhost/cellar/api/wines”;)

    Also curl gives an 404.

    do I have to change something in the .htaccess?

  • John Kuiper

    My modwrite was not working.
    After reinstall apache and php, te problem is solved.

    With curl I get the requested data.
    But my browser is not show data.
    The main.js is extended by this function:

    function findAll() {
    console.log(‘findAll’);
    $.ajax({
    type: ‘GET’,
    url: rootURL,
    dataType: “json”, // data type of response
    success: renderList,
    error : alert(‘data error’)
    });
    }

    An error occured when retrieving data back the index.php script.

    Something is wrong in the js script but I can’t find it.

    • John Kuiper

      Finally, it works.

      I’ve had n DNS type error in main.js, therefore the client couldn’t get any information.

  • me

    GET and DELETE is working, but when I try POST using cURL it send ‘could not resolve host:application”could not resolve host:new wine’ ‘could not resolve host:year’

    PUT also not working.

  • Spanish:
    Que genial que pongas todo bien explicado y con la opción de descargar el proyecto.
    Recién estoy investigando sobre Slim, y hasta ahora no había encontrado un tutorial tan explicito… y sobre todo que tenga código funcionando, he descargado y funciona muy bien, excepto por lo de agregar (he visto los comentarios de otras personas que tienen el mismo error) pero muy explícito y muy detallado.

    You are awesome ;)

  • Hey, thanks for the great example! Slim-ing my upcoming employee business card database project (looking much like your wine project) will be a good improvement over my habitual methods. I’m also a fan of your getConnection() PHP function and formToJSON() JavaScript function!

  • Good article, is usefull, now I’m trying to figure out a little variation of the case. First in place of wine I have put something else. Second in place of jQuery I will put angular.js or Backbone.js

    Any way thank you!

  • Hey, thanks for this article. but i have a problem. i can’t add the wine to database.
    when i add, always show error message.
    thank’s before.

  • Very thanks about your suggestion

  • Alex

    For those of u who have problems with add and put, try to write \Slim before Slim::getInstance()->request();
    like
    \Slim\Slim::getInstance()->request();

    and change line 5 to:
    $app = new \Slim\Slim();

    best regards
    alex

    • This is an Awesome Simple comment thank you for your help. Saved my Day and added value to an all ready invaluable tutorial.

  • blader

    plase!!!! help me!!! please.

    I can’t use the POST whit ajax,
    I can only do gets..

    • Jonathan G

      simply remove the following line from the addWine() function:

      “error_log(‘addWine\n’, 3, ‘/var/tmp/php.log’);”

      • Robert

        event after removing – “error_log(‘addWine\n’, 3, ‘/var/tmp/php.log’);”

        I am not able to achieve the results.
        Can you share CURL Request format as well

  • Jonathan G

    To fix the Add Wine problem… simply remove the following line from the addWine() function:

    “error_log(‘addWine\n’, 3, ‘/var/tmp/php.log’);”

    Then everything works brilliantly

    Great tutorial!

  • Felix

    can’t seem to get the PUT working

    Here is my info

    // curl -i -X PUT -H ‘Content-Type: application/json’ -d ‘{“id”:”2″, username”: “winey”, “first_name”: “mr”, “last_name”: “wine”, “address”: “la”}’ http://localhost/api/users/2

    function updateUser($id) {
    $request = \Slim\Slim::getInstance()->request();
    // $body = $request->getBody();
    // $user = json_decode($body);
    $user = json_decode($request->getBody());
    $sql = “UPDATE users SET username=:username, first_name=:first_name, last_name=:last_name, address=:address WHERE id=:id”;
    try {
    $db = getConnection();
    $stmt = $db->prepare($sql);
    $stmt->bindParam(“id”, $id);
    $stmt->bindParam(“username”, $user->username);
    $stmt->bindParam(“first_name”, $user->first_name);
    $stmt->bindParam(“last_name”, $user->last_name);
    $stmt->bindParam(“address”, $user->address);
    $stmt->execute();
    $db = null;
    echo json_encode($user);
    } catch(PDOException $e) {
    echo ‘{“error”:{“text”:’. $e->getMessage() .’}}’;
    }
    }

  • sachin tyagi

    if your app is not responding.

    Add the var data = JSON.parse(data);

    into renderList(data) function into main.js file as first line.

  • Hi, Great Tutorial for Restful api.

  • Pico

    Merci beaucoup pour votre application, elle fonctionne directement bien !

    Attention pour les francophones, il faut que votre serveur web (apache) ait le fichier .htaccess activé dans le répertoire /www/cellar/api/ ainsi que le module de récriture des url activé. Vous trouverez les commandes et instructions nécessaires sur le site ubuntu-fr.org pour apache et la création de la base “cellar” dans mysql. Bonne recherche ;)

    Encore merci à Christophe Coenraets et à chacun pour ses commmentaires.

  • David

    Great tutorial who helped me to understand how Slim works with real informations.
    One thing is “missing”, an example who use an oauth authentification to secure the API.
    If you have any example…
    Thank you.

  • I know this web site offers quality based articles or reviews and other stuff, is there any other
    site which presents such stuff in quality?

  • Cedric D. Anidie

    This is a very simple but great article.
    I’ve learn alot.

    Thank you.

  • Today we’re equally experienced in online marketing, including development
    of websites, content marketing, SEO, local search, you know be page 1 ranking of Google,
    pay per click. 10 Professional direct marketers need to keep in mind that your envelope has only
    one important job – to get opened.

  • sir
    i got this error
    Slim Application Errorbody{margin:0;padding:30px;font:12px/1.5 Helvetica,Arial,Verdana,sans-serif;}h1{margin:0;font-size:48px;font-weight:normal;line-height:48px;}strong{display:inline-block;width:65px;}Slim Application ErrorThe application could not run because of the following error:Details:Message: error_log(/var/tmp/php.log): failed to open stream: No such file or directoryFile: C:\xampp\htdocs\cellar\api\index.phpLine: 45Stack Trace:#0 [internal function]: Slim::handleErrors(2, ‘error_log(/var/…’, ‘C:\xampp\htdocs…’, 45, Array)
    #1 C:\xampp\htdocs\cellar\api\index.php(45): error_log(‘addWine\n’, 3, ‘/var/tmp/php.lo…’)
    #2 [internal function]: addWine()
    #3 C:\xampp\htdocs\cellar\api\Slim\Route.php(392): call_user_func_array(‘addWine’, Array)
    #4 C:\xampp\htdocs\cellar\api\Slim\Slim.php(1052): Slim_Route->dispatch()
    #5 C:\xampp\htdocs\cellar\api\index.php(14): Slim->run()
    #6 {main}

    please help me

    if i using method GET there is no problem

  • Gideon Maina

    Good job thanks and maybe you could be posting tips and tweaks too …!!!! Great!

  • Luis

    Your tutorial was very helpful to build my web application, if I not read this article, today I’m not able to do what I did in my project.

    Thanks, and sorry for my bad English

  • Scott Warnick

    I am struggling with URL rewriting on WAMP. With the .htaccess file as distributed I get a 200 error. If remove the .htaccess file I get a 404 error as I should. Can anyone supply details on how to make this work? My apologies if it has been answered already.

  • Robert

    Any one have any idea – why POST is not working? Why its taking values from request??

    here is output
    C:\curl>curl -i -X POST -H ‘Content-Type: application/json’ -d ‘{“name”: “New Wine”, “year”: “2009”}’ http://localhost:88/cellar/api/wines
    curl: (6) Could not resolve host: application
    curl: (6) Could not resolve host: New Wine,
    curl: (6) Could not resolve host: year
    curl: (3) [globbing] unmatched close brace/bracket in column 5
    HTTP/1.1 200 OK
    Date: Thu, 19 Jun 2014 22:10:29 GMT
    Server: Apache/2.4.4 (Win64) OpenSSL/1.0.1d PHP/5.4.12
    X-Powered-By: PHP/5.4.12
    Set-Cookie: PHPSESSID=1394b9b8e54757bde9e7627b1f48a6d2; path=/
    Content-Length: 97
    Set-Cookie: 1394b9b8e54757bde9e7627b1f48a6d2=DEFAULT%7C0%7C2M3TMlgUx3gTlaarYzHIdD28l8q9FTcNubt55%2BUGpAo%3D%7C7456bf61db3500c8bb7b3bc38082a470ce4a2ad3; path=/
    Content-Type: text/html

    {“name”:null,”grapes”:null,”country”:null,”region”:null,”year”:null,”description”:null,”id”:”10″}
    C:\curl>

  • John

    This is still one of the best tuts out there. I have used this as my starting template on many projects.
    So Easy.
    Thanks Again!

  • Thanks for this value able post. I have read all the things very carefully it’s really a helpful and effective post.

  • john invictus

    thank,,thanks for creating a simple understandable tutorial

  • Patrick

    After configuration I run the app and none of the data appears. The HTML is rendered but I am left with an empty shell of an applicaion. I noticed that the hosted example of this app also exhibits the same issue? Has anyone else experienced this and figured out how to fix it? Thanks guys! Thinking this is something simple.

  • Sean Loper

    I was able to fix it and update it to newest jquery, if you need help, email me : Grimmdev@gmail.com and I’ll help explain

    • Gary

      I tried to insert record or POST I encountered error, but it will insert blank information. see error below

      C:\Users\Jun-Jin>curl -i -X POST -H ‘Content-Type: application/json’ -d ‘{“name”
      : “Red Horse”, “year”: “2014”}’ http://localhost/cellar/api/wines
      curl: (6) Could not resolve host: application
      curl: (6) Could not resolve host: Red Horse,
      curl: (6) Could not resolve host: year
      curl: (3) [globbing] unmatched close brace/bracket in column 5
      HTTP/1.1 200 OK
      Date: Mon, 01 Sep 2014 09:08:53 GMT
      Server: Apache/2.4.7 (Win32) OpenSSL/1.0.1e PHP/5.5.9
      X-Powered-By: PHP/5.5.9
      Set-Cookie: PHPSESSID=b3016b573e73eaae40108f60b48374ca; path=/
      Content-Length: 97
      Set-Cookie: b3016b573e73eaae40108f60b48374ca=DEFAULT%7C0%7C2M3TMlgUx3gTlaarYzHId
      D28l8q9FTcNubt55%2BUGpAo%3D%7C7456bf61db3500c8bb7b3bc38082a470ce4a2ad3; path=/
      Content-Type: text/html

      {“name”:null,”grapes”:null,”country”:null,”region”:null,”year”:null,”description
      “:null,”id”:”45″}

      I someone can help me on this. Thanks for big help.

      regards,

      • Angom

        Hii have you solved that issue????, if you solved please share

        This is working api for POST, i remake it but its not sending in json format request

        $app->post(‘/postwine/:id’, function() use ($app) {
        // $request = \Slim\Slim::getInstance()->request();
        //$wine = json_decode($request->getBody());

        $name = $app->request->post(‘name’);
        $grapes = $app->request->post(‘grapes’);

        $data = array($name, $grapes, …);

        $db = getConnection();
        $stmt = $db->prepare(“INSERT INTO wines(name, grapes, country, region, … ) VALUES( ?, ?, ?, …)”);
        $stmt->execute($data);
        });

  • Pingback: RESTful services with jQuery, PHP and the Slim Framework | Christophe Coenraets | Andreas V. Bourakis()

  • Gary

    Hi, newbie here in Web Services and Slim Framework. What I did today after downloading the sample in github, I successfully installed example system.

    I already tested these methods below based on the example like :
    – GET
    – PUT and
    – DELETE

    all of them are running and successfully tested but I don’t know how to run and test the POST?

    Any idea how I can test in adding records using PHP Slim Framework?

    Thanks in advance.

    • Gary

      C:\Users\Jun-Jin>curl -i -X POST -H ‘Content-Type: application/json’ -d ‘{“name”
      : “Red Horse”, “year”: “2014”}’ http://localhost/cellar/api/wines
      curl: (6) Could not resolve host: application
      curl: (6) Could not resolve host: Red Horse,
      curl: (6) Could not resolve host: year
      curl: (3) [globbing] unmatched close brace/bracket in column 5
      HTTP/1.1 200 OK
      Date: Mon, 01 Sep 2014 09:08:53 GMT
      Server: Apache/2.4.7 (Win32) OpenSSL/1.0.1e PHP/5.5.9
      X-Powered-By: PHP/5.5.9
      Set-Cookie: PHPSESSID=b3016b573e73eaae40108f60b48374ca; path=/
      Content-Length: 97
      Set-Cookie: b3016b573e73eaae40108f60b48374ca=DEFAULT%7C0%7C2M3TMlgUx3gTlaarYzHId
      D28l8q9FTcNubt55%2BUGpAo%3D%7C7456bf61db3500c8bb7b3bc38082a470ce4a2ad3; path=/
      Content-Type: text/html

      {“name”:null,”grapes”:null,”country”:null,”region”:null,”year”:null,”description
      “:null,”id”:”45″}

  • Amit

    I can’t get this code running. There is just blank HTML when I run in xampp. Please Help.Thanks

  • Sean Loper

    https://drive.google.com/file/d/0B7h4Bm_Zn_MeNFNaX0NYTUNkblk/edit?usp=sharing
    This is a complete working package of the one from Github, with updated Jquery and fixes. Prepackaged just like the github svn so just follow the same setup.

    • Jamie Hogan

      Hi Sean, I’ve attempted to use your code but I am having some problems, I’m using a Wamp server on my computer and i’ve moved all the files into the www directory and linked up the database. IS there anything that I am doing wrong ? This is my first attempt at a restful api and using the slim framework any info you have would be great :)

      • sean Loper

        if you’re still having issues feel free to email me. grimmdev(at)gmail.com

  • Powell

    Thank You, now I first understood how Rest Slim works.

  • The very first RESTful code to work with no problem,”ahsante sana”

  • Pingback: Creating Restful Services/API using the Slim Framework for PHP || Calling API using Jquery | Website and Mobile Apps - Articles and Tips()

  • David

    Fantastic job, Christophe.

    One thing I’ve been wondering/working on: Let’s say you wanted to add a comments area to the wine cellar whereby customers can rate/critique the selected wines. It would seem to me that a separate table (comments) would be required, but would they be connected via a foreign key or a join? Just curious.

  • Pingback: Practical Advice - Stages Of The API Lifecycle (Part 2/4)3scale – The API Management Solution()

  • Bob
  • Fox

    Hi, really great tutorial, but I POST and PUT are not working for me too :(

    curl -i -X POST -d ‘{“name”: “New Wine”, “year”: “2009
    “}’ http://localhost/wine/api/wines
    curl: (6) Could not resolve host: New Wine,
    curl: (6) Could not resolve host: year
    curl: (3) [globbing] unmatched close brace/bracket in column 5
    HTTP/1.1 200 OK
    Date: Tue, 03 Feb 2015 21:43:27 GMT
    Server: Apache/2.4.9 (Win32) OpenSSL/1.0.1g PHP/5.5.11
    X-Powered-By: PHP/5.5.11
    Set-Cookie: PHPSESSID=26d445ea2a48f328d88c17105a54bb32; path=/
    Content-Length: 97
    Set-Cookie: 26d445ea2a48f328d88c17105a54bb32=DEFAULT%7C0%7C2M3TMlgUx3gTlaarYzHId
    D28l8q9FTcNubt55%2BUGpAo%3D%7C7456bf61db3500c8bb7b3bc38082a470ce4a2ad3; path=/
    Content-Type: application/json

    {“name”:null,”grapes”:null,”country”:null,”region”:null,”year”:null,”description
    “:null,”id”:”46″}

    any suggestions?

  • AJ

    How to test the REST Webservices for Post, Delete. I have used Advanced REST Client in Google chrome plugin. It is inserting new record with NULL data only.

    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

  • Nice tutorial and I even started to like Slim Framework :)

  • sam

    this demo does not work for me on xxamp? any ideas?

  • fallphenix

    Cool, just
    $request = \Slim\Slim::getInstance()->request();
    rather than
    $request = Slim::getInstance()->request();

  • İs there anything that I am doing

  • Lakshmi

    Thanks Chris, that was a great tutorial for starters like us!

  • Mike

    I really like this approach! I’m curious though, if this is still an advisable approach considering the article is over three years old?

    • Samuel

      Yes, this is still one of the BEST frameworks and examples of how to use it that exists out there. I still use this as my goto project template whenever creating a new project. Developers spend way to much time beating themselves up over which framework is the best, what IDE should i use, which addons should I include etc… This mindset will run you in circles and you will end up not getting much accomplished.

      Bottom line – If you see a great tool (like this one), that’s easy to setup, simple to use, and has adequate features, then use it.. Spend your unending quest time to find the perfect framework toward actually writing you application and you will be successful.

      Cheers

  • nice article

  • I couldn’t able to resist my self to appreciate. An excellent and clear explanation. Thanks for great write up.

  • Nishant

    If you can add authentication also to this. It really useful for beginner

  • Pingback: Creating a REST API using Node.js, Express, and MongoDB | Share For Life()

  • Pingback: Being RESTful | Web Development in 30 minutes or less()

  • Hieu

    Hello, i want to make API. i want to add parameter to my API example:

    don’t use layout for post. Please help me.

    function addUser($device, $point, $phone, $email) {
    //error_log(‘addUser\n’, 3, ‘/var/tmp/php.log’);
    //$request = Slim::getInstance()->request();
    //$user = json_decode($request->getBody());
    verifyRequiredParams(array(‘device’, ‘point’, ‘phone’, ’email’));
    $device = $app->request->post(‘device’);
    $point = $app->request->post(‘point’);
    $phone = $app->request->post(‘phone’);
    $email = $app->request->post(’email’);

    if (!$this->isUserExists($device))
    {
    $sql = “INSERT INTO user (device, point, phone, email) VALUES (:device, :point, :phone, :email)”;
    try {
    $db = getConnection();
    $stmt = $db->prepare($sql);
    $stmt->bindParam(“device”, $device);
    $stmt->bindParam(“point”, $point);
    $stmt->bindParam(“phone”, $phone);
    $stmt->bindParam(“email”, $email);
    $stmt->execute();
    $user->device = $db->lastInsertId();
    $db = null;
    echo json_encode($user);
    } catch(PDOException $e) {
    //error_log($e->getMessage(), 3, ‘/var/tmp/php.log’);
    echo ‘{“error”:{“text”:’. $e->getMessage() .’}}’;
    }
    }
    else
    {
    return USER_ALREADY_EXISTED;
    }

    Thanks,

  • braja

    Any help for android .how to use this rest api in android ??

  • it’s my first pay a visit of this web site;

  • Formalarımızda kullandığımız kumaş; birinci sınıf mikro-interlok olup; esnek-fit, anti-bakteriyel, termo-balans ve hemen kuruma özelliğine sahiptir. Futbol maçlarınızda size hareket özgürlüğü sunan bu formalar; günlük olarak giyilebilecek kadar şık tasarlanmıştır.

  • качество, надежность, экономичность и связанные работы выполняются imalattan.profesyonel команду

  • Pingback: Learing RESTful API – Juibow's website()

  • Sheshadri

    is it possible to use same code using latest Slim version

  • Lyazi Derricxk

    how do you implement execute create tabel

  • Huy Tran

    Must be: http://localhost/cellar/api/index.php/wines/1
    NOTE: add index.php

css.php