I'm using AdviceWithRouteBuilder in my unit tests and I'm not sure how the replaceFromWith method works. The routes I'm testing looks something like this:
from(FTP_ENDPOINT)
choice()
when(predicateA)
to("routeA")
when(predicateB)
to("routeB)
otherwise()
to("routeC");
from("routeA")
to(SOMEWHERE)
from("routeB")
to(SOMEWHER)
etc...
My unit tests uses an AdviceWithRouteBuilder to replace the FTP_ENDPOINT with "direct:start" like this:
context.getRouteDefinitions().get(0).adviceWith(context, new AdviceWithRouteBuilder() {
#Override
public void configure() throws Exception {
replaceFromWith("direct:start);
}
});
My question is, how does replaceFromWith know which endpoint to replace? I only want to replace the FTP_ENDPOINT.
You have 3 routes, eg 3 x from in the code. And in the advice with, you select the first route, when you say 'get(0)', eg
context.getRouteDefinitions().get(0)
So it will use the first route, you can use get(1) to select the 2nd route. You can also select by route id, if you assign ids to your routes.
Related
I have seen 100 examples of passing an ID into $resource.get() in order to query information out of a back-end in Angular. What I have not been able to find is how to pass a complex object.
If I have a table of objects to return, and I wish to run a search against them using multiple items of filter, I need to pass those items as parameters or as one complex parameter. For example, say I have a table of people's names and their cities, states, etc. I want to be able to say something like this:
var myResource = $resource(url);
myResource.get({name : "Mike", state : "Texas"});
The return may be a single row or multiple rows. But the point is how do I get the parameters off to the API call?
The way I have other methods set up that are simpler is by creating a repository in which I return like so:
return resource('/api/broker/productionInfo/');
Then in my API I do this (after the [RoutePrefix("api/broker")] setup:
[HttpGet]
[Route("productionInfo")]
public IHttpActionResult GetProductions()
{}
That's all awesome but I want to be able to add the search criteria in the repository call and then in the API method (i.e. extract from a querystring or however it is to be passed).
If I understand what you are asking correctly, you just want to pass additional parameters into an angular resource get request. It is as simple as what you have already suggested:
resource.get({id: 1, custom_param_1: "param1", custom_param_2: "param2"});
This would result in an http request that looks like this:
/resource/1?custom_param_1=param1&custom_param_2=param2
You can then extract these parameters on the API side of things.
Something to note is that get requests have a maximum length, and if you are attaching lots of different parameters to the request, it may be better to use a post or put instead.
The only thing I'm seeing that you're missing is a [FromUri] decorate attribute, in your GetProduction API method. Since Get supports only params binding through a query string (no body binding).
Your params:
options: {
StartDate: _startDate
EndDate: _endDate
TextSearch: "some search query....",
Page: 1,
PageSize: 25,
et...
}
Then, calling your repository from your controller:
repository.get(options).$promise.then(function (data) {
// data = response payload from backend
});
reposiroty
....
return resource('/api/broker/productionInfo/');
....
API
[HttpGet]
[Route("productionInfo")]
public IHttpActionResult GetProductions([FromUri] SearchCriteriaModel criteria) {
....
}
Hope that helps.
I am trying to get to Web API GET controller using $http.get in angular application as follows :
$http.get(BasePath + '/api/documentapi/GetDocuments/' ,
{
params: {
PrimaryID: ID1,
AlternateID: ID2,
}
}).then( ...
In my case, either the PrimaryID or the AlternateID will have the value. So, one of them will be null always.
My Web api method is
public DocumentsDto[] GetDocuments(decimal? PrimaryID, decimal? AlternateID)
{ ...
When one of the value is null, the url generated by $http.get is as follows :
http://BaseServerPath/api/documentapi/GetDocuments/?PrimaryID=1688
or
http://BaseServerPath/api/documentapi/GetDocuments/?AlternateID=154
This does not hit my Web API method.
However if I use
http://BaseServerPath/api/documentapi/GetDocuments/?PrimaryID=1688&AlternateID=null
it works. I can hardcode the values to null in my params, however I would like to know if there is any correct way to achieve this.
Thanks,
Sam
I got the correct answer from #RobJ. He has posted a link to the answer. I am pasting the same answer here as well. The solution is to have default values for the Web API parameters.
public string GetFindBooks(string author="", string title="", string isbn="", string somethingelse="", DateTime? date= null)
{
// ...
}
In my case it will be
public DocumentsDto[] GetDocuments(decimal? PrimaryID = null, decimal? AlternateID = null)
{ ...
Although you've specified on your Web API controller that the two parameters can be null, the ASP.NET routing engine will still be looking for two parameters in a call to that method - even if one of them is null.
Ideally, you'd create two methods, one which takes just the primary and one just the secondary but in your case this is slightly tricky as both your IDs are of the same type. Although you can specify which parameter corresponds to the supplied value in the query string, both these methods will have the same signature (a single parameter of type decimal) in your controller class.
So you have two options here. Either create new controller so you have one which receives queries for the PrimaryID and one for the SecondaryID, or you have one method which takes an object containing one ID set to a value and the other to null, and run your query based on that.
And yet another option can be to convert the request params to a complex object and use [FromUri] to create the object from Url.
you can try this:
$http.get(BasePath + '/api/documentapi/GetDocuments/' ,
{
params: {
PrimaryID: ID1!=undefined?ID1:0,
AlternateID: ID2!=undefined?ID2:0,
}
}).then( ...
then you can handle 0 in webapi...
in my grails app I need to get some data from database and show it in a gsp page.
I know that I need to get data from controller, for example
List<Event> todayEvents = Event.findAllByStartTime(today)
gets all Event with date today
Now, how can I render it in a gsp page?How can I pass that list of Event objects to gsp?
Thanks a lot
You can learn many of the basic concepts using Grails scaffolding. Create a new project with a domain and issue command generate-all com.sample.MyDomain it will generate you a controller and a view.
To answer your question create a action in a controller like this:
class EventController {
//Helpful when controller actions are exposed as REST service.
static allowedMethods = [save: "POST", update: "POST", delete: "POST"]
def showEvents() {
List<Event> todayEvents = Event.findAllByStartTime(today)
[eventsList:todayEvents]
}
}
On your GSP you can loop through the list and print them as you wish
<g:each in="${eventsList}" var="p">
<li>${p}</li>
</g:each>
Good luck
I am not sure if this is really what you meant, because in that case I suggest you to read some more on the grails :), but anyway, for your case you can use render, redirect as well but here I am taking simplest way:
In your controller you have:
def getAllElements(){
List<Event> todayEvents = Event.findAllByStartTime(today)
[todayEvents :todayEvents ]
}
and then in the GSP(I assume you know about grails conventions, as if you don't specify view name, it will by default render gsp page with the same name as the function in the controller, inside views/):
<g:each in="${todayEvents}" var="eventInstance">
${eventInstance.<propertyName>}
</g:each>
something like this.
I'm working on a small CakePHP application that is subject to the following constraint (awkward but out of my control): I need it to work on either of two identical databases, with the choice being based on URL. For example:
http://www.example.com/myapp/foo/action/param
http://www.example.com/myapp/bar/action/param
The first obvious solution is to have two identical CakePHP applications at myapp/foo and myapp/bar with different database configurations. This has a kludgy feel to it, though, so I'm trying to find an elegant way of creating a single application.
The approach I'm considering is this: Define routes such that myapp/foo and myapp/bar will be associated with the same controller. Then give my DATABASE_CONFIG class a constructor:
function __construct() {
$pathParts = explode('/', $_SERVER['REQUEST_URI']);
if (array_search('foo', $pathParts)) {
$this->default = $this->fooConfig;
} else if (array_search('bar', $pathParts)) {
$this->default = $this->barConfig;
}
}
(Where of course I've defined fooConfig and barConfig for the two databases.) I do have control over the URL, so I can be confident that there won't be extraneous occurrences of foo or bar in the URL.
My question is this: Is there a simpler, more elegant way of handling this odd situation? Maybe something in AppModel and/or AppController? Although I'm getting rid of duplicated code, I can't shake the feeling that I'm replacing one code smell with another.
There are a few ways to do this, here is one.
Write a sweet custom route in which you always match:
Router::connect('/:ds/*', array(), array('routeClass' => 'SweetDbRoute'));
Then have SweetDbRoutes set a class variable you can use everywhere, including in your model constructors. Then it should fail so you don't actually adjust the request.
App::import('SweetDbClass', array('file' => '/path/to/your/sweet_db_class.php'));
class SweetDbRoute extends CakeRoute {
// put your failing route code here, but use your SweetDbClass to track datasource ...
// see http://book.cakephp.org/view/1634/Custom-Route-classes
}
Then in your AppModel:
App::import('SweetDbClass', array('file' => '/path/to/your/sweet_db_class.php'));
class AppModel extends Model {
public function __construct($id = false, $table = null, $ds = null) {
$ds = SweetDbClass::$ds;
parent::__construct($id, $table, $ds);
}
}
So for example, after you perform an insert in one database, the two won't be "identical", right? Are these 2 DB somehow synced with each other? I don't know what do you need to do on those DB, but it's probably easier just to do 2 separate apps.
Yes, you can specify the DB configuration in the model: http://book.cakephp.org/view/922/Database-Configuration but you can't change it on-the-fly though (the models are not expected to change association to another table, I suppose). What you do is probably the only way.
I do have control over the URL, so I can be confident that there won't be extraneous occurrences of foo or bar in the URL
Yes, there can be "extraneous occurrences of foo or bar in the URL" :)) But it won't break your app.
I'm looking for a constant or variable that will provide a public path to my application root.
I have got so far as FULL_BASE_URL which gives me http://www.example.com but I have the added problem of my application being in a sub directory (e.g. http://www.example.com/myapp/).
Is there any way to get the path like http://www.example.com/myapp/ in my controller?
$this->Html->url( '/', true );
In general you should generate all links with that function, see http://book.cakephp.org/view/1448/url
$this->base;
http://api.cakephp.org/class/dispatcher
<?php
...
$this->redirect( Router::url( "/", true ));
...
?>
Router is the static class used by the HtmlHelper::link, Controller::redirect etc. the Router::url method takes a string, or array and matches it to a route. Then it returns the url that matched the route info as a string.
If you pass "/" to the Router::url call you get a relative link to the root of your app. If you pass "/" and true to the Router::url call you will prepend the full BASE_URL to the resulting relative path. This should give you what you need. If not, here is the link to the Router documentation. Try experimenting with the second boolean param - it may or may not work as expected depending on what you read / your own testing.
http://api.cakephp.org/class/router#method-Routerurl