I'm experimenting with ASP.Net Web API, which, by convention, splits controller methods into a Restful style of Get(), Put, Post and Delete. My question is how does one handle the PUT and DELETE requests that might come from a non-Ajax browser request.
So, let's say that I have foobar with id = 123. A normal fetch request would be
/foobars/123
To delete the item, the Restful way would be to issue:
DELETE /foobars/123
However, PUT and DELETE are not browser standards and do not have enough major browser support to be trusted if your request is coming from a non-Ajax browser request. So a common accepted workaround is:
POST /foobars/123?_method=DELETE (source: Restful Web Services)
For the new ASP.Net Web API, is there a best practice / common approach for working with this problem? What I want is for anything with a _method=DELETE to be routed to the DELETE() method in the controller and _method=PUT to be routed to the PUT() method of a controller.
You can easily achieve this using a DelegatingHandler.
So you would code:
public class HttpMethodHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var queryString = HttpUtility.ParseQueryString(request.RequestUri.Query);
if(!string.IsNullOrEmpty(queryString["_method"]))
{
request.Method = new HttpMethod(queryString["_method"]);
}
return base.SendAsync(request, cancellationToken);
}
}
And then add the handler to the pipeline. I have a blog on that.
Related
For net core web api projects is it possible to use RedirectToRoute to redirect a post action of a controller to a post action of another one? (I googled it but the responses were a little bit old and stating that only get is allowed for redirection. But I would like be sure that this is still the case.) Thanks.
Returning a 307 should do the trick. That can be done using the PreserveMethodRedirect, like this
[HttpPost]
public IActionResult Received(bool status)
{
return RedirectToActionPreserveMethod("anotherAction");
}
I am beginning to use SailsJS and i found it wonderful and powerful.
Can anybody please explain me how to send POST and GET requests to an API outside Sails and where do i actually write this request?
Thanks a lot and Happy 2016 everyone!!!
Edit:
Hello #arcseldon, thank you for been trying to help me.
I'll try to explain myself better, and show you my code.
I have an API, written in php (which i think is not relevant) which accepts POST, GET, PUT, DELETE methods. I use Postman for testings and everything looks OK.
I am trying to make an app in Sails, which GETs and POSTs requests to my API, but i dont know where is the best place to put the GET's and POST's codes.
In the model i already have the following to ask for a token to perform the other requests, and it works:
gettoken: function (requestnewtoken,tokenresult) {
if(!requestnewtoken) {
tokenresult(global.tokeng);
} else {
request({
headers: {
'User-agent' : 'develop',
'Content-Type' : 'application/x-www-form-urlencoded;charset=UTF-8',
'Content-Length' : '29',
'Authorization' : 'Basic ' + global.idsecret
},
uri: "https://myapi/oauth2/token",
method: "POST",
form: {
grant_type: "client_credentials"
}
}, function(error, response, body) {
var tokenjson = JSON.parse(body);
var token = tokenjson['access_token'];
global.tokeng = token;
tokenresult(token);
});
}
}
Then, i perform a GET request to another endpoint, which works:
listpublicroutes: function(requestnewtoken,cb) {
Model.gettoken(requestnewtoken,function(token) {
request({
headers: {
'Authorization' : 'Bearer ' + token
},
uri: "https://myapi/folder/file.json",
method: "GET",
timeout: 10000,
followRedirect: true,
maxRedirects: 10
}, function(error,response, body) {
if(error || (response.statusCode != 200)) {
Model.listpublicroutes(true,cb);
} else {
cb(null,JSON.parse(body));
}
});
});
}
My doubts are if this is the best way to write a POST and GET request or they could be more simple, and if the requests should be done in the controller (or anywhere else) instead of the model.
Can you give me an example of a POST and GET request?
Thanks a lot to everyone who's trying to understand me.
Your question isn't clear exactly what you are asking... Here are a few suggestions depending on what you wish to do.
If you are trying to call out and make an http request from within
server-side Sails code then I would recommend you take a look at the
NPM module request.
If you are talking about making get / post requests to test your API,
then use a web browser plugin / tool such as postman (also a
Chrome plugin of same name).
If you are talking about calling a completely different domain URL
using AJAX from within your web application client (via web browser)
then you can just use any AJAX approach (jquery / angular / whatever
client library you are using to make ajax calls) but be aware that the
domain you are calling to would have to have been setup with a cross
origin resource sharing (CORS).
You have control over your own CORS settings (allowing apps originating from other domains to call into your sails API from the browser, by updating config/cors.js settings.
Does this answer your question? If you need further help leave me a message below, and I'll try to assist.
Update Based On Question Update:
#Michi - ok, you wish to call your PHP api from within SailsJS - the three contenders in terms of location to do this are inside a Controller, a custom Model method, or within a custom service.
My "recommendation" is that most of the time, this logic sits within a Controller if it is logic that doesn't really need to be shared elsewhere. You could conceivably call into a Model.method(), but "usually" you want to think of the models as your domain data (certainly not always, if the responsibility for what you are doing truly belongs to a single Model etc which owns all the state interaction then the model might be the right place to locate that responsibility).
However, in your case, you are getting a token, and without seeing your model code (you have just provided the getToken function which doesn't really look like it is tied to a particular model..?) then I would say opt to invoke it within your controller if not needed elsewhere. Otherwise, refactor it out into a service. To quote the SailsJS documentation:
Services can be thought of as libraries which contain functions that
you might want to use in many places of your application. For example,
you might have an EmailService which wraps some default email message
boilerplate code that you would want to use in many parts of your
application. The main benefit of using services in Sails is that they
are globalized--you don't have to use require() to access them.
I have frequently put custom logic in Controllers, Models and Services, but for networking related logic etc, my preference is:
Controller if one-off logic.
Service if reusability required, or encapsulating the code as service improves readability / maintenance of the app
Use a model, only if you strongly believe the logic and responsibility is truly tied to that model - err on the side of caution here and use sparingly. But I acknowledge my recommendations may be construed as subjective - am basing them on what I believe to be good OOP practices in general terms.
I was trying to follow along with one of the Dart HttpServer examples from GitHub, and, while it does show how to create and handle routes, I'm still at a loss on how to produce and send an HttpResponce in response to a specific url being requested.
For example, while working with WebAPI, I would have an Api Controller, in which I could explicitly define an action for GET, PUT, DELETE and POST verbs, and return an appropriate HttpResponse with a resource from each such method.
Does anyone know how this typical CRUD business is done using Dart as an Http server?
Once you receive a HttpRequest you need to use the response attribute to answer.
void sendOk(HttpRequest request, [content]) {
request.response
..statusCode = HttpStatus.OK
..write(content)
..close()
;
}
I have an REST server as backend, it provides a set of services, also, it uses basic authentication method for access.
Now I need to create an GWT frontend,so, I need to perform http calls to the REST backend from the GWT frontend
After some research I found the HttpBuilder to handle http requests to the backend, but it seem to be a pain when trying to perform cross-site requests, and also it comes with some restricions related with Safari browser.
Then I found this https://developers.google.com/web-toolkit/doc/latest/tutorial/Xsite article, where it talks about an "Proxy on your own server", so it looks to be the solution I was looking for, but I did not find more information, or an example. It says that I could create server-side code to download the data from remote server (backend), so, should I create a http client like the apache client on server-side code, and implement a set of services that use it to make request to the backend?, if yes, how to handle the user authentication and the session? if not, give me a light please.
Thanks
it seem to be a pain when trying to perform cross-site requests,
Actually you can make Cross Site Requests from GWT RequestBuilder if we can set in Servlet Response Header
Response.setHeader("Access-Control-Allow-Origin","http://yourrestserviceur.com/url");
should I create a http client like the apache client on server-side code, and implement
a set of services that use it to make request to the backend?
No, it is not required. use RequestBuilder
RequestBuilder Example:
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url);
try {
Request request = builder.sendRequest(null, new RequestCallback() {
public void onError(Request request, Throwable exception) {
displayError("Couldn't retrieve JSON");
}
public void onResponseReceived(Request request, Response response) {
if (200 == response.getStatusCode()) {
updateTable(asArrayOfStockData(response.getText()));
} else {
displayError("Couldn't retrieve JSON (" + response.getStatusText()
+ ")");
}
}
});
} catch (RequestException e) {
displayError("Couldn't retrieve JSON");
}
What is difference between a navigation in JSF
FacesContext context = FacesContext.getCurrentInstance();
context.getApplication().getNavigationHandler().handleNavigation(context, null, url);
and a redirect
HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
response.sendRedirect(url);
and how to decide when to use what?
The issue with navigation is that page URL does not change unless faces-redirect=true is added to the query string of the navigation URL. However, in my case appending faces-redirect=true throws error if I want to redirect to a non-JSF page like a plain HTML page.
And another option is as BalusC suggested at JSF 2.0 redirect error
First of all, the term "redirect" is in web development world the action of sending the client an empty HTTP response with just a Location header with therein the new URL on which the client has to send a brand new GET request. So basically:
Client sends a HTTP request to somepage.xhtml.
Server sends a HTTP response back with Location: newpage.xhtml header
Client sends a HTTP request to newpage.xhtml (this get reflected in browser address bar!)
Server sends a HTTP response back with content of newpage.xhtml.
You can track it with the webbrowser's builtin/addon developer toolset. Press F12 in Chrome/IE9/Firebug and check the "Network" section to see it.
The JSF navigationhandler doesn't send a redirect. Instead, it uses the content of the target page as HTTP response.
Client sends a HTTP request to somepage.xhtml.
Server sends a HTTP response back with content of newpage.xhtml.
However as the original HTTP request was to somepage.xhtml, the URL in browser address bar remains unchanged. If you are familiar with the basic Servlet API, then you should understand that this has the same effect as RequestDispatcher#forward().
As to whether pulling the HttpServletResponse from under the JSF hoods and calling sendRedirect() on it is the proper usage; no, that isn't the proper usage. Your server logs will get cluttered with IllegalStateExceptions because this way you aren't telling JSF that you've already taken over the control of the response handling and thus JSF shouldn't do its default response handling job. You should in fact be executing FacesContext#responseComplete() afterwards.
Also, everytime whenever you need to import something from javax.servlet.* package in a JSF artifact like a managed bean, you should absolutely stop writing code and think twice if you're really doing things the right way and ask yourself if there isn't already a "standard JSF way" for whatever you're trying to achieve and/or if the task really belongs in a JSF managed bean (there are namely some cases wherein a simple servlet filter would have been a better place).
The proper way of performing a redirect in JSF is using faces-redirect=true query string in the action outcome:
public String submit() {
// ...
return "/newpage.xhtml?faces-redirect=true";
}
Or using ExternalContext#redirect() when you're not inside an action method such as an ajax or prerender listener method:
public void listener() throws IOException {
// ...
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
ec.redirect(ec.getRequestContextPath() + "/newpage.xhtml");
}
(yes, you do not need to put a try-catch around it on IOException, just let the exception go through throws, the servletcontainer will handle it)
Or using NavigationHandler#handleNavigation() in specific cases if you're using XML navigation cases and/or a custom navigation handler with some builtin listener:
public void listener() {
// ...
FacesContext fc = FacesContext.getCurrentInstance();
NavigationHandler nh = fc.getApplication().getNavigationHandler();
nh.handleNavigation(fc, null, "/newpage.xhtml?faces-redirect=true");
}
As to why the navigation handler fails for "plain HTML" files, that is simply because the navigation handler can process JSF views only, not other files. You should be using ExternalContext#redirect() then.
See also:
How to navigate in JSF? How to make URL reflect current page (and not previous one)
When should I use h:outputLink instead of h:commandLink?