Spray Routing not matching HTTP Method correctly - akka

I am using Spray Routing to try to match routes using different HTTP method but when I do a GET request it actually goes through DELETE, PUT and GET. I thought delete and put rejects all requests that are not HTTP DELETE or HTTP PUT.
This is my basic code:
path(Segment ~ Slash.?) { id =>
delete {
println("Hello from DELETE")
//do stuff for delete
complete("done for DELETE")
} ~
put {
println("Hello from PUT")
//do stuff for put
complete("done for PUT")
} ~
get {
println("Hello from GET")
//do stuff for get
complete("done for GET")
}
}
If I trigger a GET request I can see the app printing:
Hello from DELETE
Hello from PUT
Hello from GET
Am I missing any return call or something?

No, your code is (almost) correct.
The issue is that, in spray, the code that lives in a method matcher but does not live under an extraction (one of the directives "extracting" something, such as "parameters" or "segment") is executed all times.
In your case, you correctly match the path extractor, but after that the route executes for all get put delete etc.
The solution for this is to add the "dynamic" keyword right below your get/put etc. The downside is that you lose some performance.
path(...) {
get {
dynamic {
...
}
}
}
Alternatively, you can reshuffle your code so that the method matcher is at the top level, and the path extractor under it
get {
path(...) {
...
}
}

Related

in the apollo-client how I may be able to log or intercept all the operations (queries and mutations)

For analytic purposes I'd like to keep track on the client side of all the graphql operations (including ie #client ones). I was unable to find appropriate options in the API and wonder if this may be doable on the apollo-client level or may I need to introduce some proxy to intercept the calls by my own?
A custom Apollo link is a way to go.
You can use apollo-link-logger in particular to log all operations to console.
Usage (from docs):
import apolloLogger from 'apollo-link-logger';
// ...
ApolloLink.from([
apolloLogger,
// ...
]);
Note: Place apolloLogger before other links.
Output example:
As the answer from Yuriy was exactly what I was looking for I marked is as accepted answer - Thanks!
Still for the record here is the code doing a job for me - I believe someone may find it useful, also it is worth to show it's simplicity.
It's worth noting that Apollo links are chainable - thus the argument to a link function are operation: Operation and forward: NextLink which is supposed to be called from our link implementation.
let analytics: Analytics; // this is Fabric.io Analytics to be provided by DI
const analyticsLink = new ApolloLink((
operation: Operation,
forward?: NextLink
) => {
const operationType = operation.query.definitions[0].operation;
return forward(operation)
.map((result: FetchResult) => {
try {
analytics.sendCustomEvent(`${operationType}.${operation.operationName}`);
} catch (e) {
console.error('analytics error', e);
}
return result;
});
});
as a bonus we can also catch errors (i.e. to leverage fabric.io crashlytics) by using apollo-link-error (handling of errors in Apollo is a bit more complex);
const analyticsErrorLink = onError((error: ErrorResponse) => {
try {
// it's worth to rethink what we wanna log here
const message = error.graphQLErrors ? error.graphQLErrors[0].message :
(error.networkError.name + ': ' + error.networkError.message);
analytics.sendNonFatalCrash('GraphQL error: ' + message);
} catch(e) {
console.error('cannot report error to analytics', e);
}
});
Finally to compose the links we should put our intercepting implementations at the beginning so we will be able to catch all the GraphQL operations including those marked with #client which are not reaching network link - in my case full link looks like:
ApolloLink.from([
analyticsErrorLink,
analyticsLink,
stateLink,
auth,
http])

How can I create an Express route that handles URLs that look like this?

app.get('/:service[SOMETHING GOES HERE]', function(req, res, next){
console.log('Service is:', req.params.service);
});
This needs to catch URLs that can look like any one of:
/foo
/foo/bar
/foo/bar/baz
The call back isn't concerned with anything that comes after foo, but ideally should be able to access foo as a parameter called service without having to manually parse the path.
I've been using this to test and still haven't found anything that does exactly that. Closest so far is /:service*.
Edit: No it's not a duplicate of the one where the answer is /:service/* because that doesn't cover /foo.
Using /:service* in actual Express routes does exactly what you want:
/foo maps to { '0': '', service: 'foo' }
/foo/bar maps to { '0': '/bar', service: 'foo' }
/foo/bar/blah maps to { '0': '/bar/blah', service: 'foo' }
The Express Route Tester, for some reason, maps these URL's differently for that these kinds of patterns (it might be configured differently than Express).
You can use the app.use() function for that. Read the doc about path handling for more info. Your code once modified will be:
app.use('/foo', function(req, res, next){
console.log('Service is:', req.params.service);
});
The downside is that you are not going to recover foo as the service parameter.

Ember makes unwanted call to backend in model hook

