I'm hoping this is an easy question. I haven't made a public api using webapi or a restful service before. So I have noticed that when creating a Put or Post method that use a complex object parameter the xml sent in the body is required to contain namespace info. For example.
public HttpResponseMessage Put(Guid vendortoken, [FromBody] ActionMessage message)
{
if (message == null)
return Request.CreateErrorResponse(HttpStatusCode.ExpectationFailed,
"actionmessage must be provided in request body.");
return Request.CreateResponse(HttpStatusCode.OK);
}
For message to come back not null my request has to look like this.
<ActionMessage
xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://schemas.datacontract.org/2004/07/IntegrationModels">
<Message i:type="NewAgreement">
<AgreementGuid>3133b145-0571-477e-a87d-32f165187783</AgreementGuid>
<PaymentMethod>Cash</PaymentMethod>
</Message>
<Status>0</Status>
</ActionMessage>
the key here of course is the xmlns. On one hand the namespace is pretty generic so I feel like it shouldn't be an issue for vendors to provide, on the other hand should they really need to? If not how can I fix this so message will come back populated if they leave the name space out?
ah if only I could make them all use json :(
The namespace is significant in XML. If you want to remove it, what you can do is to change your ActionMessage class, to annotate it with the appropriate attribute (in your case, I'm assuming it would be the [DataContract(Namespace="")]), and that should remove the need for the namespace in the input (actually, after making that change using the namespace would be an error, so please consider the implications if you already have clients using your API out there).
Related
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.
I need to create an ASP.NET Web API operation that takes in a few string fields plus an optional file.
Without the file requirement, I can use the standard:
public async Task<IHttpActionResult> Post(MyModel model)
With the file always being required, I can use:
public async Task<IHttpActionResult> Post()
(this then uses a MultipartStreamProvider to extract the file and form data)
Given the fact that the file is optional though, I am not sure as to the best route to take. My android client only uses multipart/form-data if a file is present.
I can have two separate operations which seems inherently wrong. Alternatively, I can try and create a single operation that can handle both multipart/form-data and a normal post but this seems very awkward given the very different approaches required by web api in the two cases. As a third option, I can try to force all calls to use multipart at the android end but this may entail using another library which means more work.
I can't imagine I am the first person to experience this issue so am hoping someone will come up with a bright idea.
In Web API v2 when you supply data in the POST body that are not part of the model, they are ignored by the framework. This is fine in most cases, but I need to check this and return an error response, so the user doesn't get unexpected results (he expects these wrong parameters to do something...).
So how do I check for this? The model will be null, but when the framework has parsed the data and returned a null-model, I can no longer access the body through Request.Content. So what options are there?
One way is to derive your DTO class from DynamicObject. Check out my blog post: http://lbadri.wordpress.com/2014/01/28/detecting-extra-fields-in-asp-net-web-api-request/
Is it possible to have the Help Page sample generator ignore certain properties of a particular type?
For example, we use the same DTO for object Request and Response messages, for both POST and PUT requests. When user is POSTing a model (creating a new record) they don't need to provide the ID field.
But once its created and we serialize the new record into the response body, the ID field is included and returned to the client.
So in the POST request sample, I don't want the ID field to be displayed because for post request it doesn't make sense.
But the POST response sample, I do want the ID field displayed...
I am aware that there is the ApiExplorerSettings attribute which can be applied to a Class or Method...but is there anything similar for a Property?
Something like this would be great:
public class MyDTO
{
[ApiExplorerSettings(IgnoreForRequestApi = true, IgnoreForResponseApi = false)]
public int Id { get; set; }
// Other properties omitted for brevity...
}
Using the following annotation I've successfully hidden a property from the generation!
[ApiExplorerSettings(IgnoreApi = true)]
No, there isn't a similar option for a property. HelpPage uses formatter instances configured on the application to serialize the samples and as you can imagine the formatters must not have this knowledge within themselves.
Regarding workarounds:
a. You could explicitly set the raw sample for a particular action's requestsample via the SetSampleRequest extension of HttpRequestMessage. You should be able to see some examples about this in the file at *Areas\HelpPage\App_Start\HelpPageConfig.cs*.
b. In the file Areas\HelpPage\SampleGeneration\HelpPageSampleGenerator.cs, there is a method called WriteSampleObjectUsingFormatter which uses the application's formatter instances to write the samples. Here you would need to create new formatter instances having similar settings as your normal application has(so that they reflect the exact serialization/deserialization semantics that your application would normally react to when actual requests are made) and then try to hide the properties which you want to. We want to create new instances because we do not want to disturb the normal functioning of the application.
Example: In case of Json, you could create a new Json formatter instance and provide a ContractResolver which can hide the properties. Check this link: http://james.newtonking.com/projects/json/help/html/ConditionalProperties.htm
In case of Xml, I am not sure how we can hide properties without using the IgnoreDataMember attribute and also being non-intrusive.
Currently I would prefer option 'a' as its comparatively a simple workaround than 'b'.
ASP.NET WEB API uses Json.NET for JSON and DataContarctSerailizer for XML formatting so if you add [JsonIgnore] annotations over properties that you do not want included in your serialization should work just fine.
I am a web API newbie, trying my first POST to the API (all my GETs are fine). And no matter what I try, model binding doesn't seem to work. Routing is fine, because I see control coming to the correct method, but model object references is always null. I tried with a simple class as model (two properties, both strings), still no luck.
Any suggestions on what I am missing? I am using fiddler to post. eg: request body has
{"Name":"Test","Description":"Test"}
Tried with a = at the start, Tried method-argument-variable= at the start, no luck.
null always.
When you sending the parameter by request body , you must use the [FromBody] attribute in method body. [FromBody] denotes it binds the parameters from request to the model class.
Check whether you are using [FromBody] or by url ?
[System.Web.Http.HttpPost]
public List<PortalUser> GetPortalUsers([FromBody]PortalUser PortalUser)
{ }