how can i return 404 http status from dropwizard - dropwizard

new to dropwizard! is there anyway that I can manually return different http status codes from the apis? basically something similar to this!
#GET
#Timed
public MyObject getMyObject(#QueryParam("id") Optional<String> id) {
MyObj myObj = myDao.getMyObject(id)
if (myObj == null) {
//return status.NOT_FOUND; // or something similar
// or more probably
// getResponseObjectFromSomewhere.setStatus(mystatus)
}
return myObj;
}

It's as simple as throwing a WebApplicationException.
#GET
#Timed
public MyObject getMyObject(#QueryParam("id") Optional<String> id) {
MyObject myObj = myDao.getMyObject(id)
if (myObj == null) {
throw new WebApplicationException(404);
}
return myObj;
}
As you get further along you may want to put together custom exceptions which you can read more about here.

I would recommend using the JAX-RS Response object instead of returning your actual domain object in the response. It serves as an excellent standard for including metadata with your response object and provides a nice builder for handling status codes, headers, customer content types, etc.
//import javax.ws.rs.core.Response above
#GET
#Timed
public Response getMyObject(#QueryParam("id") Optional<String> id) {
MyObject myObj = myDao.getMyObject(id)
if (myObj == null) {
//you can also provide messaging or other metadata if it is useful
return Response.status(Response.Status.NOT_FOUND).build()
}
return Response.ok(myObj).build();
}

The simplest way is to return an Optional<MyObject>. Dropwizard will automatically throw a 404 when your result is Optional.absent() or Optional.empty() if you use the dropwizard-java8 bundle.
Just do:
#GET
#Timed
public Optional<MyObject> getMyObject(#QueryParam("id") Optional<String> id) {
Optional<MyObject> myObjOptional = myDao.getMyObject(id)
return myObjOptional;
}
Obviously you need to update your DAO according by returning Optional.fromNullable(get(id)) for Guava or Optional.ofNullable(get(id)) for Java8 bundle.
There is no need to play around with custom Response objects unless you want to return a custom status code outside of 200 and 404

Related

Ok() vs Ok(null)

What's the difference between Ok() vs Ok(null)?
The Ok(null) returns status code 204 with no body but header, therefore we have to change our code in this way:
[HttpGet]
public IActionResult GetTest(string test)
{
MyClass result = GetMyClass(test)
if(result == null) return Ok();
return Ok(result);
}
I suggest you use NoContent (HttpStatus 204).
That means the request successfully executed, but didn't return a value or object, and it's an official status code for this purpose
See the following example:
[HttpGet()]
public IActionResult GetTest(string test)
{
var result = GetMyClass(test)
return result != null
? Ok(result)
: NoContent();
}
Hope you'll find this useful.
Official documentation says
Ok() Creates a OkResult object that produces an empty Status200OK
response.
Ok(Object) Creates an OkObjectResult object that produces an
Status200OK response.
https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.controllerbase.ok?view=aspnetcore-2.1
When you pass null , it will creates an OkObjectResult of null , So you are getting 204 status code.
HTTP status code 204 is a valid "success" result that lets the recipient know that there is no content. This actually seems rather appropriate, but still it may not be supported everywhere.
Either your could 'teach' (or program) your recipient to handle it correctly, or you need to apply your workaround.
If you need this workaround in multiple places then you could use a base class to overload Ok() (or more precisely, redefine it) to always do what you need, like this:
public abstract class MyBaseApiController : ApiController
{
public new IHttpActionResult Ok<T>(T content)
{
if (content == null) return base.Ok();
return base.Ok(content);
}
}

Change returned object value after action execution in Web API

