I'm using Supertest to test my APIs in my NestJS application. My tests seem to be working fine except for my DELETE request test, which throws this error:
ERROR [ExceptionsHandler] Converting circular structure to JSON
--> starting at object with constructor 'Socket'
| property '_writableState' -> object with constructor 'WritableState'
| property 'afterWriteTickInfo' -> object with constructor 'Object'
--- property 'stream' closes the circle
TypeError: Converting circular structure to JSON
--> starting at object with constructor 'Socket'
| property '_writableState' -> object with constructor 'WritableState'
| property 'afterWriteTickInfo' -> object with constructor 'Object'
--- property 'stream' closes the circle
at JSON.stringify (<anonymous>)
Here is the test I currently have:
it('should delete the relevant summary', (done) => {
request(app.getHttpServer())
.delete(`/engine/summaries/${summary_id}`)
.set('Authorization', `Bearer ${token}`)
.expect(204)
.end(done)
});
I initially thought it was because I didn't use the end() callback with 'done' passed into it, but that doesn't seem to be the issue. This is my return statement in my API if it helps: return res.status(204).send();
I've encountered this error before but it was because I was testing my asynchronous code incorrectly. However, this doesn't seem to be the issue here (or maybe it is?) and I've already spent the entire day trying to figure it out. Any help is greatly appreciated!
Related
My TValue object has foreign key related objects, which has null values when posting; I am having the logic to set the FK objects in the repository. The issue I am facing is that API controller is not getting called when FK objects have all fields null. Please see screenshot. The same code works if I set the value for all but the ID field of the FK objects from the front end.
Is the issue because Json serializer checking for nulls? I have also tried to set the null check ignore option. I am not getting an error on PostAsJsonAsync and the control simply goes to the next line of code
return await result.Content.ReadFromJsonAsync();
without calling the API controller and send an exception
public async Task<SubContract> AddSubContract(SubContract subContract)
{
/* On the injected httpClient, call the PostAsJsonAsync method and pass the subContractObject
* We also need to specifi the api Uri in the parameter list */
JsonSerializerOptions option = new()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
var result = await httpClient
.PostAsJsonAsync<SubContract>("api/SubContracts", subContract, option);
//Use the content object and ReadFromJsonSync method and typecast it to <SubContract>
return await result.Content.ReadFromJsonAsync<SubContract>();
}
Screenshot
--- Further observations ---
#Serge Thanks for the response. You are right, I am using .Net 6. I have now commented out the nullable but I still have the same issue. Further, I tried to change the function to PostAsync instead of PostAsJsonAsync; below is the new code
// ---- Post Asysc Option -----
var subContractSeralized = JsonSerializer.Serialize(subContract, option);
var stringContent = new StringContent(subContractSeralized,
encoding: System.Text.Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync("api/subcontract", stringContent);
return await response.Content.ReadFromJsonAsync<SubContract>();
I initially thought it was a serialization issue because of the nulls in the nested object but when I debug the new code, I get the below result
subContractSerealized = '{"Id":0,"Name":"Aquatic-Repairs","Status":"In-Progress","WorkTypeId":1002,"WorkType":{"Id":0},"SiteId":3,"Site":{"Id":0},"OrganizationId":3,"Organization":{"Id":0}}'
If you compare this with the Debug screen shot in my first post, you can see that the null value fields in the nested objects are omitted out
Response StatusCode = “Not Found-404”
I am not sure how Response Status code is obtained as the API is not called. I.e. httpClient.PostAsync does not transfer control to the API and my debug breakpoint is not hit.
I tried the same code for an Entity model that has no nested foreign key related objects and it works fine and I am able to add the record to the DB. I have the “Required” validation set on the field properties of the entity models; however, after the API call, I have my repository that is taking care of it. So, I doubt that is an issue. In any case, the code is not even hitting the API and simply returns an 404 NotFound on httpClient.PostAsync.
you must be using Net 6 API, and it causes a validation error. Try to comment Nullable in your API project (your serializer option is not working in this case)
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<!--<Nullable>enable</Nullable>-->
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
NextJS backend issue while dealing with http post, It throws converting circular structure to JSON error.
Here is the code stack trace which details issue
[Nest] 29840 - 01/04/2021, 2:46:31 PM ExceptionsHandler Converting circular structure to JSON
--> starting at object with constructor 'ClientRequest'
| property 'socket' -> object with constructor 'TLSSocket'
--- property '_httpMessage' closes the circle +199712ms
TypeError: Converting circular structure to JSON
--> starting at object with constructor 'ClientRequest'
| property 'socket' -> object with constructor 'TLSSocket'
--- property '_httpMessage' closes the circle
at JSON.stringify (<anonymous>)
at stringify node_modules\express\lib\response.js:1123:12)
at ServerResponse.json \node_modules\express\lib\response.js:260:14)
at ExpressAdapter.reply node_modules\#nestjs\platform-express\adapters\express-adapter.js:24:57)
at RouterResponseController.apply node_modules\#nestjs\core\router\router-response-controller.js:13:36)
at \node_modules\#nestjs\core\router\router-execution-context.js:173:48
at processTicksAndRejections (internal/process/task_queues.js:94:5)
at async node_modules\#nestjs\core\router\router-execution-context.js:47:13
at async \node_modules\#nestjs\core\router\router-proxy.js:9:17
It took some time to figure out solution however this issue can be resolved by adding below code
this.http.post(https://api-enpont,body, headerData).pipe( map(response => response.data));
Do not forget to import { map } from 'rxjs/operators';
I have a very specific question, and i really searched the answer all over the place...
Here is a situation: i have a Scatter-Gather component with a custom aggregation strategy.
http://clip2net.com/s/j66jK8 - Image of a subflow
Semantic of this process is rather simple. Request comes with Basic Authentication Header, the upper road calls just empty java processor, which returns original payload, the lower road authenticates user over LDAP, and returns Boolean result of this authentication process. Custom aggregation class checks result and if authentication was OK, then returns original payload, which results from the road #1. If not OK, then throws exception. Nothing wrong here, it works.
There is a bit tricky thing. If a user passed wrong authentication data then exception occurs in ldap:bind module. According to documentation exception is propagated to the Scatter-Gather so i'm trying to catch it using this:
#Override
public MuleEvent aggregate(AggregationContext context) throws MuleException {
for (MuleEvent event: context.collectEventsWithExceptions()) {
event.getMessage().getExceptionPayload().getException().printStackTrace();
throw new RuntimeException(event.getMessage().getExceptionPayload().getException());
}
MuleEvent result = DefaultMuleEvent.copy(context.getEvents().get(0));
if (!(Boolean) context.getEvents().get(1).getMessage().getPayload()) {
throw new SecurityException();
}
return result;
}
BUT!
As a result i see exception which stacktrace does not have javax.naming.AuthenticationException which was rased by ldap:bind component, and was printed to log automaticaly (see below).
So, my question is: how can i reach and rethrow this javax.naming.AuthenticationException exception out of Custom Aggregation Class?
I'd appreciate all you ideas and help. Thank you in advance.
WARN 2014-10-15 20:51:18,552 [[minkult].ScatterGatherWorkManager.02] org.mule.module.ldap.api.jndi.LDAPJNDIConnection: Bind failed.
ERROR 2014-10-15 20:51:18,559 [[minkult].ScatterGatherWorkManager.02] org.mule.retry.notifiers.ConnectNotifier: Failed to connect/reconnect: Work Descriptor. Root Exception was: javax.naming.AuthenticationException: [LDAP: error code 49 - INVALID_CREDENTIALS: Bind failed: Attempt to lookup non-existant entry: cn=sim,ou=people,dc=example,dc=com]; resolved object com.sun.jndi.ldap.LdapCtx#5de37d66. Type: class javax.naming.AuthenticationException
COUNT: 1
org.mule.api.transport.DispatchException: route number 1 failed to be executed. Failed to route event via endpoint: InterceptingChainLifecycleWrapper 'wrapper for processor chain 'null''
[
ScriptComponent{CheckAuth.component.553657235},
org.mule.module.ldap.processors.BindMessageProcessor#647af13d,
org.mule.module.ldap.processors.SearchMessageProcessor#2aac6fa7,
InvokerMessageProcessor [name=ldapUtils, object=com.at.mkrf.aggregate.LDAPUtils#5714c7da, methodName=findGroupByName, argExpressions=[#[payload], #[systemName]], argTypes=[Ljava.lang.Class;#5af349a6]
]. Message payload is of type: NullPayload
On a CompositeRoutingException, you can call:
exception.getExceptions().values()
to get an Array of Throwables thrown from within the scatter-gather. Then just re-throw the appropriate exception.
I have three levels deep of a hierarchy that I am binding in a JSON request:
Group -> Zone -> Segment
(1) -> (n) -> (n)
In my command object I have:
class GroupCommand {
Long id
Set zones
}
When binding the JSON request the zones get bound properly and I get a LinkedHashSet that I can get the properties of and use with my domain object. However when I get to iterating over the segments in my service:
groupCommand.zones.each { zone ->
zone.segments.each { segment ->
//Would like to get LinkedHashMap here also
//but get JSONArray
}
}
As noted above, I'd ideally like the deeply nested Segments to also bind to a LinkedHashMap but it's bound to a JSONArray.
Any suggestions how to get it bound to a LinkedHashMap as I'd like to avoid having to manipulate JSONArray in my service and thereby coupling my service with the JSON format.
If there's a way to do the conversion at the command level using a getter I'm all for that also.
thanks
EDIT:
Using
List zones = org.apache.commons.collections.list.LazyList.decorate(new ArrayList(), new org.apache.commons.collections.functors.InstantiateFactory(ZoneCommand.class))
appears to work but the underlying objects are still JSON elements. I then tried using:
List<RateZoneCommand> zones = org.apache.commons.collections.list.LazyList.decorate(new ArrayList(), new org.apache.commons.collections.functors.InstantiateFactory(ZoneCommand.class))
and at least I got an error indicating it trying to convert:
Validation error: ... org.codehaus.groovy.grails.web.json.JSONArray to required type java.util.List for property zones; nested exception is java.lang.IllegalStateException: Cannot convert value of type [org..JSONObject] to required type [ZoneCommand] for property zones[0]: no matching editors or conversion strategy found.
Create a command class for each level. Mark Zone- and Segment-command as #Validateable.
To your GroupCommand, add:
List zones = org.apache.commons.collections.list.LazyList.decorate(new ArrayList(), new org.apache.commons.collections.functors.InstantiateFactory(ZoneCommand.class))
To your ZoneCommand, add:
List segments = org.apache.commons.collections.list.LazyList.decorate(new ArrayList(), new org.apache.commons.collections.functors.InstantiateFactory(SegmentCommand.class))
In your form just use group.zones[0].segments[0]. If you change a field type of your command class, remember to restart the grails server.
I am trying to serve up my user repository via zend_json_server. The problem is the service is returning empty objects. What have i missed?
server side:
$repo = App_User_Repository::getInstance();
$server = new Zend_Json_Server();
$server->setClass($repo);
if ('GET' == $_SERVER['REQUEST_METHOD']) {
$server->setTarget('/service/json-rpc.php')
->setEnvelope(Zend_Json_Server_Smd::ENV_JSONRPC_2);
$smd = $server->getServiceMap();
// Set Dojo compatibility:
$smd->setDojoCompatible(true);
header('Content-Type: application/json');
echo $smd;
return;
}
$server->handle();
client side:
var object = new dojo.rpc.JsonService('/service/json-rpc.php');
var deferred = object.getById(1);
deferred.addBoth(function(result) {console.log(result)});
Firebug console output:
Object {}
This should be a User object
When doing the actual RPC with the "getById()" method, an dojo.deferred object is returned. At this point, a asynchronous request is running. By using the deferred object, you can define callbacks and error handlers in advance whilst waiting for the response to be returned.
Check if the actual response object isn't empty as well. Remember, you still have to use the return keyword in your attached classes to return results back to Zend_Json_Server. Zend_Json_Server will then serialize and send back the returned value automatically. A response from Zend_Json_Server is always a serialized object in JSON, containing an id (which increments automatically with each request), an string indicating what jsonrpc version is being used (ie. 2.0) and of course a result containing the returned data from the attached class.
The setClass() method should not be a object instance, but a string containing the className of the class you want to attach. Zend_Json_Server handles the creation of the object instance by itself, as well as generating the SMD (Service Method/Mapper Description). Remember to document each public method with docblocks, as Zend_Json_Server uses those docblocks to determine the SMD.
Furthermore, it is much more handy to use a fluent-like interface with the then() method like so:
var myService = new dojo.rpc.JsonService('/service/json-rpc.php?');
var deferredObj = myService.doThis('myArgument');
deferredObj.then(callback, errorHandler).then(afterCallback).then(cleanUp);
In above example, the variables callback, errorHandler, afterCallback and cleanUp, are actually references to functions. The first then() method you call, automatically passes the rpc result to the callback function. If you throw an exception from within the attached rpc class, the errorHandler method (second optional argument of the first then() method call) will be called instead.
More information: http://www.sitepen.com/blog/2010/05/03/robust-promises-with-dojo-deferred-1-5/
I recently ran into the same problem and it wasn't a problem with dojo deferred. I'm assuming getById(1) is your remote function call, in which case if your server finds results dojo shouldn't get the empty object. Even using addBoth method on a deferred object would still show the result from the server, which leads me to believe your problem is not in any of the code you've listed, but getById(1) call in your App_User_Repository class. Did you use Zend_Dojo_Data or something else to json encode before returning? That would clobber your result, Zend_Json_Server does the encoding for you.