I’ve received requests to talk about PUT and DELETE calls on my article about CORS with Angular.js. So here it comes!
If you don’t have the code yet, you can get it from Github. Don’t hesitate to read the original article for the setup details.
Let’s get started!
The Headers
To allow Get and Post calls from our angular.js application, we used the following code in the sinatra app:
# server.rb
before do
content_type :json
headers 'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Methods' => ['OPTIONS', 'GET', 'POST'],
'Access-Control-Allow-Headers' => 'Content-Type'
end
set :protection, false
Obviously, if we want to add Put and Delete calls, we’ll need to change this line:
'Access-Control-Allow-Methods' => ['OPTIONS', 'GET', 'POST']
To this:
'Access-Control-Allow-Methods' => ['OPTIONS', 'GET', 'POST', 'PUT', 'DELETE']
Now our server should be able to accept Put and Delete calls from any origin. You can change this behavior by specifying the allowed origin instead of putting *.
'Access-Control-Allow-Origin' => 'http://example.com'
The actions
Now we need to add actual actions to respond to PUT and DELETE requests. We’re going to reuse the POST action and simply change a bit the output. You can see all the actions below:
options '/movie' do
200
end
get '/movie' do
{ result: "Monster University" }.to_json
end
post '/movie' do
begin
params.merge! JSON.parse(request.env["rack.input"].read)
rescue JSON::ParserError
logger.error "Cannot parse request body."
end
{ result: params[:movie], seen: true, method: 'POST' }.to_json
end
put '/movie' do
begin
params.merge! JSON.parse(request.env["rack.input"].read)
rescue JSON::ParserError
logger.error "Cannot parse request body."
end
{ result: params[:movie], updated: true, method: 'PUT' }.to_json
end
delete '/movie' do
begin
params.merge! JSON.parse(request.env["rack.input"].read)
rescue JSON::ParserError
logger.error "Cannot parse request body."
end
{ result: "#{params[:movie]} deleted!", method: 'DELETE' }.to_json
end
The View
Remember the ugly view that we created to start our GET and POST calls? Let’s make even more hideous! We are just going to reuse the POST style and change the ng-model name and the function called on click.
<!doctype html>
<html ng-app="myApp">
<head>
<title>CORS App</title>
</head>
<body ng-controller="MainCtrl">
Cross-Origin Resource Sharing<br/>
<button ng-click="get()">GET</button>
Result : {{resultGet}}
<br/>
<input ng-model="moviePost"/><button ng-click="post(moviePost)">POST</button>
Result : {{resultPost}}
<br/>
<!-- NEW -->
<input ng-model="moviePut"/><button ng-click="put(moviePut)">PUT</button>
Result : {{resultPut}}
<br/>
<input ng-model="movieDelete"/><button ng-click="delete(movieDelete)">DELETE</button>
Result : {{resultDelete}}
<!-- /NEW -->
<script src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
<script src="app.js"></script>
</body>
</html>
Make the call!
Our POST call was like this:
$scope.post = function(value) {
$http.post("http://localhost:4567/movie", { 'movie': value }).success(function(result) {
console.log(result);
$scope.resultPost = result;
}).error(function() {
console.log("error");
});
};
How about we reuse it by simply changing the function name and the method called on $http.
$scope.put = function(value) {
$http.put("http://localhost:4567/movie", { 'movie': value }).success(function(result) {
console.log(result);
$scope.resultPut = result;
}).error(function() {
console.log("error");
});
};
$scope.delete = function(value) {
$http.delete("http://localhost:4567/movie", { 'movie': value }).success(function(result) {
console.log(result);
$scope.resultDelete = result;
}).error(function() {
console.log("error");
});
};
And that’s it! Try it and everything should work fine: