The idea is to call a certain function when a route matches. That function has dependencies . I'm new to clojure and compojure and this approach could be wrong.
But still, this is what I try to achieve.
(defroutes my-routes (GET "/user/list"
[]
(list-users)) ; where list-users is for example (partial list-users user-service)
Since I didn't find a way to do this with defroutes, I tried to setup the routes "dynamically".
(defn define-routes [services]
(routes
(GET "/user/:id"
[id]
((:show-user services) id))
(GET "/user/list"
[]
((:list-users services))))
When I start jetty with the routes defined like this,
(defn app [services]
(j/run-jetty (define-routes services) {:port 3000 :join? false}))
every call leads to an exception:
java.lang.NullPointerException: Response map is nil
Is there a way to use defroutes and call functions where dependecies are injected or is ok to do it the way I tried, but I'm doing it wrong?
When you return the data that doesn't implement compojure.response/Renderable protocol, compojure doesn't know how to render it, so it expects that your result would be the whole response map.
More details can be found in the compojure documentation
So what you have to do is either implement Renderable for your data, or create the ring response yourself (presumably with some libraries), like they do in ring.util.response
Related
I am just starting with language-ext, trying to use it in my Azure Function.
In this function, I first parse/validate the POSTed data from the HTTP request using some validator.
This validator returns an Either<ValidationErrors, RequestModel>.
Then I would like to chain onto the either result a service call that should use the request model to grab some data from an API an return an Option.
At the end of the chain I would then like to return an IActionResult BadRequest if there were ValidationErrors in the first step, or otherwise perform a Match on the result of the service call Option to either return a NotFoundResult or ObjectResult.
The issue I run into is that if I want to chain my service call (using Bind, or BiBind) after the Either<ValidationErrors, GetRequestModel>, then the signature of my service method must be some Either<ValidationErrors, ...>, which is incorrect, since my service method has nothing to do with ValidationErrors. It should just return an Option.
So I guess my question is how can preserve any ValidationErrors until the end of the chain, and be able to chain my service call with a Option signature onto an Either?
You have to decide what the result of your chained expression is.
Option:
var maybeResult = from validated in GetValidationResult(...).ToOption()
from apiResult in ApiCall(...)
select apiResult;
Either:
var resultOrError = from validated in GetValidationResult(...)
from apiResult in ApiCall(...).ToEither(*LEFT*)
select apiResult;
You have to replace *LEFT* by some error value or error generating function returning same type like left type of GetValidationResult.
Replace above pseudo code with your own code and look at the return types of the functions used above to see what's going on.
The reason why you need a common left type is that the bind operation can return some left (error) of first (GetValidationResult) or second (ApiCall) function call -- or right of your last (ApiCall) function if your reach successful end of your chain.
Recommendation: If you mix different left (error) return types you might want to use some thing like LanguageExt's built-in Error type or maybe just a plain string (or Exception).
Either with string as error type:
var resultOrError = from validated in GetValidationResult(...).MapLeft(Prelude.toString)
from apiResult in ApiCall(...).ToEither("api call failed")
select apiResult;
Additional note: I use LINQ style here, you can use method style:
var resultOrError = GetValidationResult(...)
.MapLeft(Prelude.toString)
.Bind(validated => ApiCall(...)
.ToEither("api call failed"));
I am creating a service that aggregates data and will need to be able to read any unknown JSON document. I have the pipeline defined as follows:
private def pipeline = (
addHeader("Accept", "application/json")
~> sendReceive
~> unmarshal[JsObject] // Need this to work for JsObject or JsArray //
~> recover
)
This will work with a JsObject but not a JsArray. If I change it to a JsArray then it will not (of course) work with a JsObject. My recover method returns a JsObject.
I would love to be able to define this as a JsValue or enforce a Root format, but for JsValue I get the following compiler error:
could not find implicit value for evidence parameter of type spray.httpx.unmarshalling.FromResponseUnmarshaller[spray.json.JsValue]
And Root Formats also error.
I am not sure how to accomplish what I need, any help would be appreciated.
Use Either, Eric! :) If the response will be either JsObject or JsArray then Either is good solution.
private def pipeline =
addHeader("Accept", "application/json")
~> sendReceive
~> unmarshal[Either[JsObject, JsArray]]
~> recover
However, beware that unmarshal[Either[JsObject, JsArray]] tries to parse response as JsObject first and if it fails, tries to parse it as JsArray. This may lead some performance issues.
After reviewing #Mustafa's answer I created the following to avoid the potential performance hit. In the end, I really only need a JSON AST to pass on.
In the most simple terms, I simply created a function to handle it:
def unmarshalJSON(httpResponse: HttpResponse): JsValue = {
httpResponse.entity.asString.parseJson
}
and altered below:
private def pipeline = {
addHeader("Accept", "application/json")
~> sendReceive
~> unmarshalJSON
~> recover
}
I would of course want to beef this up a bit for production level code, but this could be another alternative and allows me to return a JsValue. #Mustafa I would be interested to hear your thoughts.
I'm trying out Silex and I'm having a bit of a problem, or I might say, more of an inconvenience...
I'm trying to load 2 routes from 2 separate yaml files, but for some reason the mounting ($app->mount(...)) doesn't work with closures.
Here's some code:
// load configuration
$loader->load('core.yml');
$loader->load('api.yml');
function bla($app, $container, $key) {
$myApp = $app['controllers_factory'];
foreach ($container->getExtensionConfig('routes')[$key] as $name => $route) {
$controller = $myApp->match($route['pattern'], $route['controller']);
$controller->method($route['requirements']['_method']);
$controller->bind($name);
}
return $myApp;
}
$app->mount('/core', bla($app, $container, 0));
$app->mount('/api', bla($app, $container, 1));
This works.
What doesn't work is if I do the exact same thing with closures, like this:
$app->mount('/core', function ($app, $container, $key) {
return $app['controllers_factory'];
});
Gives the following error:
LogicException: The "mount" method takes either a ControllerCollection or a ControllerProviderInterface instance.
But
var_dump($app['controllers_factory']);
spits out an object of type Silex\ControllerCollection.
I'm obviously missing something.
Thank you for your help.
The problem
In your first example, you're mounting the result of a function. In your second example, you're mounting the function itself.
Function bla() returns the controller collection when it's called. When you do
$app->mount('/core', bla($app, $container, 0));
the function is executed first and then the returned ControllerCollection is mounted.
But when you do
$app->mount('/core', function ($app, $container, $key) {...});
the function is not executed. It is treated as an object and mounted. Since the function itstelf is not a ControllerCollection or a ControllerProviderInterface, you get the error.
Two alternatives
Use PHP routing
This is how I like to do it. I don't know if this is "the Silex way", but it works well for me.
You mount each controller collection like so:
$app->mount('/core', include 'controllers/core.php');
$app->mount('/api', include 'controllers/api.php');
Each controller collection goes in a separate file in the controllers folder. So api.php might look like this:
$controllers = $app['controllers_factory'];
$controllers->get('/version', function() use ($app) {
// do whatever you want
return 'version 1.2';
});
return $controllers;
There may even be a way of doing this using the YML loader and keeping your routes in yml files, but I don't like mixing yml and php in general. Why use two technologies when you can just use one.
A fancier way
Take a look at this article. His technique is way more elegant than mine, but also more complicated. It's probably better for larger projects. Maybe it will work better for you.
I am currently creating a Backbone.js and jquery Mobile web application and I have some calls to Backbone.model.fetch().
I have the proper success and error-callbacks, but there is some code that I want to execute no matter if the fetch was successfull or not.
Currently, I'm simply copying the common code. But I asked myself if there is any callback that is executed no matter what happens.
Like the try{} catch{} finally{} from C#.
Is there anything like that?
fetch() returns a 'Deferred Object'
see: http://api.jquery.com/category/deferred-object/
it's not really like try{} catch{}, but you can use .always() method to bind a callback which will be executed after the request is done (no matter if it was successful or not)
like so.
var doSomething = function () {
//will run after fetch() request is finished
};
collection.fetch().always(doSomething);
similarly, instead of passing success or error callbacks to fetch()'s options, in general it is encouraged to chain .done(), .fail(), or .then() methods to deferred methods(fetch, save...etc)
I'm using StructureMap, v. 2.5.3 and am having trouble with chaining together implementations on an interface to implement the Decorator pattern.
I'm used to Windsor, where it is possible to name variations on interface implementations and send the named impl. into another (default) impl.
This is the default, non decorated version, which works fine:
ObjectFactory.Initialize(registry =>
{
registry.ForRequestedType<ICommentService()
.TheDefault.Is.OfConcreteType<CommentService>();
... }
This is the ctor on the decorator, that I want to call:
public CommentAuditService( ICommentService commentService,
IAuditService auditService )
This works, but does not give me access to the decorated object:
registry.ForRequestedType<ICommentService>()
.TheDefault.Is.OfConcreteType<CommentService>()
.EnrichWith(x => new CommentAuditService());
This takes me int an inf. loop:
registry.ForRequestedType<ICommentService>()
.TheDefault.Is.OfConcreteType<CommentService>()
.EnrichWith(x => new CommentAuditService( new CommentService(),
new AuditService()));
So far this is what seems to me should work:
registry.ForRequestedType<ICommentService.()
.TheDefault.Is.OfConcreteType<CommentAuditService>()
.WithCtorArg("commentService")
.EqualTo(new CommentService());
However it send it into an endless loop of creating new instances of CommentAuditService
Does anyone have an quick answer? (other than switching to Castle.Windsor, which I'm very close to at the moment)
You were very close. Try:
registry.ForRequestedType<ICommentService>()
.TheDefaultIsConcreteType<CommentService>()
.EnrichWith(original => new CommentAuditService(original,
new AuditService()));
If AuditService might itself have dependencies, you would do:
registry.ForRequestedType<ICommentService>()
.TheDefaultIsConcreteType<CommentService>()
.EnrichWith((ioc, original) => new CommentAuditService(original,
ioc.GetInstance<AuditService>()));
Or, if you change the last part to:
ioc.GetInstance<IAuditService>()
you can register the concrete type of your audit service separately.