In ASP.Net Web API, the action returned object will be converted to XML or JSON automatically - is there a way to add additional process to the returned object before it gets converted?
What I want to achieve is to wrap returned object into a generic APIResponse (another class) type which has an object Property called Data that will be assigned with whatever the original returned object is.
for example:
public Books[] FindBooks(string keyword)
{
..
return new Books[] {new Book(){Name="ASP.NET"}};
}
This will return JSON of book array by default, however I want to wrap the result into an object called APIResponse, so the returned object becomes:
new APIResponse(){
Data = //the Book[] array return from the action method
}
By doing this, I will be able to keep the freedom of returning normal business objects in Web API however always return the same object type in JSON format when the front-end Ajax requests.
I believe it can be done in a way however I'm not familiar with the Web API life cycle, can any way give some guide on this?
Thank you.
I fixed it by creating a custom MediaTypeFormatter however simply inheriting from JSON formatter which have already got all what I need, here is the very simple code I added, which resolved all issues I have!!!
public class APIResponseMediaFomatter : JsonMediaTypeFormatter
{
public override Task WriteToStreamAsync(Type type, object value, System.IO.Stream writeStream, System.Net.Http.HttpContent content, System.Net.TransportContext transportContext)
{
ResponseMessage wrappedValue = null;
if (type != typeof(ResponseMessage) || (value != null && value.GetType() != typeof(ResponseMessage)))
wrappedValue = new ResponseMessage(value);
return base.WriteToStreamAsync(typeof(ResponseMessage), wrappedValue, writeStream, content, transportContext);
}
}
Cheers!
Interestingly, Web API already works exactly how you describe. It already has generic request and response classes that can hold your object payload. Just do the following,
public HttpResponseMessage FindBooks(string keyword)
{
...
var books = new Books[] {new Book(){Name="ASP.NET"}};
var content = new ObjectContent<Book[]>(books,new JsonMediaTypeFormatter());
return new HttpResponseMessage { Content = content);
}
There is no need to re-invent your own generic response object that can hold metadata and data, HTTP has already done that for you.
Why dont you return your wrapper object APIResponse from WebAPI
public APIResponse FindBooks(string keyword)
{
var books = new Books[] {new Book(){Name="ASP.NET"}};
return new APIResponse {Data= books };
}
Just use an action filter, and modify the response content inside it:
public class ApiResponseWrapperActionFilter : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
// Check that the response is an object content
var objectContent = actionExecutedContext.Response.Content as ObjectContent;
if (objectContent != null)
{
// Wrap the returned value in the ApiResponse
objectContent.Value = new ApiResponse() { Data = objectContent.Value };
}
}
Apply the filter to the whole API (in global config) or a whole controller (attribute applied to the controller class) or to the desired methods (attribute in each method).
If you're returning something that it's not an object (a custom response) it will skip the wrapping.

In ASP.Net Web API, how do I map multiple http query parameters to a single method parameter

We're using ASP.Net Web API to generate a feed and it includes the ability to do paging.
myfeed.com/afeed?page=2
My boss says "let's also allow users to use 'paged', because that's what WP uses." In addition, we're also using pageIndex in some of our older feeds. So what I'd like to do is accept all three.
myfeed.com/afeed?page=2
myfeed.com/afeed?paged=2
myfeed.com/afeed?pageIndex=2
I'd like to do is be able to write a clean Web API method, such as
public Foo Get(int page = 1)
{
//do some stuff
return foo;
}
without cluttering the method with page 'plumbing'. So I tried creating an ActionFilter
public override void OnActionExecuting(HttpActionContext actionContext)
{
object pageParam = new object(); //query["page"]
if (pageParam == null)
{
var altPageParam = GetPageParamUsingAlternateParams(actionContext);
if (altPageParam != null){}
//SetPageParam here
}
base.OnActionExecuting(actionContext);
}
private object GetPageParamUsingAlternateParams(HttpActionContext actionContext)
{
object result = new object();
object pageIndexParam = new object(); //Query["pageIndex"]
object pagedParam = new object(); ////Query["paged"]
if (pagedParam != null)
result = pagedParam;
else if (pageIndexParam != null)
result = pageIndexParam;
return result;
}
I didn't finish. As I was looking for the best way to get the query params, I stumbled into a big mistake!
OnActionExecuting is executed after int page = 1. Sure, I could override it in an ActionFilter, but that would lead to confusion down the road. I really want to be able to do a simple flow through the URI query parameters that goes from
page -> paged -> pageIndex -> default value in method
I have found a lot of articles on custom binding to a an object. Also, I found articles about "parameter binding", however those dealt with FromUri and FromBody. I didn't find anything that I felt had a direct parallel to what I'm facing.
You could achieve what you want by defining 3 different GET method with parameters matched with the query segment of the Url like the code snippet below:
public class ProductsController : ApiController
{
//Matched api/products?page=1
public IHttpActionResult Get(int page)
{
return GetPagedData(page);
}
//Matched api/products?paged=1
public IHttpActionResult GetPaged(int paged)
{
return GetPagedData(paged);
}
//Matched api/products?pagIndex=1
public IHttpActionResult GetPageIndex(int pageIndex)
{
return GetPagedData(pageIndex);
}
//Do the real paging here
private IHttpActionResult GetPagedData(int page =1)
{
return Ok("Data Pages");
}
}