I want to be able to retrieve a certain conversation when its id is entered in the URL. If the conversation does not exist, I want to display an alert message with a record not found.
here is my model hook :
model: function(params){
return this.store.filter('conversation', { status : params.status}, function(rec){
if(params.status == 'all'){
return ((rec.get('status') === 'opened' || rec.get('status') === 'closed'));
}
else{
return (rec.get('status') === params.status); <--- Problem is here
}
});
}
For example, if I want to access a certain conversation directly, I could do :
dev.rails.local:3000/conversations/email.l#email.com#/convid
The problem is when I enter a conversation id which doesn't exist (like asdfasdf), ember makes call to an inexisting backend route.
It makes a call to GET conversation/asdfasdf. I'm about sure that it is only due to the record not existing. I have nested resources in my router so I'm also about sure that it tries to retrieve the conversation with a non existing id.
Basically, I want to verify the existence of the conversation before returning something from my hook. Keep in mind that my model hook is pretty much set and won't change, except for adding a validation on the existence of the conversation with the id in the url. The reason behind this is that the project is almost complete and everything is based on this hook.
Here is my router (some people are going to tell me you can't use nested resources, but I'm doing it and it is gonna stay like that so I have to work with it because I'm working on a project and I have to integrate ember in this section only and I have to use this setup) :
App.Router.map(function(){
// Routing list to raw namespace path
this.resource('conversations', { path : '/' }, function() {
this.resource('conversation', { path : '/:conversation_id'});
});
});
This also happens when I dont specify any id and I use the hashtag in my url like this :
dev.rails.local:3000/conversations/email.l#email.com#/ would make a call to conversation/
I know it is because of my nested resource. How can I do it?
By passing a query to filter (your { status : params.status}) you are asking Ember Data to do a server query. Try removing it.
From the docs at http://emberjs.com/api/data/classes/DS.Store.html#method_filter:
Optionally you can pass a query, which is the equivalent of calling find with that same query, to fetch additional records from the server. The results returned by the server could then appear in the filter if they match the filter function.
So, remove the query:
model: function(params){
return this.store.filter('conversation', function(rec) {
if (params.status == 'all') {
return rec.get('status') === 'opened' || rec.get('status') === 'closed';
} else {
return rec.get('status') === params.status;
}
});
}
Ok so here is what I did. I removed my nested resource because I realised I wasn't using it for any good reason other than redirecting my url. I decided to manually redirect my url using javascript window.location.
This removed the unwanted call (which was caused by the nested resource).
Thanks to torazaburo, you opened my eyes on many things.

Getting the "no type was found that matches the controller named" error message during Ajax Request

I've seen a lot of topics about this, but unfortunately I believe that each case is a different case (or most of them), and I really would love some experts opinion about my case in particular since I cannot make my code work even after reading through some of the other topics.
Situation: I am using an Ajax Request call in jQuery to a WebService method I have created in an WebApi project together with a MVC 4 Application.
My WebService controller class looks like the default, like this:
public class AdditionalInfoController : ApiController
{
//GET api/AdditionalInfo
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
//GET api/AdditionalInfo/5
public string Get(int id)
{
return "value";
}
//PUT api/AdditionalInfo/5
public void Put(int id)
{
string test = "";
}
}
My Ajax Request from jQuery looks like this:
function GetAdditionalInfo(obj)
{
var request = jQuery.ajax({
url: "/api/AdditionalInfo/Get",
type: "GET",
data: { id: obj.id },
datatype: "json",
async: false,
beforeSend: function () {
},
complete: function () {
}
})
.done(function (a,b,c) {
alert("Additional info was retrieved successfully!");
})
.fail(function (a,b,c) {
alert("An error happened while trying to get the additional info!");
});
}
My WebAPIConfig file looks like this:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
And last but not least, this is my problem: this error message keeps appearing when I browse the returned data variable in .fail and this is what is written:
"{
"Message":"No HTTP resource was found that matches the request URI 'http://localhost:59096/api/AdditionalInfo/Get?id=1'.",
"MessageDetail":"No type was found that matches the controller named 'AdditionalInfo'."
}"
I would really appreciate it if someone could help me as soon as possible. Thanks in advance!
Best regards,
Mad
Looking at the error looks like Web API is unable to find the controller 'type' AdditionalInfo. Web API uses assemblies resolver to scan through the assemblies and finds out the controller types. In your case for some reason its unable to find your 'AdditionalInfo' controller probably because it has some problem loading the assembly having this controller.
Try the following and see if there are any errors logged in your EventLog. If you notice any errors then probably you should check if your controllers are present in those assemblies.
Make the following change in Web.config to view errors in EventLog
<system.diagnostics>
<trace autoflush="false" indentsize="4">
<listeners>
<add name="myListener"
type="System.Diagnostics.EventLogTraceListener"
initializeData="WebApiDiagnostics" />
</listeners>
</trace>
</system.diagnostics>
In your WebApiConfig.cs, you can do the following:
IAssembliesResolver assembliesResolver = config.Services.GetAssembliesResolver();
ICollection<Assembly> assemblies = assembliesResolver.GetAssemblies();
StringBuilder errorsBuilder = new StringBuilder();
foreach (Assembly assembly in assemblies)
{
Type[] exportedTypes = null;
if (assembly == null || assembly.IsDynamic)
{
// can't call GetExportedTypes on a dynamic assembly
continue;
}
try
{
exportedTypes = assembly.GetExportedTypes();
}
catch (ReflectionTypeLoadException ex)
{
exportedTypes = ex.Types;
}
catch (Exception ex)
{
errorsBuilder.AppendLine(ex.ToString());
}
}
if (errorsBuilder.Length > 0)
{
//Log errors into Event Log
Trace.TraceError(errorsBuilder.ToString());
}
BTW, some of the above code is actually from the DefaultHttpControllerTypesResolver which Web API uses to resolve the controller types.
http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Http/Dispatcher/DefaultHttpControllerTypeResolver.cs
Edited:
One more scenario where you could hit this problem is if your controller is nested inside another class. This was a bug which was fixed later though.
Ok, so I believe I found out what was going on. I am not entirely certain, but at least my problem got fixed.
Simply by changing what was inside of the "data" field in the Ajax call and I have created a class for an object in the application to hold the whole data. It seems that for some reason the method could not have the syntax "Get(int ID)".
Instead, I did something like "Get( object)" and in the Ajax Request something like "data: obj.ID" and voila, it worked.
Also, since the framework is picky about the names of the REST methods (Get, Post, Put and Delete), I changed the name of the method to something else (like Retrieve or something).
Hopefully this will help someone in the future as well.
Best regards,
Mad
Be sure that you have the same parameter names in your methods (int id) as well as in your WebApiConfig/RouteConfig. Try it by changing
public string Get(int id)
{
return "hello";
}
to
public string Get(int? id = null)
{
return "hello";
}
I had the same problem. with me it happens due to a crush in the visual studio (2012). I had the controller file open in visual studio but it wasn't a part of my solution - I couldn't find him in the controllers directory in the solution explorer.
I just added the file to the solution by right clicking on controllers directory => add => existing item.
that fixed the problem for me.
if that doesn't work maybe try to delete the controller and add a new one with the same code . . .

