Help implimenting restful API please! 404 when I pass parameters
Hi everyone,
I'd really appriciate a consise response to my issue here. I'm sure it's something lots of people do regularly so here goes.
I have followed the docs on umbraco.tv on implimenting ApiControllers. And indeed when I don't try to pass parameters in it works fine! However I need to pass parameters and this is where I'm falling over...
I also have a situation where I have a custom model, a SurfaceController that supplies the origional Partial, an ApiController that will supply the updated content based on the parameter. Is there a way to make my SurfaceController accessible via ajax?? I need to get this working without additional frameworks as this is an existing site and restarting with a famework can't happen!
What follows is my code example. If anyone can suggest how to make this work I'd appriciate it!
namespace MyProject.Controllers
{
public class TestApiController : UmbracoApiController
{
public TestApiController(){ }
[HttpPost]
public string ReturnString()
{
return "hello ajax return";
}
[HttpPost]
public string ReturnDynamicString(string part)
{
return "hello ajax, you sent me " + part;
}
}
}
Pretty simple huh?? Well, the ReturnString fucntion works perfectly, I can get to it via the URL /umbraco/api/testapi/returnstring and the ajax call works. However I can't get the second function to work, I get a message that the second call is not accessible via GET when I try to inspect the URL, which makes sense (no parameters). Here's my Javascript snippet:
Can I call methods on my SurfaceController via ajax??
(makes no sense to me to have one controller for initial "index" view and another to supply ajax updates, when they are based on the same model)
As an update it seems I've over compartmentalised over this. Of course the Surface controller is able to respond to ajax requests. I actually found it way easier, My mind boggles as to why they would publish tutorials on the ApiController when it's so difficult to impliment, yet so easy in a normal SurfaceController...
Anyway, to solve I modified the surface controller as below. I Added the HttpPost attribute to allow the Controller to accept the ajax post and a simple check on the HtppContext seems to make it an AJAX only method:
namespace MyProject.Controllers
{
public class MySurfaceController : SurfaceController
{
//a simple test
[HttpPost]
public JsonResult TestJson()
{
return Json("Hello Surface Ajax");
}
//passing multiple values
[HttpPost]
public JsonResult TestJsonWithParam(int brand, string test)
{
//only ajax requests please
if (!HttpContext.Request.IsAjaxRequest()) { return Json(new { success = false } ); }
return Json("Hello Surface Ajax with param " + test + " - " + brand.ToString() + " Called with context ");
}
}
}
So that makes querstion 1 somewhat covered. It seems so much moe logical to me for the SurfaceController to supply views and ajax responses, and it can use it's own custom model of course, you just need the main PartialView and a @Html.Action stub within a MacroPartial if you want it available in the RTE.
I would still recommend you use UmbracoApiController (which inherits from ApiController, we just add a few little extra handy things), not only because it's more lightweight than using a SurfaceController but also because ApiController is much better at doing content negotiation and automatically returning properly formatted data (see http://stackoverflow.com/a/9495189/5018 )
Thanks for taking the time to look into this in some more detail for me.
I see how the [FromBody] attribute works, it makes alot of sense really!
Thank you also for explaining a bit more about the UmbracoApiController, in my full case I had issues with returning IPublishedContent even with the content negotiation and properly formatted returns so I ended up making my own Model that would serialise properly and worked from that.
Also, in my circumstance I am using my Partial view in an RTE Macro. If I was to develop an UmbracoApiController approch to this how would I do away with the SurfaceController I make so that within the PartialView I can call @Html.Actnon("partial", "model")??
In order to benifit from the light weight apiController Id need to get rid of this SurfaceControllr otherwise it somewhat defeats the light weight logic as the project is now cartrying both!
Would I Forget about the SurfaceController and put my Partial View code straight into the MacroPartialView? If so, how would I pass my custom Model to the PMV? I tried the below (which resembles what I would do with a normal Partial View) but this is an error as PartialViewMacroPage doesn't accept type arguments...
Or would a surfaceController in fact be more suitable in this case where I'd like (require?) a SurfaceController for the initial view and/or manual url navigation of the page (for instance no Javascript) and extend this with ajax?
Only use REST API controllers if you're need to be working in a RESTful way (in general: javascript/ajax)
@inherits Umbraco.Web.Mvc.UmbracoViewPage<MyModel> should work - you can also do route hijacking where make a particular document type always go through a controller of your choosing and return a strongly typed partial view - see my blog http://cultiv.nl/blog/whats-this-umbraco-route-hijacking-all-about/
I have since made an UmbracoApiController that serves KML for google maps, and in this case we really benifit from the streamlined ApiController inheritance! I had to force the formatter to be always XML but hey that wasn't too bad.
As the Google Map has it's own SurfaceController and view (for the markup and RTE embedding) it was easy to simply add the map code here and point the map to the Kml Api, everything went swimmingly!
I think for the case where we want a SurfaceController anyway (some sort of Html that we can get via Html.Action, PVM or not!) it's still more semantic to initialise the model in the Surface controller and extend the controller with JSON style responses as it means no seperate ApiController, but hey I guess thats down to implimentation!
Help implimenting restful API please! 404 when I pass parameters
Hi everyone,
I'd really appriciate a consise response to my issue here. I'm sure it's something lots of people do regularly so here goes.
I have followed the docs on umbraco.tv on implimenting ApiControllers. And indeed when I don't try to pass parameters in it works fine! However I need to pass parameters and this is where I'm falling over...
I also have a situation where I have a custom model, a SurfaceController that supplies the origional Partial, an ApiController that will supply the updated content based on the parameter. Is there a way to make my SurfaceController accessible via ajax?? I need to get this working without additional frameworks as this is an existing site and restarting with a famework can't happen!
What follows is my code example. If anyone can suggest how to make this work I'd appriciate it!
Pretty simple huh?? Well, the ReturnString fucntion works perfectly, I can get to it via the URL /umbraco/api/testapi/returnstring and the ajax call works. However I can't get the second function to work, I get a message that the second call is not accessible via GET when I try to inspect the URL, which makes sense (no parameters). Here's my Javascript snippet:
So guys in a nutshell, 2 questions...
Can I call methods on my SurfaceController via ajax?? (makes no sense to me to have one controller for initial "index" view and another to supply ajax updates, when they are based on the same model)
Can anyone make my code above work??
Thanks in advance,
Danny "Blatant"
PS, I also tried to JSON.stringify the data object too...
No dice...
As an update it seems I've over compartmentalised over this. Of course the Surface controller is able to respond to ajax requests. I actually found it way easier, My mind boggles as to why they would publish tutorials on the ApiController when it's so difficult to impliment, yet so easy in a normal SurfaceController...
Anyway, to solve I modified the surface controller as below. I Added the HttpPost attribute to allow the Controller to accept the ajax post and a simple check on the HtppContext seems to make it an AJAX only method:
So that makes querstion 1 somewhat covered. It seems so much moe logical to me for the SurfaceController to supply views and ajax responses, and it can use it's own custom model of course, you just need the main PartialView and a @Html.Action stub within a MacroPartial if you want it available in the RTE.
Regards,
Danny "Blatant"
So I dove into this and there's some interesting oddities here. The following code will work:
But you'll also need to update your
ApiController
, notice the extra[FromBody]
here:Read more about this here: http://encosia.com/using-jquery-to-post-frombody-parameters-to-web-api/
I would still recommend you use UmbracoApiController (which inherits from ApiController, we just add a few little extra handy things), not only because it's more lightweight than using a SurfaceController but also because ApiController is much better at doing content negotiation and automatically returning properly formatted data (see http://stackoverflow.com/a/9495189/5018 )
Hi Sebastiaan,
Thanks for taking the time to look into this in some more detail for me.
I see how the [FromBody] attribute works, it makes alot of sense really!
Thank you also for explaining a bit more about the UmbracoApiController, in my full case I had issues with returning IPublishedContent even with the content negotiation and properly formatted returns so I ended up making my own Model that would serialise properly and worked from that.
Also, in my circumstance I am using my Partial view in an RTE Macro. If I was to develop an UmbracoApiController approch to this how would I do away with the SurfaceController I make so that within the PartialView I can call @Html.Actnon("partial", "model")??
In order to benifit from the light weight apiController Id need to get rid of this SurfaceControllr otherwise it somewhat defeats the light weight logic as the project is now cartrying both!
Would I Forget about the SurfaceController and put my Partial View code straight into the MacroPartialView? If so, how would I pass my custom Model to the PMV? I tried the below (which resembles what I would do with a normal Partial View) but this is an error as PartialViewMacroPage doesn't accept type arguments...
Or would a surfaceController in fact be more suitable in this case where I'd like (require?) a SurfaceController for the initial view and/or manual url navigation of the page (for instance no Javascript) and extend this with ajax?
Thanks for the response!
Danny "Blatant"
Only use REST API controllers if you're need to be working in a RESTful way (in general: javascript/ajax)
@inherits Umbraco.Web.Mvc.UmbracoViewPage<MyModel>
should work - you can also do route hijacking where make a particular document type always go through a controller of your choosing and return a strongly typed partial view - see my blog http://cultiv.nl/blog/whats-this-umbraco-route-hijacking-all-about/Thanks for the feedback Seb,
I have since made an UmbracoApiController that serves KML for google maps, and in this case we really benifit from the streamlined ApiController inheritance! I had to force the formatter to be always XML but hey that wasn't too bad.
As the Google Map has it's own SurfaceController and view (for the markup and RTE embedding) it was easy to simply add the map code here and point the map to the Kml Api, everything went swimmingly!
I think for the case where we want a SurfaceController anyway (some sort of Html that we can get via Html.Action, PVM or not!) it's still more semantic to initialise the model in the Surface controller and extend the controller with JSON style responses as it means no seperate ApiController, but hey I guess thats down to implimentation!
is working on a reply...