In OpenRasta, how should you handle codec errors or exceptions?

My scenario is this:
A client application executes a HTTP POST against an endpoint exposed by OpenRasta.
The body of the request contains an error that causes a problem in the codec - which is a custom implementation of OpenRasta.Codecs.IMediaTypeReader. This converts a JSON payload to the POCO expected by the handler.
The codec throws an exception that describes the error in a useful way. For example: Newtonsoft.Json.JsonReaderException: After parsing a value an unexpected character was encountered: ". Line 4, position 5.
The client application receives a HTTP 405 - MethodNotAllowed. The client doesn't see any of the exception details.
If the codec is modified to catch a JsonReaderException and return Missing.Value, similar to the Implementing a codec wiki, then the client receives a HTTP 500 - Internal Server Error. The body of the response also describes the following exception:
System.InvalidOperationException: The operation is not ready for invocation.
at OpenRasta.OperationModel.MethodBased.MethodBasedOperation.Invoke()
at OpenRasta.OperationModel.Interceptors.OperationWithInterceptors.<Invoke>b__0()
at OpenRasta.OperationModel.Interceptors.OperationWithInterceptors.Invoke()
at OpenRasta.OperationModel.OperationExecutor.Execute(IEnumerable`1 operations)
at OpenRasta.Pipeline.Contributors.OperationInvokerContributor.ExecuteOperations(ICommunicationContext context)
at OpenRasta.Pipeline.PipelineRunner.ExecuteContributor(ICommunicationContext context, ContributorCall call)
How should I modify my application so that:
The client receives a HTTP 400 Bad Request.
The client receives a string containing the details of the exception encountered in the codec.
Here is a minor variation of the answer above - this time with codec selection based on the operation result data.
Within IConfigurationSource:
using (OpenRastaConfiguration.Manual)
{
ResourceSpace.Uses.PipelineContributor<ErrorCheckingContributor>();
ResourceSpace.Has.ResourcesOfType<ApplicationError>()
.WithoutUri
.TranscodedBy<ApplicationErrorCodec>();
// Or use a generic JSON serializer like this:
// .AsJsonDataContract();
// Other configuration here
}
Now ErrorCheckingContributor looks like this:
public class ErrorCheckingContributor : IPipelineContributor
{
public void Initialize(IPipeline pipelineRunner)
{
pipelineRunner
.Notify(CheckRequestDecoding)
.After<KnownStages.IOperationResultInvocation>()
.And.Before<KnownStages.ICodecResponseSelection>();
}
private static PipelineContinuation CheckRequestDecoding(ICommunicationContext context)
{
if (context.ServerErrors.Count == 0)
{
return PipelineContinuation.Continue;
}
Error err = context.ServerErrors[0];
// Get a suitable message (err.Message contains stack traces, so try to avoid that)
string msg = err.Title;
if (msg == null && err.Exception != null)
msg = err.Exception.Message;
if (msg == null)
msg = err.Message;
// Create instance of an error information resource which is specific for the application
// - This one is rather simple and only contains a copy of the message
ApplicationError error = new ApplicationError(msg);
// Set operation result to be "400 Bad Request" and remove errors
context.OperationResult = new OperationResult.BadRequest { ResponseResource = error };
context.ServerErrors.Clear();
// Render immediately without starting any handlers
return PipelineContinuation.RenderNow;
}
}
The class ApplicationError is:
public class ApplicationError
{
public string Message { get; set; }
public ApplicationError(string message)
{
Message = message;
}
}
At last we need a codec ApplicationErrorCodec for ApplicationError. This is not different from any other IMediaTypeWriter codec but depends a lot on your expected response media type. See https://github.com/openrasta/openrasta/wiki/Implementing-a-Codec for one example.
Having found this thread on Google Groups which contains all the answers, my current implementation looks something like this.
Within my implementation of IConfigurationSource:
using (OpenRastaConfiguration.Manual)
{
ResourceSpace.Uses.PipelineContributor<ErrorCheckingContributor>();
// Other configuration here
}
Then ErrorCheckingContributor looks something like this:
public class ErrorCheckingContributor : IPipelineContributor
{
public void Initialize(IPipeline pipelineRunner)
{
pipelineRunner
.Notify(CheckRequestDecoding)
.After<KnownStages.IOperationResultInvocation>()
.And.Before<KnownStages.ICodecResponseSelection>();
}
private static PipelineContinuation CheckRequestDecoding(ICommunicationContext context)
{
if (context.ServerErrors.Count == 0)
{
return PipelineContinuation.Continue;
}
var first = context.ServerErrors[0];
if (first.Exception is Newtonsoft.Json.JsonReaderException)
{
context.Response.Entity.ContentType = MediaType.TextPlain;
context.Response.Entity.ContentLength = first.Exception.Message.Length;
using (var sw = new StreamWriter(context.Response.Entity.Stream))
{
sw.Write(first.Exception.Message);
}
}
return PipelineContinuation.Continue;
}
}
There's some things to be aware of with the above:
If a handler were to throw a JsonReaderException, it would also be processed here.
It doesn't check what media types the client accepts. This is different from exceptions thrown by Handlers that do go through codec selection.
Tried setting context.OperationResult to context.ServerErrors - but it doesn't go through the codec.

How to get and set http headers in an Action, the testable way

I have an action that returns either a FileContentResult or a NotModifiedResult, which is a custom result type that returns HTTP 304 to indicate that the requested resource has not been modified, like this:
[ReplaceMissingPicture(Picture = "~/Content/Images/nothumbnail.png", MimeType = "image/png")]
public ActionResult Thumbnail(int id)
{
var item = Service.GetItem(id);
var requestTag = Request.Headers["If-None-Match"] ?? string.Empty;
var tag = Convert.ToBase64String(item.Version.ToArray());
if (tag == requestTag)
{
return new NotModifiedResult();
}
if (item.Thumbnail != null)
{
var thumbnail = item.Thumbnail.ToArray();
var mime = item.PictureMime;
Response.AppendHeader("ETag", tag);
return File(thumbnail, mime);
}
else
{
return null;
}
}
This action needs to access the Response object, which is of course not present during testing, so that makes this action untestable. I could add conditional statements around it, so that it runs during testing, but then I can't test for the headers being set correctly.
What would be a solution to this problem?
FYI, the ReplaceMissingPicture filter returns a specific resource in case null was returned from this action, to keep the MapPath() call out of the controller for the very same reason.
The first step would be to create an interface which simplifies the services you need:-
public interface IHeaders
{
public string GetRequestHeader(string headerName);
public void AppendResponseHeader(string headerName, string headerValue);
}
Now create a default implementation:-
public Headers : IHeaders
{
public string GetRequestHeader(string headerName)
{
return HttpContext.Current.Request[headerName];
}
public void AppendResponseHeader(string headerName, string headerValue)
{
HttpContext.Current.Response.AppendHeader(headerName, headerValue);
}
}
Now add a new field to your Controller:-
private IHeaders myHeadersService;
add new constructor to you controller:-
public MyController(IHeaders headersService)
{
myHeadersService = headersService;
}
modify or add the default constructor:-
public MyController()
{
myHeadersService = new Headers();
}
now in your Action code use myHeadersService instead of the Response and Request objects.
In your tests create your own implementation of the IHeaders interface to emulate/test the Action code and pass that implementation when constructing the Controller.
How about creating a subclass of FileResult--say ETagFileResult--that in its ExecuteResult() method sets the ETag header, and then defaults to the base class implementation? You can test that class with a mocked context (as you presumably are with your NotModifiedResult) to be sure that it's doing the right thing. And remove the entire complication from the testing of the controller.
Failing that, it's possible to set a mocked context on the controller in your test (after instantiating the class, before calling the action method). See this question, for instance. But that seems like more work.
(Also, by the way, it looks like you're quoting the tag value twice there: once when tag is set, and once more when you actually set the header....)

Resources