Pre-routing with querystrings with Express in Node JS

I'm trying to use express to parse the querystring in case certain parameters are set and execute a little piece of code, before the actual routing is happening. The use-case is to grab a certain value, that could be set, independant of what link is being used. I use express' functionality to pass the stuff to the next possible rule using next().
So far, I tried - at the very top of all the app.get/post-rule-block:
app.get('[?&]something=([^&#]*)', function(req, res, next) {
var somethingID = req.params.something;
// Below line is just there to illustrate that it's working. Actual code will do something real, of course.
console.log("Something: "+somethingID);
next();
})
app.get('/', site.index);
and also:
app.param('something', function(req, res, next) {
var somethingID = req.params.something;
console.log("Something: "+somethingID);
next();
})
app.get('/', site.index);
Example of what should be triggered:
URL: www.example.com/?something=10239
URL: www.example.com/superpage/?something=10239
URL: www.example.com/minisite/?anything=10&something=10239
Unfortunately, none of my solutions actually worked, and all that happens is, that the next matching rule is triggered, but the little function above is never executed. Anybody have an idea, of how this can be done?
EDIT: I do understand, that the param-example wasn't working, as I'm not using said parameter within any other routing-rule afterwards, and it would only be triggered then.
I also do understand, that logic implies, that Express ignores the querystring and it is normally parsed within a function after the routing already happened. But as mentioned, I need this to be "route-agnostic" and work with any of the URL's that are processed within this application.
express does not allow you to route based on query strings. You could add some middleware which performs some operation if the relevant parameter is present;
app.use(function (req, res, next) {
if (req.query.something) {
// Do something; call next() when done.
} else {
next();
}
});
app.get('/someroute', function (req, res, next) {
// Assume your query params have been processed
});
Ok, there is quite a logical flaw in here. Routing only uses the URL, and ignores the querystring.
The (or better "A") solution is actually this:
app.get('*', function(req, res, next) {
if (req.query.something) {
console.log("Something: "+req.query.something);
};
next();
})
Explanation: As Express is ignoring the querystring for the routing, the only regular expression matching all URL's is "*". Once that is triggered, I can check if said querystring is existing, do my logic and continue the routing matching the next rule by using "next()".
And yes: facepalm