warnings about "failed mapping nested object: (null)" - restkit

I'm getting JSON back from a REST call. I've created a mapping called "Teacher", which has 3 properties in it. Nothing special.
Another object "Classroom", has a property to the teacher object. So it looks something like this:
classroom : {
roomNumber : "123",
floor: 2,
id : "A123",
teacher: {
name: "John Doe",
specialty: "Science",
homeroom: "128"
},
}
The problem I'm getting is that sometimes a classroom has no dedicated "teacher", and I'm getting an empty object from the service:
teacher: { }
When I get this, RestKit gives me a warning, "failed mapping nested object: (null)".
I realize that it would be better if the service were to return "null", or no teacher property at all. But until I can convince the server guys otherwise, is there a way I can tell RestKit to not worry if I get an object like this?

Related

GraphQL java: return a partial response and inform a user about it

I have a SpringBoot application that uses GraphQL to return data to a request.
What I have
One of my queries returns a list of responses based on a list of ids supplied. So my .graphqls file is a follows:
type Query {
texts(ids: [String]): [Response]
}
type Response {
id: String
text: String
}
and the following are request & response:
Request
texts(ids:["id 1","id 2"]){
id
text
}
Response
{
"data": [
{
"id": "id 1",
"text": "Text 1"
},
{
"id": "id 2",
"text": "Text 2"
}
]
}
At the moment, if id(s) is/are not in aws, then exception is thrown and the response is an error block saying that certain id(s) was/were not found. Unfortunately, the response for other ids that were found is not displayed - instead the data block returns a null. If I check wether data is present in the code via ssay if/else statment, then partial response can be returned but I will not know that it is a partial response.
What I want to happen
My application fetches the data from aws and occasionally some of it may not be present, meaning that for one of the supplied ids, there will be no data. Not a problem, I can do checks and simply never process this id. But I would like to inform a user if the response I returned is partial (and some info is missing due to absence of data).
See example of the output I want at the end.
What I tried
While learning about GraphQL, I have encountered an instrumentation - a great tool for logging. Since it goes through all stages of execution, I thought that I can try and change the response midway - the Instrumentation class has a lot of methods, so I tried to find the one that works. I tried to make beginExecution(InstrumentationExecutionParameters parameters) and instrumentExecutionResult(ExecutionResult executionResult, InstrumentationExecutionParameters parameters) to work but neither worked for me.
I think the below may work, but as comments suggests there are parts that I failed to figure out
#Override
public GraphQLSchema instrumentSchema(GraphQLSchema schema, InstrumentationExecutionParameters parameters) {
String id = ""; // how to extract an id from the passed query (without needing to disect parameters.getQuery();
log.info("The id is " + id);
if(s3Service.doesExist(id)) {
return super.instrumentSchema(schema, parameters);
}
schema.transform(); // How would I add extra field
return schema;
}
I also found this post that seem to offer more simpler solution. Unfortunately, the link provided by host does not exist and link provided by the person who answered a question is very brief. I wonder if anyone know how to use this annotation and maybe have an example I can look at?
Finally, I know there is DataFetcherResult which can construct partial response. The problem here is that some of my other apps use reactive programming, so while it will be great for Spring mvc apps, it will not be so great for spring flux apps (because as I understand it, DataFetcherResult waits for all the outputs and as such is a blocker). Happy to be corrected on this one.
Desired output
I would like my response to look like so, when some data that was requested is not found.
Either
{
"data": [
{
"id": "id 1",
"text": "Text 1"
},
{
"id": "id 2",
"text": "Text 2"
},
{
"id": "Non existant id",
"msg": "This id was not found"
}
]
}
or
{
"error": [
"errors": [
{
"message": "There was a problem getting data for this id(s): Bad id 1"
}
]
],
"data": [
{
"id": "id 1",
"text": "Text 1"
},
{
"id": "id 2",
"text": "Text 2"
}
]
}
So I figured out one way of achieving this, using instrumentation and extension block (as oppose to error block which is what I wanted to use initially). The big thanks goes to fellow Joe, who answered this question. Combine it with DataFetchingEnviroment (great video here) variable and I got the working solution.
My instrumentation class is as follows
public class CustomInstrum extends SimpleInstrumentation {
#Override
public CompletableFuture<ExecutionResult> instrumentExecutionResult(
ExecutionResult executionResult,
InstrumentationExecutionParameters parameters) {
if(parameters.getGraphQLContext().hasKey("Faulty ids")) {
Map<Object, Object> currentExt = executionResult.getExtensions();
Map<Object, Object> newExtensionMap = new LinkedHashMap<>();
newExtensionMap.putAll(currentExt == null ? Collections.emptyMap() : currentExt);
newExtensionMap.put("Warning:", "No data was found for the following ids: " + parameters.getGraphQLContext().get("Faulty ids").toString());
return CompletableFuture.completedFuture(
new ExecutionResultImpl(
executionResult.getData(),
executionResult.getErrors(),
newExtensionMap));
}
return CompletableFuture.completedFuture(
new ExecutionResultImpl(
executionResult.getData(),
executionResult.getErrors(),
executionResult.getExtensions()));
}
}
and my DataFetchingEnviroment is in my resolver:
public CompletableFuture<List<Article>> articles(List<String> ids, DataFetchingEnvironment env) {
List<CompletableFuture<Article>> res = new ArrayList<>();
// Below's list would contain the bad ids
List<String> faultyIds = new ArrayList<>();
for(String id : ids) {
log.info("Getting article for id {}",id);
if(s3Service.doesExist(id)) {
res.add(filterService.gettingArticle(id));
} else {
faultyIds.add(id);// if data doesn't exist then id will not be processed
}
}
// if we have any bad ids, then we add the list to the context for instrumentations to pick it up, right before returning a response
if(!faultyIds.isEmpty()) {
env.getGraphQlContext().put("Faulty ids", faultyIds);
}
return CompletableFuture.allOf(res.toArray(new CompletableFuture[0])).thenApply(item -> res.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList()));
}
You can obviously separate error related ids to different contexts but for my simple case, one will suffice. I however still interested in how can the same results be achieved via error block, so i will leave this question hanging for a bit before accepting this as a final answer.
My response looks as follows now:
{
"extensions": {
"Warning:": "No data was found for the following ids: [234]"
},
"data": { ... }
My only concern with this approach is security and "doing the right thing" - is this correct thing to do, adding something to the context and then using instrumentation to influence the response? Are there any potential security issues? If someone know anything about it and could share, it will help me greatly!
Update
After further testing it appears if exception is thrown it will still not work, so it only works if you know beforehand that something goes wrong and add appropriate exception handling. Cannot be used with try/catch block. So I am a half step back again.

Insert Document with reference to Existing Document in another Collection

I'm using Java Spring and MongoDB.
I have two collections: customer and order.
I have a reference from the order to the customer collection.
I have an already existing customer.
I want to create a new order with reference to the existing customer.
My POST body request looks like this:
{
"type": "SaaS",
"units": 5,
"price": 30000,
"customer":{
"$ref": "customer",
"$id": {
"oid": "6230853866f97257c050d330"
}
}
}
However, the java serialization process can't resolve the customer subdocument. I understand that I need to apply some logic here but I can't find nor understand how to do it. Basically in mongosh syntax it look similar to this:
db.order.updateOne({_id: ObjectId("623070ab3207ac1de9f8351c")}, {$set: {customer: new DBRef('customer', new ObjectId("6230824c942afc6dee673f3b"))}})

Elastic/Opensearch: HowTo create a new document from an _ingest/pipeline

I am working with Elastic/Opensearch and want to create a new document in a different index out of an _ingest/pipeline
I found no help in the www...
All my documents (filebeat) get parsed and modified in the beginning by a pipline, lets say "StartPipeline".
Triggered by an information in a field of the incoming document, lets say "Start", I want to store that value in a special way by creating a new document in a different long-termindex - with some more information from the triggering document.
If found possibilities, how to do this manually from the console (update_by_query / reindex / painlesscripts) but it has to be triggered by an incoming document...
Perhaps this is easier to understand - in my head it looks like something like that.
PUT _ingest/pipeline/StartPipeline
{
"description" : "create a document in/to a different index",
"processors" : [ {
"PutNewDoc" : {
"if": "ctx.FieldThatTriggers== 'start'",
"index": "DestinationIndex",
"_id": "123",
"document": { "message":"",
"script":"start",
"server":"alpha
...}
}
} ]
}
Does anyone has an idea?
And sorry, I am no native speaker, I am from Germany

Error when trying to rename a nested object name in elasticsearch

I'm trying to rename data that is in this shape:
using this:
POST r_xair_signals-2020-06/_update/2020-06-15T22:23:00Z_-1344027716
{
"doc" : {
"Customer ImpactedNested" : "CustomerImpactedNested"
}
}
But I'm getting:
"type": "mapper_parsing_exception",
"reason": "object mapping for [Customer ImpactedNested] tried to parse field [Customer ImpactedNested] as object, but found a concrete value"
I've confirmed the type of Customer ImpactedNested is nested. I see info online about people getting this error, but not when trying to rename, and don't see any solutions. I saw one article that indicated it occurred when the new name conflicted with an existing name. So, tried renaming to CustomerImpactedNested11111 as a test (sure to be unique), but same result.
Any ideas would be great!
There are two problems actually.
Your query is not renaming the field.
Renaming the nested field
What is happening actually in the following line from the question:
POST r_xair_signals-2020-06/_update/2020-06-15T22:23:00Z_-1344027716
{
"doc" : {
"Customer ImpactedNested" : "CustomerImpactedNested"
}
}
It updates column value of column=Customer ImpactedNested to CustomerImpactedNested document whose id is 2020-06-15T22:23:00Z_-1344027716.
And Customer ImpactedNested is a nested object and you are trying to set a string value to the nested object field. Hence you are getting the error. Refer this
Coming to your original problem, you need to do this via reindex. Refer this, this also
POST _reindex
{
"source": {
"index": "r_xair_signals-2020-06"
},
"dest": {
"index": "<some_new_index_name>"
},
"script": {
"inline": """ctx._source['CustomerImpactedNested'] = ctx._source.remove("Customer ImpactedNested")"""
}
}
Please try the above and let me know for errors as I didn't try the above query.

Why is deep insert failing when trying to create a Contact and Account entities through a Connection in Dynamics WebAPI

I have been able to create a contact in Dynamics WebAPI using a payload similar to this ...
{
"firstname": "asd",
"lastname": "asd"
}
I have been able to create an Account entity in Dynamics WebAPI using a payload similar to this ...
{
"name":"SOLE TRADER ORG",
"emailaddress1":"otbpostman1#post.com",
"telephone1":"07188888"
}
and a Connection entity between the two as follows ...
{
"record1roleid#odata.bind":"/connectionroles(1EB54AB1-58B7-4D14-BF39-4F3E402616E8)",
"record2roleid#odata.bind":"/connectionroles(35A23B91-EC62-41EA-B5E5-C59B689FF0B4)",
"record1id_contact#odata.bind":"/contacts(645f6455-8f1d-e911-a847-000d3ab4f534)",
"record2id_account#odata.bind":"/accounts(233cf761-8f1d-e911-a847-000d3ab4f534)"
}
According to this page I should be able to do a deep insert where I can atomically create all three in one request, I have tried the following ...
{
"record1roleid#odata.bind":"/connectionroles(1EB54AB1-58B7-4D14-BF39-4F3E402616E8)",
"record2roleid#odata.bind":"/connectionroles(35A23B91-EC62-41EA-B5E5-C59B689FF0B4)",
"record1id_contact": {
"firstname": "asd",
"lastname": "asd"
},
"record2id_account": {
"name":"SOLE TRADER ORG",
"emailaddress1":"otbpostman1#post.com",
"telephone1":"07188888"
}
}
... as well a bunch of variations around this but with no luck. I keep getting errors of type ...
"code": "0x80048210",
"message": "Both objects being connected are missing."
Have I missed some key feature that means this is or is not possible?
I think record2id_account is expecting a guid, so that wont work,
as the page you linked says, they do it on opportunity, they use
"An opportunity is created because it is defined as an object within an array that is set to the value of a collection-valued navigation property opportunity_customer_accounts."
for contacts i can guess it's contact_customer_accounts and contact_customer_contacts maybe?
this will hopefully create everything at once, but how to associate to the connection is a another problem.
without testing, something like this could work:
{
"record1roleid#odata.bind":"/connectionroles(1EB54AB1-58B7-4D14-BF39-4F3E402616E8)",
"record2roleid#odata.bind":"/connectionroles(35A23B91-EC62-41EA-B5E5-C59B689FF0B4)",
"record1id_contact": {
"contact_customer_contacts":
[
{
"firstname": "asd",
"lastname": "asd"
}
]
},
"record2id_account": {
"contact_customer_accounts":
[
{
"name": "SOLE TRADER",
"emailaddress1":"otbpostman1#post.com",
"telephone1":"07188888"
}
]
}
}

Resources