Obtain dynamic object in MassTransit consumer - masstransit

We use an empty marker interface for a group of events that need to be saved to some audit log database.
However, in the consumer, messages are cast to this interface, so we get an empty object.
What we actually need is to get the "dynamic" or get hold on the message body so we can send it to the audit database "as-is" since our database can save JSON documents. But we cannot see how we can get the message body as JSON from the context. Is it possible at all?

If you really wanted to be efficient, you could keep your consumer using the interface as it is today, but then, in your consumer, get the JToken from the message context, and use the JToken to save the JSON of the message. This way, your consumer doesn't need to know every single object type nor have the assembly for that object type.
public async Task Consume(ConsumeContext<IEvent> context)
{
ConsumeContext<JToken> jsonContext;
if(context.TryGetMessage(out jsonContext))
{
_eventStore.Save(jsonContext.Message); // the JToken
}
}

Related

apollo graphql server subscription - send only if data differs

So I created a subscription in apollo server.
i have my data for that request coming from multiple classes, nested in each other, and this works just fine.
But if I would like apollo to only send out the message if the values the client requested actually changed from the last update.
I can't just cache and compare the last sent object, as I don't know which fields this specific connection is interested in.
Is there a hook or something, that would let me compare the current "over the wire" message before it is sent, so I could compare it with the last "over the wire" message and decide if I actually want to send it?
Putting it in example let's say I have a data structure defined:
{
foo: "valueA",
bar: "valueB"
}
If I were to subscribe with one client to foo and another client to bar, and valueB got updatet to valueC, I would want only the client subscribed to bar to get an update, as the message for the client subscribed to foo would be the same as before.
While I could try to manually filter the data to recreate what would actually be sent to the specific client, this would be sort of redundant, as apollo already does this. Much rather I'd like to intercept the JSON message which gets sent over the websocket, compare it with a stored copy of the last message and decide whether I actually want to send it or to silently discard it.
Also I'm not sure how to find out, which fields the client subscribed to, but then again, I really don't want to go down that route recreating functionality apollo already has built in.
I'm not an expert in apollo graphql by any stretch of the imagination, but I had encountered some cases that could help you with this.
What I'd check first though, is wether Apollo server supports hot/cold subscriptions, but the truth is, that doesn't help much in a case of many connections.
What you should look into is a context of a connection. If it works as I think it works you should be able to create a custom resolver that'd do something along the lines of:
export const SomeResolver = {
Subscription: {
subscribeToSomeMessages: {
subscribe: withFilter(
(rootValue, args, context, info) => {
return pubsub.asyncIterator(["YOUR EVENT"])
},
(payload, variables, context, info) => {
{here compare payload with context}
{update context with new value}
return {if values differ}
}
)
},
...
You can then pass this resolver into ApolloServer initialisation block.
Hope that helps and gives you something to start with

How to map an input validation error to a specific error code in Spring

I am having a case in which I would like to do some input validation on the #RequestParams of an endpoint.
I know about Validators and Custom Validators, and my current strategy implies creating a wrapper object around the RequestParams, a custom validator and apply class level the annotation that triggers the custom validation.
My problem is that the custom validation is implementing ConstraintValidator, which means that the validator will either return true or false, and an error will be created by Spring with some text (I also know that I can change this text). My desire, however, is to create a custom payload back to the client. An example could be
class MyError {
int code;
String message;
}
The way to return this object is through a #ControllerAdvice Error handler, which understands that a ConstraintValidationException should return my custom payload format. However, I need to return different codes and messages for different reasons on the input validation failed. For example:
A Field is empty -> code XXX
A Field is formatted incorrectly -> code YYY
As far as I know, there is little customization possible on the exception that is reachable from my #ControllerAdvice, I can get a list of errors that happened but I cannot easily determine what happened. (Technically I can, but it would have to be based on the message string, which is pretty weak).
Is there a way to provide extra data to the Exception so I can distinguish from the #ControllerAdvice what happened and create my custom error response accordingly?
Am I approaching it the wrong way?
You can intercept the BindException (https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/validation/BindException.html) with the #ExceptionHandler. This contains detailed information about all validation errors. For example, with e.getFieldErrors() you can access all errors associated with fields.
For example, for a field
#MyConstraint
#Length(min = 3)
private String field;
that failed validation you get the following information in the exception:
Field error in object data on field field: rejected value [XY]; codes [Length.data.field,Length.field,Length.java.lang.String,Length].
Field error in object data on field field: rejected value [XY]; codes [MyConstraint.data.field,MyConstraint.field,MyConstraint.java.lang.String,MyConstraint].
From this you can see that it failed the #Length constraint and the custom #MyConstraint constraint.

Can we update tags on struct fields via reflection?

I would like to know if we can update tag on a struct instance before unmarshaling data into it.
type Response struct {
Name string `json:"name"`
Payload json.RawMessage `json:"default"`
}
var data Response
<update tag on data.Payload to say `json:"id"`>
json.Unmarshal(server_response, &data)
The motivation is to load common keys in Response struct and delegate API specific response to API handler by passing the raw Payload.
The Payload fields, are complex structs, hence being parsed in their own handlers makes it cleaner.
Need to apply the tag, to let json.Unmarshal know which key from server_response to map to Payload.
The metadata fields (like Name) need some validations. So, if I pass the entire response to handler, each handler has to extract each field and return this metadata, which is well, not a very clean approach.
Decoding response to map[string]interface{} also leads to same issue. I want all the fields of metadata in one struct, populated automatically and handler to parse payload. Decoding to generic map, means copying keys.
Example:
type Response struct {
Version int
Name string
Hash string
Payload json.RawMessage
}
Would like the main function to load the server response in this object, to be able to do all kinds of validations and pass on Payload to handler to let it deal with it.
Using generic map means writing code like:
decodedData.Version = genericMap["version"]
which does not scale to lots of keys.
If I understand your question properly, why don't you simply pass the entire response to the handler? The handler will then know if it needs to read from the stats or the id or whatever field... https://play.golang.org/p/pQXa3Gm_WS0 shows roughly the idea.
An alternative would be to decode your response into a map[string]interface{} and to use https://github.com/mitchellh/mapstructure afterwards to decode parts of the response into structs.

How return a Message (from Spring) to represent that the information was not found?

I'm working with messaging on Spring and I had a simple question.
When another services sends a message requesting an information that does not exists for the service that are able to answer, the first thing that I thoutght was pass a "null" do the payload:
MyResponse myResponse = service.find(id); //ops, the information with this id does not exists
Message<MyResponse> message = MessageBuilder
.withPayload(myResponse) // the information does not exists, so null
.copyHeadersIfAbsent(request.getHeaders())
.build();
But the method withPayload not accept null. So, what is the good practice or alternative to fill this message with a "empty" value to the original request receive the result and know that this information does not exists?
For now I'm passing a empty object (new MyResponse()) to the payload, but this could create a confusion for who consumes the message. I could create another class to represent this "not exists" state, but I'm trying to understand my options now.
Thanks!
The null payload doesn't bring too much information and isn't supported by many network protocols. More over there are many places in the framework which are based on the payload type, but if it is a null we might not have any information what and how to do with it. In some components the null return value is a signal to stop the flow and don't produce any messages downstream to reply.
The solution you may go is like constant object (MyNullResponse) to indicate that it is about a null.
You might also consider a way with an exception instead of an attempt to return null. Let's consider that you do some post-search processing and a bunch of filtering and conversion steps. In case of null your message will still travel all the flow down. But when we deal with an exception (like it is with the javax.persistence.EntityNotFoundException) we just bubble the problem to end-user immediately. And that's already the target service responsibility to represent that exception as a comprehensible message for end-user.
We have a JIRA ticket about null payload support. You can read there about more reasons and what other people think on the matter. My idea to allow something on the matter is like Optional.empty(). Then we can map it to null easily on the target end-user code.
You must clearly differentiate between The response itself ( in your case MyResponse object) and the existence or not of the information which something relative to you business logic, the message that you construct must be as generic as possible not hard coupled to your service layer, simple reason => the message is just a message you send to consumers , so if possible try to embed the existence or not of the information in your object MyResponse (Boolean Flag) , and construct it on the fly after invoking your service
instead of
MyResponse myResponse = service.find(id);
you can try this :
CustomResponse myResponse = service.find(id);
// use helper class to respect DRY principal if you need it somewhere
MyResponse messageReponse = ResponseBuilder.constructResponse(myReponse);
Message<MyResponse> message =// .. construct you message
In the example above ResponseBuilder take care of myResponse if it null, and fully create the response ( you could integrate all cases .. )
I would like to share with you guys my solution after read the #Artem answer.
I created an OptionalMessage class, very similar of Optional class from Java 8+. As I'm using application/json as content-type for messages.
I can use this OptionalMessage in different messages:
OptionalMessage optionalMessage = messaging.find(id);
if (optionalMessage.isPresent()) {
MyMessage myMessage = optionalMessage.getContent();
}
It has also the methods of() and empty(), used in the another side to populate the OptionalMessage.
The Json structure generated follow this example:
{
"content": { /*attributes */}
}
When we have no content (my "null" return), the Json look like this:
{
"content": null
}
I tried to use generics (OptionalMessage<MyMessage>), but I would need to change my Jackson setup (on IntegrationFlow DSL) to not receive the error java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to MyMessage when calling the getContent method.

How to always return Graphql field?

I would like to always return a field when certain requests are made so that additional actions can be performed by the client.
For example if user registration has been successful I want to show flash message. But it has to be handled by the backend and not the front end.
I could "require" clients to always request specific field that would hold the needed information but it could be easily overlooked so I'd like to return data whenever needed.
Is this possible?
There is nothing in the GraphQL spec that allows particular fields to be required in the same sense that arguments can be required. This can be handled inside the resolver, however. For example, if you have a query called getFoos, and you want to require the clients to always request the field foo when fetching that query, your resolver for getFoos could look like this:
function (obj, args, ctx, info) {
const fields = info.fieldNodes[0].selectionSet.selections.filter(s => s.name.value)
if (!fields.includes('foo')) return Promise.reject(new Error('Missing field foo!'))
// continue resolving the query as normal
}
Each resolver takes as its fourth parameter an info object that contains detailed information about the request, including what fields were requested. So inside your resolver, just verify that the field was included, and if it's missing, return a rejected Promise instead. This will cause your query to fail anytime that particular field is missing.

Resources