I'm currently trying to get the traverson library to fetch some information from an REST interface provided by SpringBoot.
My goal for now would be to get traverson to follow the path to
http ://localhost/users and fetch the information by using this code
traverson.from('http://localhost:8090')
.json()
.follow('$._links.user')
.getResource(function(err, resource){
if(err){
console.log(err);
return;
}
console.log(resource);
});
The json structure which is returned upon calling the endpoint looks like this:
{
"_links" : {
"ressource" : {
"href" : "http://localhost:8090/ressource{?page,size,sort}",
"templated" : true
},
"user" : {
"href" : "http://localhost:8090/user{?page,size,sort}",
"templated" : true
},
"alert" : {
"href" : "http://localhost:8090/alert{?page,size,sort}",
"templated" : true
}
}
Unfortunately this results in an error:
Uncaught TypeError: a.step.url.search is not a function
However if I just fetch the endpoint without the JSONPath Syntax it provides me the mentioned structure.
It will produce a more sensible error when I mess up the JSONPath Expression:
[Error: JSONPath expression $.links.user returned no match in document:
{"_links":{"ressource":{"href":"http://localhost:8090/ressource{?page,size,sort}
","templated":true},"user":{"href":"http://localhost:8090/user{?page,size,sort}"
,"templated":true},"alert":{"href":"http://localhost:8090/alert{?page,size,sort}
","templated":true}}]
Might be that I'm missing something super obvious which would be nice...
At least thanks for reading this far :)
To whom it might concern,
After some trial and error it turns you have to be very careful about the JSON Path expression you provide.
traverson.from('http://localhost:8090')
.json()
.follow('$._links.user.href')
.getResource(function(err, resource){
if(err){
console.log(err);
return;
}
console.log(resource);
});
This will work while this:
traverson.from('http://localhost:8090')
.json()
.follow('$._links.user')
.getResource(function(err, resource){
if(err){
console.log(err);
return;
}
console.log(resource);
});
will not.
The reason seems to be that $._links.user points to an object not an object attribute (see the endpoint structure above). This causes the evaluating function within the traverson library to cause a somewhat unintelligible error.
Let's hope that someone might make use of this information and doesn't spend hour brooding over this.
EDIT 1: After filling an issue with the library’s owner, this issue should now longer occur
Related
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])
I am trying to assert that a few steps in the code (visiting page, providing wrong card-number, password combination and clicking submit)should generate an error from the backend service - I have referred to this already..
and tried the suggestion of using Error Object as the second argument to assert.throws but that doesn't work for me.
i did see this link as well before posting my question,
My problem is - I don't have control over the code that throws the exception/error in this case. (I cannot change it to say Ember.assert etc) I just want to be able to catch an erroneous case.
Secondly, I don't have a component in this case. Its a straight forward API call that's made when click on submit is done, basically an action submitAuthForm is called in controller which calls ember cli mirage scenario that returns the following object problems object.
return new Response(401,{'X-Auth-Token': 'wrong-username-password-combination'},failResponse401);
and the returned object looks like
var failResponse401 = {
problems: [ {
field: null,
index: null,
value: null,
code: '0006',
subCode: '',
details: {},
_type: 'error'
} ]
};
We have a node_module dependency on an in-house exceptions kit that throws an Error object based on this.
Here's my Qunit test
test('ERROR_CASE_visiting /signon, provide cardNumber(2342314) and ' +
'password, submit and expect to see invalid cardnumber/password error',
function (assert) {
assert.expect(2);
assert.throws(
function () {
visit('/signon');
fillIn('#a8n-signon-card-number input', '2342314');
fillIn('#a8n-signon-password input', 'password');
click('#a8n-signon-submit-button button');
},
Error,
"Error Thrown"
);
});
I keep getting this error from Qunit
Error Thrown# 110 ms
Expected:
function Error( a ){
[code]
}
Result:
undefined
Diff:
function Error( a ){
[code]
}defined
Source:
at Object.<anonymous> (http://localhost:7357/assets/tests.js:175:12)
at runTest (http://localhost:7357/assets/test-support.js:3884:30)
at Test.run (http://localhost:7357/assets/test-support.js:3870:6)
at http://localhost:7357/assets/test-support.js:4076:12
at Object.advance (http://localhost:7357/assets/test-support.js:3529:26)
at begin (http://localhost:7357/assets/test-support.js:5341:20)
API rejected the request because of : []# 1634 ms
Expected:
true
Result:
false
Source:
Error: API rejected the request because of : []
at Class.init (http://localhost:7357/assets/vendor.js:172237:14)
at Class.superWrapper [as init] (http://localhost:7357/assets/vendor.js:55946:22)
at new Class (http://localhost:7357/assets/vendor.js:51657:19)
at Function._ClassMixinProps.create (http://localhost:7357/assets/vendor.js:51849:12)
at Function.createException (http://localhost:7357/assets/vendor.js:172664:16)
at Class.<anonymous> (http://localhost:7357/assets/vendor.js:133592:72)
at ComputedPropertyPrototype.get (http://localhost:7357/assets/vendor.js:32450:27)
at Object.get (http://localhost:7357/assets/vendor.js:37456:19)
at Class.get (http://localhost:7357/assets/vendor.js:50194:26)
at http://localhost:7357/assets/vendor.js:133645:30
Is there anything else that i can try to get it to work.
Is there someway i could somehow pass this test, by wrapping the returned response somehow in a way that it doesn't break my test altogether.
I found a workaround following this link
the user pablobm has posted a link to a helper
I used that to workaround this Qunit issue.
After working with loopback for the past 6 months, i have now encountered a problem i can't seem to figure out the reason for.
My problem occurs when using loopbacks, "where" with a "and" condition.
Like.find({
"where: {
"and": [{
"relation_id": ctx.instance.relation_id
},
{
"user_id": ctx.options.accessToken.userId
}
]
}
})
Above is the call with the where/and filter included.
I console.log the values before the call and see:
"ctx.instance.relation_id" which prints "59a32764029ab660b1c7f862"
"ctx.options.accessToken.userId" which prints "59a32597c606a85b5e08db18"
And below is the object i am trying to query:
{
"_id" : ObjectId("59a5cade884d8c48e135768c"),
"user_id" : "59a32597c606a85b5e08db18",
"relation_id" : "59a32764029ab660b1c7f862",
"created_at" : ISODate("2017-08-29T22:13:18.209+02:00"),
"status" : NumberInt("1")
}
Now. Calling the find() function without the "and" condition for just one of the values, either user_id or relation_id, returns the expected result, but with the "and" it returns an empty array.
The official Loopback documentation gives this examples for using the where/and filter:
Post.find({where: {and: [{title: 'My Post'}, {content: 'Hello'}]}},
function (err, posts) {
...
});
as shown here
And as far as i can tell, my query matches it completely, but still don't get the expected results. I know that there could be many reasons why it fails, but i was hoping someone here, maybe could give some pointers or provide insight i could use to solve my issue.
Thanks
I am trying to do a simple dynamoDB scan with a filter expression (documentation here)
This is my expression string:
"attribute_exists("my_db_key") AND ("my_db_key" = 1)"
This simply states:
"If a value for my_db_key exists AND my_db_key EQUALS 1, return it in the results"
However it does not work and I get a this error:
Invalid FilterExpression: Syntax error; token: "1", near: "= 1)
I am aware that I can use an attribute value placeholder for values and then use that in the expression but I do not want to do this. And according to Amazon's documentation it is NOT required.
So how do I do this simple expression? Does anyone have an example or link to documentation? Amazon's documentation is unfortunately of no help.
NOTE: I am implementing this with AWSDynamoDBScanInput on iOS but my issue here is to do with global expression syntax so it should not matter.
Your params need to look something like this (for the Node AWS library):
params = {
"FilterExpression": 'attribute_exists("my_db_key") AND ("my_db_key" = :value)',
"ExpressionAttributeValues": {
":value": 1
},
// ...
};
docClient.scan(params, function(err, data){
// Handle err or process data
})
For some languages, the parameters should look more like this:
{
"FilterExpression": 'attribute_exists("my_db_key") AND ("my_db_key" = :value)',
"ExpressionAttributeValues": {
":value": {"N":1}
},
// ...
};
You have to use a placeholder and pass the value separately. Here's some documentation and a Post from AWS forums
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 . . .